大概看了下,这个洞跟5.0的原理大致相同,都是利用Reuqest类的Method方法覆盖了$this->filter
属性,然后进入filterValue
调用call_user_func($filter, $value)
,$value
为当前请求参数和URL地址中的参数合并,从而导致RCE。
漏洞验证
测试版本:Thinkphp_5.1.1
补丁:https://github.com/top-think/framework/commit/2454cebcdb6c12b352ac0acd4a4e6b25b31982e6
需要在入口文件处关闭报错。
payload
c=exec&f=calc.exe&&_method=filter&
流程分析
在获取应用调度信息时会调用Request类的method方法获取当前的请求类型
且$this->config->get('var_method')
外部可控,即$this->method
我们可控,从而我们可以通过$this->{$this->method}($_POST)
调用任意方法。
跟进filter
方法,发现我们post的数据可以覆盖$this->filter
属性。
回到App类,由于我们开启了$this->debug
从而可以进入Request
类的param
方法。
跟进param
方法,$this->param
为当前请求参数和URL地址中的参数合并。然后进入input
方法。
跟进input
方法,因为$data
为上面提到的$this->param
即数组,从而进入if条件执行array_walk_recursive($data, [$this, 'filterValue'], $filter);
查阅array_walk_recursive
函数可知,该函数会调用$this->filterValue
函数,把$data
数组的每个值作为其第一个参数,键名作为第二个参数,并且把$this->filter
作为第三个参数。
继续跟进filterValue
方法,发现调用了call_user_func($filter, $value)
,$filter
为刚开始我们覆盖的$this->filter
属性的遍历键值,等于$_POST
数组。$value
为当前请求参数和URL地址中的参数合并数组$this->param
的键值。
当遍历到$this->param
的第二个键值calc.exe
和$filters
的第一个键值exec
时,成功执行命令,弹出了计算器。
补丁分析
与5.0一样,对表单请求类型伪装变量添加了白名单。