thinkphp 6.0.0–6.0.1任意文件写入漏洞源于sessionid未过滤直接拼接文件路径,攻击者通过构造恶意phpsessid(如../../../public/shell.php)可写入webshell;该漏洞在6.0.14+版本中通过basename()和正则校验修复。

ThinkPHP文件写入漏洞主要集中在会话(Session)文件驱动的路径构造环节,核心问题是用户可控的PHPSESSID未经过滤就直接拼接进文件路径,导致攻击者可写入任意位置、任意内容,包括Webshell。
漏洞触发的关键路径
该漏洞在ThinkPHP 6.0.0–6.0.1中被确认,其利用链清晰且依赖默认配置:
- 应用启用
SessionInit中间件(如middleware.php中注册) - 使用文件驱动(
driver => 'file')存储会话,默认开启 - 攻击者完全控制
Cookie: PHPSESSID值 - 框架调用
File::write()时,将sess_前缀与未经净化的PHPSESSID拼接为文件名 - 若
PHPSESSID设为../../../public/shell.php,最终写入路径即为runtime/session/sess_../../../public/shell.php,实际落地为public/shell.php
为什么能绕过常规防护
该漏洞不是因开发者代码错误引发,而是框架底层逻辑缺陷,因此常规输入过滤无效:
- 不涉及
$_GET/$_POST参数,WAF对Cookie字段常疏于规则覆盖 - 会话ID本身是合法HTTP头,多数安全组件默认放行
- 路径拼接发生在框架内部
getFileName()方法中,无开发者介入点 - 即使关闭调试模式、禁用错误回显,漏洞仍可稳定利用
有效防御手段
需从框架层、配置层、运行层三方面同步加固:
-
立即升级:TP6.x必须升至
6.0.14+或更高版本,官方已在File.php中加入basename()和白名单校验 -
禁用文件驱动:改用
redis或database等非文件型会话驱动,彻底规避路径风险 -
限制会话存储目录权限:确保
runtime/session/不可执行、不可被Web访问,例如Nginx中添加location ~ ^/runtime/ { deny all; } -
强制会话ID格式校验:在
config/session.php中设置'id_pattern' => '/^[a-zA-Z0-9]{26,40}$/',拒绝含../、点号、斜杠等危险字符的ID
验证是否已修复
完成加固后,可通过以下方式快速验证:
- 手动发送请求:
curl -H "Cookie: PHPSESSID=../../../test.txt" http://your-site.com,检查public/test.txt是否生成 - 查看
vendor/topthink/framework/src/think/session/driver/File.php第87行附近,是否存在basename($name)或preg_match校验逻辑 - 运行
php think version确认输出为v6.0.14或更新版本
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











