thinkphp 6.0.0–6.0.1 存在任意文件写入漏洞,因 session 文件驱动未校验 $sessid 合法性,攻击者可构造恶意 phpsessid 将 session 写入任意路径(如 public/shell.php)实现 getshell。

ThinkPHP 6.0.0–6.0.1 存在可被直接利用的任意文件写入漏洞,根本原因在于 session 文件驱动中对 $sessID 参数未做路径合法性校验,导致攻击者可通过构造恶意 PHPSESSID 值,将 session 内容写入任意路径(如 public/xxx.php),进而 getshell。
漏洞触发点:File.php 中的 writeFile() 路径拼接失控
漏洞实际发生在 vendor/topthink/framework/src/think/session/driver/File.php 的 writeFile() 方法中:
该函数调用 file_put_contents($path, $content),其中 $path 来自 getFileName($id) —— 而 $id 直接来自用户可控的 PHPSESSID cookie 或 URL 参数,未经任何过滤就参与了路径拼接。
关键问题在于:getFileName() 仅做前缀拼接('sess_' . $id),不校验 $id 是否含 ../、斜杠、点号等危险字符。
常见错误现象:
- 访问
index?c=<?php phpinfo();?>&PHPSESSID=../../../../public/shell后,public/shell.php被成功创建 - 日志中无报错,但
public/下出现非 session 文件(如1omg12377.php) -
session_start()正常执行,但服务端磁盘上多出可疑 PHP 文件
复现时 session 必须启用且可控
漏洞利用前提是目标已启用 session,并且 PHPSESSID 可被外部指定(默认开启,且未禁用 session.use_trans_sid 或未强制绑定 cookie)。
实操要点:
- 确认
app/middleware.php中已启用\think\middleware\SessionInit::class(取消注释) - 控制器中需有触发 session 写入的逻辑,例如
session('key', $_GET['c'])或Session::set() - 必须确保 session 存储驱动为
file(默认),若配置为 redis 或 database 则不受影响 - PHP 配置中
session.save_path需为可写目录,且 Web 进程有权限在目标路径(如public/)下创建文件
修复核心:强制校验 session_id 字符集
官方补丁(6.0.2+)在 src/think/session/Store.php 的 setId() 方法中加入 ctype_alnum() 校验:
你只需在项目中覆盖或补丁该逻辑,例如在中间件或全局初始化处加一行:
if (!is_string($id) || strlen($id) !== 32 || !ctype_alnum($id)) {
throw new Exception('Invalid session id');
}
注意:不能只依赖前端 JS 或 Nginx 重写过滤,必须在 PHP 层、setId() 或 start() 入口处拦截;session_regenerate_id() 生成的新 ID 是安全的,但旧 ID 若已被污染,仍可能被用于写入。
容易被忽略的点:即使你没显式调用 session(),只要启用了 SessionInit 中间件,且请求携带了非法 PHPSESSID,框架在 session 初始化阶段就可能触发 write() —— 漏洞链比表面看到的更早、更隐蔽。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











