影响版本
根据thinkphp发布的5.0.24的补丁可以看到问题出在核心类Request的method方法。补丁增加了对传入的$method的限制。1
2
3漏洞影响的产品版本包括:
ThinkPHP 5.0.x ~ 5.0.23版
漏洞分析
本文以5.0.5 full版本进行分析
这里Config::get(‘var_method’)获取到的内容为_method,被称为表单请求类型伪装变量,具体功能不细究,可查阅官方文档了解。
那么在未打补丁之前对POST进来的_method变量未作任何过滤,而且下面直接进行了调用,而且函数参数可控。那么便可实现对本类所有方法的调用。1
$this->($this->method)($_POST);
根据payload,其传入的是_method = __construct
查看__construct方法
该方法对传入的参数数组进行遍历,并通过property_exists检查对象或类是否具有该属性。如果是本类的属性,则通过$this->$name = $item对属性进行重新赋值。
那么这里因为传入的参数可控,可实现对Requset类下任意属性的覆盖。
单单一个变量覆盖是不能得到满足的,继续将这个漏洞扩大化。
可以查看可以覆盖的属性,并看看这些属性的覆盖会不会引起更致命的操作。
这是其中一部分属性
而通过已知的payload了解到这里的全局过滤规则filter被覆盖。查看哪里用到了filter,搜索后发现该类中很多方法都用到了这个变量
其中input方法中调用了filterValue方法
而filterValue方法中,将其带入了call_user_func函数,这里还有一个参数value,向上跟踪value来自于input方法的data,继续往上查看到哪里调用了input。发现了param方法,data来自于其$this->param1
2// 当前请求参数和URL地址中的参数合并
$this->param = array_merge($this->get(false), $vars, $this->route(false));
其中$vars数组来自上面,也即我们通过http传入的参数
到此为止,call_user_func的两个变量我们均可以控制,便可以实现任意代码执行。
其中这里要想任意代码执行有两个条件:
- 1.调用method()实现filter变量覆盖
- 2.调用param()方法,实现任意代码执行链
首先是第一条在检测url路由check()中触发
整个调用链运行时自动加载
而第二个条件。全局搜索漏洞触发点,看看哪里调用了param方法。
其中当开启debug时调用param。
当debug关闭时,继续搜索其他触发点。
这里当dispatch[‘type’]==’method’时,触发param方法
向上跟踪dispatch
最终还是与$request->method()有关
而method方法返回的method是可以覆盖掉的,可以post传递method=get控制dispatch的最终值,从而进入method分支,调用param
0x02 payload
最终payload1
2
3post:
_method=__construct&method=get&filter=system&boo=whoami