漏洞介绍
ThinkPHP5.0.23版本的漏洞:获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。
漏洞范围
Thinkphp 5.1.0 - 5.1.31
Thinkphp 5.0.5 - 5.0.23
漏洞靶场
使用vulhub的靶场
1 | docker-compose up -d |
漏洞原理

/thinkphp/library/think/App.php#L120
我们可以看到通过self::routerCheck函数进行路由检测

/thinkphp/library/think/App.php#L622-L663
我们可以看到又进入$request->path()函数

/thinkphp/library/think/Request.php#L433-L450
进入pathinfo()函数,继续追踪到384行

/thinkphp/library/think/Request.php#L401-L426
Config::get(‘var_pathinfo’)是配置文件中的设置的参数,默认值为s,从GET中获取键值,然后赋值给routeCheck中的$path

我们再回到App.php

/thinkphp/library/think/App.php#L622-L663
这里会进行路由检测,检查$check后会进入else分支导入路由配置,接着检测路由url调度结果为$result,如果调度失败且开启了强制路由$must,则报出路由无效,接着进入Route::parseUrl函数,根据$path(自定义url)解析操作
开始跟踪parseUrl函数

/thinkphp/library/think/Route.php#L1217-L1276
进入parseUrlPath函数

/thinkphp/library/think/Route.php#L1284-L1302
这里我们可以看到对模块/控制器/操作的url地址分割成数组来返回,行数:1217


/thinkphp/library/think/Route.php#L1217-L1276
我们可以看到,返回的结果赋值为$path,提取路由信息又封装到$route,最后返回

thinkphp/library/think/App.php#L120
进入self::exec函数

/thinkphp/library/think/App.php#L445-L483
我们可以看到模块/控制器/操作 的函数为self::module
开始跟踪module函数


我们可以看到,根据$config[‘app_multi_module’]进入多模块部署,$bind为NULL,又进入elseif分支,判断模块是否在禁止的列表里面$config[‘deny_module_list’],而且mmodule存在,$available = true,就不会抛出异常
module函数最后的返回值,发现$controller没有进行过滤,那么此时应该为think\app,也就是return self::invokeMethod($call, $vars);

/thinkphp/library/think/App.php#L494-L612
进入self::invokeMethod函数

/thinkphp/library/think/App.php#L329-L344
此时穿进去的$call也就是$method,是一个数组,第一个元素是一个think\App对象,第二个元素则是调用方法名称的字符串invokefunction,然后通过反射ReflectionMethod获取这个对象下对应的方法
再通过函数$args = self::bindParams($reflect, $vars);获取传入的参数,也就是payload
最后再调用反射$reflect->invokeArgs($args);,将Payload数组传入反射对象函数invokeFunction,完成代码执行。

/thinkphp/library/think/App.php#L311-L320
漏洞复现
访问http://127.0.0.1:8080/进入靶场页面

发送数据包:
1 | POST /index.php?s=captcha HTTP/1.1 |
成功执行id命令:

参考
https://blog.csdn.net/weixin_44971640/article/details/128495915