攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的
字数 992 2025-08-27 12:33:37

PHP Phar包伪装成图像绕过文件类型检测技术分析

背景知识

在2018年US BlackHat大会上,安全研究人员Sam Thomas展示了如何利用PHP的phar://流包装器实现服务器代码执行攻击。关键发现包括:

  1. 当PHAR包被执行时,PHP会对其内容进行反序列化,允许攻击者启动PHP对象包含链
  2. 对归档的任何文件操作都会触发有效载荷执行,即使文件调用失败也会执行反序列化
  3. PHAR包可以被伪装成图像文件,绕过安全检查

PHAR文件结构基础

PHAR(PHP Archive)是PHP的归档格式,包含三个主要部分:

  1. 存根(Stub):可执行PHP代码,通常以__HALT_COMPILER();结束
  2. 清单(Manifest):描述归档内容的元数据
  3. 文件内容:实际存储的文件数据

伪装技术原理

基本伪装方法

攻击者可以通过修改PHAR文件的二进制内容,使其同时满足:

  1. 有效的PHAR归档结构
  2. 有效的图像文件格式
<?php
class TestObject {}

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->addFromString("test.txt", "test");
$phar->setStub("\xFF\xD8\xFF\xFE\x13\xFA\x78\x74 __HALT_COMPILER(); ?>");
$o = new TestObject();
$phar->setMetadata($o);
$phar->stopBuffering();

技术要点

  1. 文件头欺骗:在存根部分插入JPEG文件头(\xFF\xD8\xFF)
  2. 保持PHAR有效性:保留__HALT_COMPILER();结构
  3. 绕过基础检测
    • file命令识别为JPEG
    • mime_content_type()返回image/jpeg
    • 仍可通过phar://协议访问内部文件

高级伪装技术

基础方法无法通过getimagesize()检测,因为不是真正的图像。解决方案是在__HALT_COMPILER()前嵌入完整的图像数据:

$jpeg_header_size = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01..."; // 完整的JPEG头数据

$phar->setStub($jpeg_header_size . " __HALT_COMPILER(); ?>");

这种方法创建的文件:

  1. 是合法的PHAR包(可通过phar://访问)
  2. 是完整的JPEG图像(可通过图像查看器打开)
  3. 能通过getimagesize()检测

防御措施

  1. 严格文件类型验证

    • 不要仅依赖文件头或扩展名
    • 使用多重验证方法组合
  2. 禁用危险功能

    • 考虑禁用phar://流包装器
    • 限制反序列化操作
  3. 服务器配置

    • 设置phar.readonly = On防止PHAR写入
    • 使用最新PHP版本,修复已知漏洞
  4. 深度内容检查

    • 对上传文件进行实际内容解析
    • 检查文件内部结构是否一致

总结

这种攻击技术利用了文件本质上是字节序列的特性,通过精心构造同时满足两种格式要求的文件,绕过安全检查。防御关键在于实施多层、深入的文件验证机制,而非依赖单一检测方法。

PHP Phar包伪装成图像绕过文件类型检测技术分析 背景知识 在2018年US BlackHat大会上,安全研究人员Sam Thomas展示了如何利用PHP的 phar:// 流包装器实现服务器代码执行攻击。关键发现包括: 当PHAR包被执行时,PHP会对其内容进行反序列化,允许攻击者启动PHP对象包含链 对归档的任何文件操作都会触发有效载荷执行,即使文件调用失败也会执行反序列化 PHAR包可以被伪装成图像文件,绕过安全检查 PHAR文件结构基础 PHAR(PHP Archive)是PHP的归档格式,包含三个主要部分: 存根(Stub) :可执行PHP代码,通常以 __HALT_COMPILER(); 结束 清单(Manifest) :描述归档内容的元数据 文件内容 :实际存储的文件数据 伪装技术原理 基本伪装方法 攻击者可以通过修改PHAR文件的二进制内容,使其同时满足: 有效的PHAR归档结构 有效的图像文件格式 技术要点 文件头欺骗 :在存根部分插入JPEG文件头( \xFF\xD8\xFF ) 保持PHAR有效性 :保留 __HALT_COMPILER(); 结构 绕过基础检测 : file 命令识别为JPEG mime_content_type() 返回 image/jpeg 仍可通过 phar:// 协议访问内部文件 高级伪装技术 基础方法无法通过 getimagesize() 检测,因为不是真正的图像。解决方案是在 __HALT_COMPILER() 前嵌入完整的图像数据: 这种方法创建的文件: 是合法的PHAR包(可通过 phar:// 访问) 是完整的JPEG图像(可通过图像查看器打开) 能通过 getimagesize() 检测 防御措施 严格文件类型验证 : 不要仅依赖文件头或扩展名 使用多重验证方法组合 禁用危险功能 : 考虑禁用 phar:// 流包装器 限制反序列化操作 服务器配置 : 设置 phar.readonly = On 防止PHAR写入 使用最新PHP版本,修复已知漏洞 深度内容检查 : 对上传文件进行实际内容解析 检查文件内部结构是否一致 总结 这种攻击技术利用了文件本质上是字节序列的特性,通过精心构造同时满足两种格式要求的文件,绕过安全检查。防御关键在于实施多层、深入的文件验证机制,而非依赖单一检测方法。