前言
通常我们在利用反序列化漏洞的时候,只能将序列化后的字符串传入 unserialize() ,随着代码安全性越来越高,利用难度也越来越大。但是利用 phar 文件会以反序列化的形式存储用户自定义的 meta-data 这一特征,拓展了 php 反序列化漏洞的攻击面。该方法在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合 phar://
协议,可以不依赖 unserialize() 直接进行反序列化操作。
Phar反序列化漏洞的原理
什么是Phar?
Phar("Php ARchive") 是PHP 里类似于 JAR 的一种打包文件,在 PHP 5.3 或更高版本中默认开启,这个特征使得 PHP 也可以像 Java 一样方便地实现应用程序打包和组件化。一个应用程序可以打包一个Phar 包, 直接放到 PHP-FPM
中运行。
PHP内置的流包装器
php 通过用户定义和内置的“流包装器”实现复杂的文件处理功能。内置包装器可用于文件系统函数。如(fopen(),copy(),file_exists()和filesize())。 phar://
就是一种内置的流包装器
file:// — 访问本地文件系统,在用文件系统函数时默认就使用该包装器
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
Phar文件结构
- a stub
可以理解为一个标志,格式为xxx<?php xxx; __HALT_COMPILER();?>
,前面的xxx内容不限,但必须是以__HALT_COMPILER();?>
来结尾,否则phar扩展将无法识别这个文件为phar文件。
- a manifest describing the contents、
Phar文件中被压缩的文件的一些信息,其中Meta-data
部分的信息会以序列化的形式储存,这里就是漏洞利用的关键点
- the file contents
被压缩的文件内容,在没有特殊要求的情况下,这个被压缩的文件内容可以随便写的,因为我们利用这个漏洞主要是为了触发它的反序列化
- a signature for verifying Phar integrity
签名,放在文件末尾,格式如下:
测试
根据文件结构我们来自己构建一个phar文件,php内置了一个Phar类来处理相关操作。
注意:要将php.ini中的phar.readonly
选项设置为Off
,否则无法生成phar文件。
phar_demo.php
<?php
class TestObject {
}
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new TestObject();
$o->data = 'seizer';
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
运行代码后,会生成一个phar.phar的文件在当前目录下
Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000: 3C 3F 70 68 70 20 5F 5F 48 41 4C 54 5F 43 4F 4D <?php.__HALT_COM
00000010: 50 49 4C 45 52 28 29 3B 20 3F 3E 0D 0A 64 00 00 PILER();.?>..d..
00000020: 00 01 00 00 00 11 00 00 00 01 00 00 00 00 00 2E ................
00000030: 00 00 00 4F 3A 31 30 3A 22 54 65 73 74 4F 62 6A ...O:10:"TestObj
00000040: 65 63 74 22 3A 31 3A 7B 73 3A 34 3A 22 64 61 74 ect":1:{s:4:"dat
00000050: 61 22 3B 73 3A 36 3A 22 73 65 69 7A 65 72 22 3B a";s:6:"seizer";
00000060: 7D 08 00 00 00 74 65 73 74 2E 74 78 74 04 00 00 }....test.txt...
00000070: 00 CE E8 66 61 04 00 00 00 0C 7E 7F D8 B6 01 00 .Nhfa.....~.X6..
00000080: 00 00 00 00 00 74 65 73 74 A6 98 F8 F3 51 ED C0 .....test&.xsQm@
00000090: FE 94 7A E7 FC 1A 77 1D 83 52 78 FD B0 02 00 00 ~.zg|.w..Rx}0...
000000a0: 00 47 42 4D 42 .GBMB
可以明显的看到meta-data是以序列化的形式存储的。
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://
伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:
phar_fan.php
<?php
class TestObject{
function __destruct()
{
echo $this -> data; // TODO: Implement __destruct() method.
}
}
include($_GET['phar']);
?>
成功触发反序列化