参考php反序列化拓展攻击详解--phar-先知社区]
什么是phar?
phar类似Java中的jar,将整个php应用程序打包到一个文件里面。
用户可以直接通过php test.phar执行一个php项目
phar本质上是一个包含多个文件的压缩包,里面存储着有特殊的数据。
开发者可以把phar一整个项目打包成一个phar文件,用户下载这一个文件就可以执行整个项目

phar文件的结构
大体来说 Phar 结构由4部分组成

1.stub:phar 文件标识
<?php
Phar::mapPhar();
include 'phar://phar.phar/index.php';
__HALT_COMPILER();
?>
- 这是一个 合法的 PHP 脚本片段,必须以
<?php开头,并以__HALT_COMPILER(); ?>结尾。 - 当你直接运行
php app.phar时,PHP 解释器会执行这个 stub。 - 它通常用于设置自动加载、引导应用入口等。
简单来说可以把他理解为一个标志
格式为xxx<?php xxx; __HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。
2. Manifest(清单 / 元数据)
- 一个二进制或序列化的结构,记录了归档中每个文件的:
- 文件路径(在 phar 内部的虚拟路径)
- 偏移量(在文件中的位置)
- 大小
- 压缩方式(none / gzip / bzip2)
- 权限(如 0644)
- 时间戳
- 是否为目录
- 还可能包含全局元数据(通过
setMetadata()设置)。
这部分由 Phar 扩展自动管理,开发者通常无需手动操作。
3. File Contents(文件内容区)
- 所有被添加到 Phar 中的实际文件内容(按顺序或按压缩方式存储)。
- 每个文件可以独立选择是否压缩(Gzip 或 Bzip2)。
- 在 PHP 中可通过
phar://流访问,例如:
file_get_contents('phar://myapp.phar/config/app.php');
4. Signature(签名,可选)
- 位于文件末尾(但在
__HALT_COMPILER();之后?不,实际在__HALT_COMPILER();之前的数据之后)。 - 用于验证 Phar 文件是否被篡改。
这个没啥好讲的,一般不是考点
生成一个phar文件
注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。
<?phpclass TestObject {}$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();//开启 Phar 的缓冲写入模式。操作暂存内存中$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub$o = new TestObject();$phar->setMetadata($o); //将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test"); //在 Phar 归档内部创建一个名为test.txt的虚拟文件,内容为字符串 "test"。//签名自动计算$phar->stopBuffering();//将内存中数据写入磁盘
?>
我们可以在phpstorm里面看到phar文件展开的格式

phar文件中的meta-data是以序列化的形式储存的

当 PHP 访问 phar://... 流时(如 file_exists('phar://a.phar')),会自动反序列化 manifest 中的 metadata。
metadata里面序列化后的数据:

触发反序列化的函数
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:

这里我们来演示一下phar触发反序列化
生成phar的php:
<?php
phpinfo();
class TestObject { public function __destruct() { echo $this->data; echo 'Destruct called'; }
} @unlink("phar.phar"); $phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new TestObject();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
读取phar的php:
<?php
class TestObject { public function __destruct() { echo $this->data; echo 'Destruct called'; }
}
include('phar://phar.phar/test.txt');
运行第一个生成phar文件
然后运行第二个php

可以看到成功触发了反序列化
Bzip / Gzip协议和phar://一样可以触发反序列化
$filename = 'compress.zlib://phar://phar.phar/test.txt';
利用phar进行rce
利用条件
1.phar文件要能够上传到服务器端。
2.如file_exists(),fopen(),file_get_contents(),file()等文件操作的函数要有可用的魔术方法作为"跳板"。
3.文件操作函数的参数可控,且::、/、phar等特殊字符没有被过滤。
看几个例题
待补充.....