代码执行
常见函数
-
eval()
:将字符串当成代码进行执行,传入一个完整的语句 -
assert()
:判断参数是否为字符串,是则当成代码执行php
版本大于7.0.29
,不可动态执行assert()
,即不能直接传参,但是静态执行依然可以eval()
对代码的正确性要求很高,不正确的代码则无法执行,但是assert()
对代码的正确性要求不高 -
call_user_func()
:回调函数,第一个参数时回调的函数,其余参数是回调函数的参数(记得做过这么一道题,但是现在有点忘了),回调的函数可以是内置的也可以是用户自定义的函数,当传入的参数是数组时,会把第一个元素当成类,把第二个元素当成类中的方法。调用的函数就是类中的方法。 -
call_user_func_array()
:回调函数,参数为数组。回调函数接收的参数为数组的元素 -
create_function(String $arg1, String $arg2)
:创建匿名函数,返回值为一个匿名函数。第一个参数表示匿名函数的参数,参数二表示函数内要执行的参数<?php $a = create_function($code, "echo $code"); $b = "test"; $a($b); // 结果输出test ?>
-
preg_replace()
:当第一个参数的模式为//e
时,用第二个参数去替换第三个参数时,会把替换后的字符串当成代码执行 -
array_map()
:为数组的每个元素的调用回调函数<?php $array[0] = "phpinfo();" array_map("assert", $array); ?>
-
array_filter()
:将数组的每个元素传入到回调函数里,如果回调函数的返回值为true
的话,则数组的当前值会被包含在返回结果数组中,数组的键名保持不变。<?php $array[0] = "system('whoami')"; array_filter($array, 'assert') ?>
-
usort()
:使用用户自定义的排序函数进行排序,第一个参数为待排序的数组,第二个参数为自定义的排序数组名。<?php function cmp($a,$b){ if($a == $b){ return 0; } return ($a>$b)?1:-1; } $array = array(3,5,2,1,4); usort($array, 'assert'); foreach($array as $key=>$value){ echo "$key:$value\n"; } ?> //output: 0:1 1:2 2:3 3:4 4:5
可以看到,使用
usort()
是会使数组的键值发生变化的 -
uasort()
:使用用户自定义的函数对数组进行排序,并且保持数组的键值关联在上面的那个例子当中,如果将
usort()
改成了uasort()
,那么输出结果将变成:3:1 2:2 0:3 4:4 1:5
可以看到
uasort()
保持了数组的键值关联 -
${}
:花括号中间的代码将会被执行<?php ${phpinfo();}; ?>
绕过一些限制
-
抓住
php
的特性!a=false !!a=true
加上
@
可以忽略警告信息bool
值做数学运算的话,@!!a
会被当作1
,@!a
被当作0
,可以通过这种方式可以构造数字。可以通过字符与字符形的数字异进行异或、与运算构造出其他的数字,例如:
@a^'1'='P' @a&'1'='!'
对于字符串,也可以用相同的方法进行利用,如:
@scandir^'1234500'='BQRZQYB'
那么我们可以构造出
1234500
,然后通过可用的函数将数字转化成字符串,得到之后就可以构造出scandir
了当然,我们还可以对可用的字符写个脚本,跑出来所有的组和可以得到的结果,然后针对性地选择组合就行。
-
利用取反
举个例子:
现在假设
phpinfo
被过滤了,可以用下面的流程进行构造:urlencode(~"phpinfo"); // %8F%97%8F%96%91%99%90,urlencode是为了防止不可见字符产生报错 (~%8F%97%8F%96%91%99%90)(); //利用形式需要看php版本,这种形式适用于php 7.0+
上面的只是举个例子,除此之外还可以用16进制构造、取反汉字等手段,这些手段也常被用于写一些webshell