ThinkPHP6.0.5目录穿越漏洞排查核心是识别用户可控路径输入是否未经realpath()规范化及根目录白名单校验即参与file_get_contents()等文件操作,重点审计lang参数、模板fetch()、附件接口,并检查Nginx目录禁访与APP_DEBUG关闭情况。

ThinkPHP6.0.5虽比3.x和早期5.x更安全,但仍可能因开发习惯或配置疏漏引入目录穿越漏洞。排查重点不是“有没有漏洞”,而是“有没有不安全的路径拼接逻辑”。核心思路是:找所有用户可控的路径输入点 → 看是否未经规范化就参与文件操作 → 检查是否缺乏根目录约束。
盯紧三类高危文件操作入口
目录穿越必须经过“用户输入→路径拼接→文件读写”链条。在TP6.0.5中,优先审计以下位置:
-
多语言加载逻辑:如
lang参数被直接拼入语言包路径(lang/zh-cn.php),常见于think\lang\Lang类或自定义语言切换接口 -
模板渲染与动态加载:比如
view()->fetch($_GET['tpl'])、Loader::parseName()配合用户传参、think\Template中loadTemplate()方法的路径处理 -
附件/资源读取接口:后台预览、下载、日志查看等API,参数如
file、path、filename,尤其注意file_get_contents()、fopen()、readfile()前的路径构造
检查路径处理是否真正规范化
仅用str_replace('..', '', $input)或正则过滤../是无效的。TP6.0.5自带think\facade\Env::get()和think\helper\Str::cleanPath(),但开发者未必调用。需人工确认:
- 是否对用户输入调用了
realpath()或框架的normalizePath()(位于think\helper\Str)? - 规范化后是否做了“根目录白名单校验”?例如:
if (strpos(realpath($userPath), ROOT_PATH) !== 0) { throw new Exception('非法路径'); } - 是否允许URL编码绕过?如
%2e%2e%2f、%c0%ae%c0%ae%2f未在解码后统一处理
验证敏感目录是否被有效隔离
即使代码层没出问题,服务器配置不当也会让目录穿越“绕过防御”。检查:
立即学习“PHP免费学习笔记(深入)”;
-
public/以外的目录(如app/、config/、runtime/)是否在Web服务器中禁止直接访问?Nginx应有类似location ~ ^/(config|app|runtime)/ { deny all; }规则 - 调试模式是否关闭?
APP_DEBUG = false必须生效,否则错误页面可能泄露真实物理路径,辅助攻击者构造精准Payload - 是否禁用危险函数的动态调用?如
include()、require()、file_get_contents()直接使用$_GET参数——这类写法在TP6中虽不推荐,但老项目迁移时仍可能出现
用典型Payload快速验证可疑点
对疑似接口,手工尝试几个轻量级Payload(生产环境慎用,建议先在测试环境验证):
-
?lang=../../config/database.php—— 测试多语言参数是否可读取配置 -
?file=..%2f..%2f..%2fetc%2fpasswd—— URL编码绕过检测 -
?tpl=../../public/index.php—— 测试模板加载是否可包含非模板文件 -
?path=.//.//config/app.php—— 多斜杠混淆,部分逻辑会误判为合法
观察响应:返回404/500是好现象;返回明文内容(尤其是PHP源码、数据库密码)即确认存在漏洞。注意区分是“读取成功”还是“解析执行”——后者可能触发RCE,风险更高。



















