thinkphp5.x代码审计核心是追踪用户输入流向,而非仅搜索eval;需紧盯request()->get()/input()等入口,验证其是否经白名单过滤或类型强转,防止被用于assign、db::where、fetch、反射调用及缓存写入等危险操作。

ThinkPHP5.x 的代码审计不是找“有没有 eval”,而是盯死“谁把用户输入喂给了谁”。漏洞往往藏在框架默认行为里——比如自动合并请求参数、自动提取模板变量、自动解析路由类名,这些“方便”背后全是可控点。
盯紧 request()->get() / input() 的流向
这是最常见也是最危险的输入入口。一旦没做白名单过滤或类型强转,后续任何调用都可能被带偏。
-
request()->get()返回的是未经过滤的原始$_GET数组,键名、键值全由攻击者控制 - 若直接传给
$this->assign()(如Index.php中常见写法),就会进extract($vars, EXTR_OVERWRITE),覆盖任意变量,包括$cacheFile、$template - 若传给
Db::where()且未限定字段名,可能触发数组 SQL 注入(如uid[0]=exp&uid[1]=1=updatexml(1,concat(0x7e,(select%20user())),0)) - 别信注释里写的“已过滤”,要顺藤摸瓜看到底有没有真正校验——比如只检查了
is_numeric(),但没拦住1' OR 1=1--这种字符串型绕过
警惕 fetch() 和 display() 的模板路径可控
ThinkPHP 默认允许通过参数指定模板文件路径,而这个路径若拼接了用户输入,就等于开了任意文件包含门。
-
$this->fetch('index')看似安全,但如果写成$this->fetch(input('template')),攻击者就能传template=../../config/database - 5.1.x 中
hinkiewdriverPhp::display()支持content参数直接执行 PHP 代码,payload 形如?s=index/ hinkiewdriverPhp/display&content=<?php phpinfo();?> - 注意
fetch()底层会调用read(),而read()里有extract()+include $cacheFile组合,只要能覆盖$cacheFile,就能包含任意后缀为.php的文件
识别危险的反射调用链:invokefunction、Container::invokeClass
ThinkPHP 把控制器/方法名当作路由参数解析,再通过反射动态调用,这就给了攻击者构造任意调用链的机会。
-
?s=index/ hinkpp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id是典型利用方式,关键在于s参数是否可控、是否跳过了命名空间白名单校验 - 5.0.x 中
hinkRequest::input()支持filter参数,可传入assert、system等函数名,配合data执行任意代码 - 审计时重点看
App.php的run()方法如何解析s,再查dispatch()是否对类名做了strpos($class, '\') === false类似的宽松判断 - 别忽略大小写绕过:有些版本只拦截
system,但不拦System或SYsTeM
缓存写入点:序列化数据落地为 .php 文件
ThinkPHP 的 Cache::set() 默认使用 File 驱动,将序列化数据直接写入可访问目录下的 .php 文件——这等于帮攻击者把 webshell 写进了磁盘。
- 缓存键名经
md5()后取前两位作子目录,后 30 位作文件名,路径可预测(如runtime/cache/34/34a7d8c9e2b1f0a6c5d4e3b2a1f0c9d8.php) - 写入内容是
//<?php exit();?> ' . serialize($data),但换行符%0d%0a可绕过注释头,让后续 PHP 代码被执行 - 确认
cache目录是否在 Web 根目录下可直接访问(如public/runtime/cache/),否则即使写入也无法触发 - 注意 PHP 版本影响:PHP 7.4+ 对反序列化更严格,部分 gadget 链可能失效,复现时建议用 PHP 7.2–7.3
真正卡住人的从来不是“找不到漏洞”,而是“不确定某个参数到底能不能走到那个函数”。每一步都要用 var_dump() 或 xdebug 断点验证变量值和调用栈,尤其当看到 array_merge、extract、call_user_func 这类函数时,必须立刻停下来问一句:它的参数从哪来?中间有没有过滤?有没有类型转换?
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











