目录
前言
除了unserialize()来利用反序列化漏洞之外,还可以利用phar文件以序列化的形式存储用户自定义的meta-data这一特性,扩大php反序列化漏洞的攻击面。该方法在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作。
这次在比赛当中遇到phar反序列化,却不知道如何下手。社区里前面也有人总结过,但没有包括一些ctf利用和zxc师傅发现的姿势。于是就自己来整理了。
phar反序列化漏洞的原理
什么是phar文件?:
在软件中,PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发。wiki
php通过用户定义和内置的“流包装器”实现复杂的文件处理功能。内置包装器可用于文件系统函数,如(fopen(),copy(),file_exists()和filesize()。 phar://就是一种内置的流包装器。
php中一些常见的流包装器如下:
1 |
file:// — 访问本地文件系统,在用文件系统函数时默认就使用该包装器 |
流包装器的详细内容可以参考
php流Streams、包装器wrapper 详解
phar文件的结构:
phar文件都包含以下几个部分:
1. stub
phar文件的标志,必须以 xxx __HALT_COMPILER();?> 结尾,否则无法识别。xxx可以为自定义内容。
2. manifest
phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是漏洞利用最核心的地方。
3. content
被压缩文件的内容
4. signature (可空)
签名,放在末尾。
生成一个phar文件:
php内置了一个phar类来处理相关操作。
注意:这里要将php.ini里面的phar.readonly
选项设置为Off
。并把分号去掉。
(如果你在命令行运行PHP文件还是无法生成成功,请使用php -v查看php版本并在修改指定版本的php.ini。)
1 |
|
执行这个php文件,会生成一个phar.phar文件。打开查看可以看到Meta-data的内容是以序列化的形式储存的。
php在解析这个phar的时候,还会对meta-data数据进行一次反序列化。PHP底层代码:
通过反序列化,我们就能够控制一些类的变量进行利用。
漏洞利用条件
- phar文件要能够上传到服务器端。
- 要有可用的魔术方法作为“跳板”。
- 文件操作函数的参数可控,且
:
、/
、phar
等特殊字符没有被过滤。
受影响的文件操作函数
知道创宇测试后受影响的函数列表:
但实际并不止这一些。
参考zxc师傅的文章:https://blog.zsxsoft.com/post/38
在跟踪了受影响函数的调用情况后发现,除了所有文件函数,只要是函数的实现过程直接或间接调用了php_stream_open_wrapper
。都可能触发phar反序列化漏洞。
以下这些方式都可触发phar反序列化漏洞:
exif
exif_thumbnail
exif_imagetype
gd
imageloadfont
imagecreatefrom***
hash
hash_hmac_file
hash_file
hash_update_file
md5_file
sha1_file
file / url
get_meta_tags
get_headers
standard
getimagesize
getimagesizefromstring
zip
$zip = new ZipArchive();
$res = $zip->open('c.zip');
$zip->extractTo('phar://test.phar/test');
Bzip / Gzip
当环境限制了phar不能出现在前面的字符里。可以使用compress.bzip2://和compress.zlib://绕过
$z = 'compress.bzip2://phar:///home/sx/test.phar/test.txt';
$z = 'compress.zlib://phar:///home/sx/test.phar/test.txt';
配合其他协议:(SUCTF)
当环境限制了phar不能出现在前面的字符里,还可以配合其他协议进行利用。
php://filter/read=convert.base64-encode/resource=phar://phar.phar
Postgres
1 |
|
pgsqlCopyToFile和pg_trace同样也是能使用的,需要开启phar的写功能。
Mysql
LOAD DATA LOCAL INFILE也会触发这个php_stream_open_wrapper
配置一下mysqld:
[mysqld]
local-infile=1
secure_file_priv=""
1 |
|
漏洞的利用实例
一个简单的例子
phar.php
1 |
|
index.php
1 |
|
使用php phar.php
生成phar.phar
文件。
访问:http://127.0.0.1/index.php?file=phar://phar.phar
返回:Threezh1。 反序列化利用成功。
绕过文件格式限制
- 上传html页面: upload.html
- 后端校验页面:upload.php
- 一个漏洞页面:index.php (存在file_exits(), eval()函数)
- 一个上传目录: upload_file/
upload.html:
1 |
<!DOCTYPE html> |
upload.php
仅允许格式为gif的文件上传。上传成功的文件会存储到upload_file目录下。
1 |
|
index.php
1 |
|
绕过思路:GIF格式验证可以通过在文件头部添加GIF89a绕过
我们可以构造一个php来生成phar.phar。
1 |
|
利用过程:
- 一、生成一个phar.phar,修改后缀名为phar.gif
- 二、上传到upload_file目录下
可见已经执行了phpinfo命令了。
通过修改后缀名和文件头,能够绕过大部分的校验。
配合PHP内核哈希表碰撞攻击
参考:https://xz.aliyun.com/t/2613
在PHP内核中,数组是以哈希表的方式实现的,攻击者可以通过巧妙的构造数组元素的key使哈希表退化成单链表(时间复杂度从O(1) => O(n))来触发拒绝服务攻击(DDOS)。
使用 phar.php 生成恶意的phar文件:
1 |
|
index.php:
1 |
|
访问:http://127.0.0.1/index.php 耗时67秒
漏洞的检测与修复
检测:
- 使用RIPS自动化检测
RIPS对敏感字符串分析使我们能够精确评估文件路径是完全还是由攻击者控制,以及是否可以phar://注入。
修复:
- 在文件系统函数的参数可控时,对参数进行严格的过滤。
- 严格检查上传文件的内容,而不是只检查文件头。
- 在条件允许的情况下禁用可执行系统命令、代码的危险函数。
参考
- https://paper.seebug.org/680/
- https://www.freebuf.com/articles/web/182231.html
- https://xz.aliyun.com/t/2715
- https://xz.aliyun.com/t/2613
- https://blog.zsxsoft.com/post/38
- https://i.blackhat.com/us-18/Thu-August-9/us-18-Thomas-Its-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf
- By:threezh1.com
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论