thinkphp缓存漏洞是多版本反复出现的三类模式:换行注入、模板路径拼接绕过、tagcache反序列化pop链。核心均因信任用户输入并写入可执行位置,需在set()等入口过滤换行、禁用动态路径、限制反序列化类型。

ThinkPHP缓存漏洞不是单一漏洞,而是多个版本中反复出现的几类模式:缓存文件写入时未过滤换行、模板变量覆盖导致文件包含、反序列化后触发POP链写文件。直接看代码最有效。
File缓存驱动中 set() 方法的换行注入(TP3.2.3 / TP5.0.x)
漏洞核心在 think\cache\driver\File::set():它把用户可控数据序列化后拼进 "<?php \n//" . $data . "\n?>" 再写入 .php 文件。攻击者用 %0a(LF)绕过 // 注释封装,让后续内容变成可执行PHP代码。
- 典型触发点:
S('key', $_POST['user_input'])或任何将未过滤输入传给S()第二个参数的地方 - 关键路径:
File.php的set()→filename()→ 生成md5($name).php路径(默认在./Runtime/Temp/) - 修复动作必须在
set()内部做:$data = str_replace(["\r", "\n"], '', $data);,不能只靠上层校验 - 注意:TP5.0.x 同样存在该问题,但缓存文件名逻辑改为
md5($name . $tag),路径由cache_path配置决定,仍可预测
view() 模板路径拼接绕过(TP6.0.x / TP6.1.0)
当业务代码显式拼接模板路径且未禁用目录跳转时,view('../runtime/log/' . input('file')) 可被利用。攻击者上传带PHP代码的图片到 public/uploads/,再用 ?file=../../uploads/shell.jpg 触发解析执行。
- 风险前提:开发者手动调用
view()并拼接用户输入;且未设置view()->engine->layout(false)或类似限制 - TP6.1.0 仅默认关闭遍历,不等于修复——只要代码里显式启用路径拼接,漏洞就复活
- 检查点:全局搜索
view(、fetch(、display(,看参数是否含input()、param()、get()等 - 安全替代:用白名单映射,如
$map = ['a' => 'index', 'b' => 'about']; view($map[$_GET['t']] ?? 'index');
TagCache 反序列化配合 session 伪造(TP6.0.12+)
TP6.0.12 引入的 think\cache\driver\TagCache 在 get() 中调用 unserialize(),但未做类型白名单限制。若攻击者能篡改 session 数据(例如通过 XSS 窃取并修改 cookie),再触发 TagCache::get(),就可能激活已知 POP 链(如 think\cache\driver\File::setPath())写 Webshell。
- 关键条件:session 存储介质为 file 或 redis(非 memcached),且反序列化入口暴露(常见于缓存命中失败后的 fallback 逻辑)
- 审计重点:
TagCache.php的get()方法是否直接对$this->handler->get($key)结果调用unserialize() - 危险链起点:
__wakeup()→setPath()→file_put_contents(),路径由攻击者控制的属性注入 - 临时缓解:禁用
TagCache驱动;或在get()前加is_string($data) && preg_match('/^[O:]/', $data)粗筛
缓存漏洞的共性是“信任输入 + 写入可执行位置”,但每个版本的落点不同:TP3.2.3 是换行注入,TP5 是模板变量覆盖,TP6 则转向反序列化与 session 交互。真正难防的不是某一行代码,而是开发时默认认为“缓存只是暂存数据”的思维惯性——一旦这个假设松动,所有缓存写入点都得重审。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











