源码分析
该处漏洞主要是preg_replace 函数/e模式下存在的代码执行问题,虽然该程序版本较老,但该问题在其他程序中仍时有存在
漏洞触发点在 lib/tool/form.php文件中,关键代码如下:
1 | function getform($name,$form,$field,$data) { |
关键点在于这句
1 | if (isset($form[$name]['default'])) |
当if条件成立时,就会引发代码执行问题
下面寻找触发getform函数的代码
可以看到该函数存在六处调用,尝试跟进第一处
代码位于 cache/template/default/manage/#guestadd.php
1 | <?php echo form::getform('catid',$form,$field,$data);?> |
该段直接调用了静态方法getform,但目前并不知道 catid是什么,尝试全局搜索
在/lib/table/archive.php中找到了catid 相关的函数
1 | function get_form() { |
注意到这一句
1 | 'default'=>get('catid'), |
跟进get函数
1 | function get($var) { |
继续跟进
1 | static function get($var) { |
最后跟进到front类中__construct()函数
1 | //关键语句 |
这就说明catid和defult的值都是我们可以控制的,这样我们就可以通过控制$form[$name(catid)] [‘default’]来达到执行任意代码的目的
此时我们需要寻找一个触发get_form()函数的地方,并且再触发该函数后需要引用guestadd.php页面以此衔接我们的利用操作,全局搜索后定位在 /lib/default/manage_act.php ,该文件在第29行对get_form()函数进行了调用
1 | $this->view->form=$this->_table->get_form(); |
同时在/lib/tool/front_class.php 文件的front类中存在这样的代码
1 | if (@$_GET['g'] &&is_numeric(@$_GET['g'])) { |
该文件是网站入口文件index.php所引用的,所以我们访问如下url即可触发
1 | http://localhost/?g=1 |
接着会被重定向为这样:
1 | http://localhost/index.php?case=manage&act=guestadd&manage=archive&guest=1 |
这时只要post过去符合正则匹配的代码就可以了
1 | '/\{\?([^}]+)\}/e' |
梳理一下利用过程:
1 | index.php-> |
后记
当我们传入{?(phpinfo())}时,函数会变成这样
1 | preg_replace('/\{\?([^}]+)\}/e',"eval('return $1;')","{?(phpinfo())}"); |
匹配成功后会执行eval(‘return $1;’)
而(phpinfo())在正常情况下同样会执行
执行成功会返回true这样前面的eval(‘return $1;’)就相当于eval(‘return phpinfo();’),所以出现了代码执行