攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的
字数 992 2025-08-27 12:33:37
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归档结构
- 有效的图像文件格式
<?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();
技术要点
- 文件头欺骗:在存根部分插入JPEG文件头(
\xFF\xD8\xFF) - 保持PHAR有效性:保留
__HALT_COMPILER();结构 - 绕过基础检测:
file命令识别为JPEGmime_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(); ?>");
这种方法创建的文件:
- 是合法的PHAR包(可通过
phar://访问) - 是完整的JPEG图像(可通过图像查看器打开)
- 能通过
getimagesize()检测
防御措施
-
严格文件类型验证:
- 不要仅依赖文件头或扩展名
- 使用多重验证方法组合
-
禁用危险功能:
- 考虑禁用
phar://流包装器 - 限制反序列化操作
- 考虑禁用
-
服务器配置:
- 设置
phar.readonly = On防止PHAR写入 - 使用最新PHP版本,修复已知漏洞
- 设置
-
深度内容检查:
- 对上传文件进行实际内容解析
- 检查文件内部结构是否一致
总结
这种攻击技术利用了文件本质上是字节序列的特性,通过精心构造同时满足两种格式要求的文件,绕过安全检查。防御关键在于实施多层、深入的文件验证机制,而非依赖单一检测方法。