tp6任意文件创建漏洞本质是session id校验缺失导致的路径可控问题,存在于6.0.0–6.0.1版本,因setid()未白名单校验id内容,攻击者可构造../shell.php等恶意id,配合file驱动写入任意文件,需升级至6.0.2+并加固配置。

TP6任意文件创建漏洞本质是Session ID校验缺失导致的路径可控问题,影响范围明确、利用门槛低,必须从框架版本、运行配置和业务代码三方面同步处理。
漏洞成因与影响范围
该漏洞存在于 ThinkPHP 6.0.0 至 6.0.1 版本中,核心问题是 session_id 未做字符白名单校验。Store.php 中 setId() 方法仅判断长度是否为32位,不校验内容是否仅含字母数字,攻击者可传入如 ../test.php 或 shell.php%00 等恶意 Session ID。当系统启用 File 驱动存储 session 时,writeFile() 函数直接将该 ID 拼接进文件路径,调用 file_put_contents() 写入任意位置,造成文件创建、覆盖甚至写入 Webshell。
- 触发前提:session 功能开启(中间件中启用
SessionInit)且使用默认 File 驱动 - 典型危害:创建 .php 文件 getshell、覆盖 .env 或 config.php 泄露密钥、删除关键日志掩盖痕迹
- 已知可利用场景:Apache + PHP 7.2–7.4 环境下稳定复现,Nginx+PHP-FPM 同样受影响
修复方式:必须升级或补丁拦截
官方已于 6.0.2 版本修复此问题,但实际生产环境不能只依赖“已修复”,需确认当前是否真正脱离风险。
- 执行
php think version,输出必须为 6.0.2 或更高;若显示 6.0.1+git 或 6.0.1.*,仍处于漏洞版本 - 若无法立即升级,可在
app/middleware.php中禁用 session 中间件(仅适用于无登录态需求的接口服务) - 临时缓解:在入口
public/index.php顶部加入强制过滤逻辑:if (isset($_COOKIE['PHPSESSID']) && !ctype_alnum($_COOKIE['PHPSESSID'])) { http_response_code(400); exit; }
配套加固不可省略
仅修复 session ID 校验不够,攻击者可能通过其他路径再次达成任意文件操作。
- 检查
config/session.php中'use_trans_sid' => false,禁用 URL 传递 session_id - 确认 session 存储目录(如
runtime/session/)不在 Web 可访问路径下,禁止直接浏览器访问 .php 结尾的 session 文件 - 在 Nginx 配置中增加规则,拒绝匹配
.*\.php$的 session 文件访问:location ~ ^/runtime/session/.*\.php$ { return 403; } - 所有用户上传、缓存、导出类功能,必须对文件名做严格过滤(仅保留 a-z0-9._-),并指定固定后缀,禁止拼接原始参数
验证是否修复成功
修复不是改完就结束,必须实操验证:
- 用 Burp 发送请求,Cookie 中设置
PHPSESSID=../../../public/shell.php,访问任意页面,检查public/shell.php是否被创建 - 查看
runtime/session/目录下生成的 session 文件名,确认全为 32 位纯字母数字,不含点、斜杠、下划线等特殊字符 - 尝试访问
/runtime/session/xxx.php(手动构造),应返回 403 或 404,而非 PHP 解析结果











