从ThinkPHP漏洞里学到的

前几天thinkphp被爆出执行任意代码漏洞。正好我平时常用的也是thinkphp,乘此时机研究一下。

引起漏洞的代码(Dispatcher.class.php):

1
$res = preg_replace('@(w+)'.$depr.'([^'.$depr.'/]+)@e', '$var['1']="2";', implode($depr,$paths));

这个是tp用来把url后的参数赋值的操作。类似于domain.com/index.php/Index/index/a/111/b/222这样的URL,它的使命就是使$var[‘a’] = 111;$var[‘b’] = 222;然后合并到$_GET和$_REQUEST中。

为了使preg_replace的第二个参数’$var[‘1’]=”2”;’(这是一个字符串)作为PHP语句执行以便完成赋值操作,tp在这里用了preg_replace的e参数(e参数的作用)。

问题就出在这了。如我们所看到的,2的外面包围的是双引号——有些php常识的就知道双引号和单引号的区别——双引号里的变量可以直接执行。

但是双引号里的函数却是不被执行的。不是没有办法的——在PHP里可以通过{${}}构造一个特殊的变量,把函数放在中间就可以执行了:

domain.com/index.php/Index/index/a/${@phpinfo()}

加一个@来忽略错误。这样,就直接执行并显示了:

update:

刚开始以为用@是为了忽略错误,后来搜索发现仅仅是${phpinfo()}是没法执行的,会报unexpected ‘(‘错误。
需要在函数前加空格、@、回车、tab、注释才行(php程序里,url上只能用空格和@)。

参考:

1.《preg_replace危险的/e修饰符,慎用!!!

2.《浅谈PHP可变变量安全续

坚持原创技术分享,您的支持将鼓励我继续创作!