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

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

缺陷编号:wooyun-2013-046216

漏洞标题:Destoon全版本通杀SQL注入

相关厂商:DESTOON

漏洞作者: Chora

提交时间:2013-12-17 14:49

修复时间:2014-03-17 14:50

公开时间:2014-03-17 14:50

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

还有一个类似的点在特定的环境里触发,还没测试,明天测试了再说。

详细说明:

common.inc.php 0x00

if(!empty($_SERVER['REQUEST_URI'])) strip_uri($_SERVER['REQUEST_URI']); //跟进0x01
if($_POST) { $_POST = strip_sql($_POST); strip_key($_POST); }//跟进0x01
if($_GET) { $_GET = strip_sql($_GET); strip_key($_GET); }
if($_COOKIE) { $_COOKIE = strip_sql($_COOKIE); strip_key($_COOKIE); }
if(!IN_ADMIN) {
$BANIP = cache_read('banip.php');
if($BANIP) banip($BANIP);
$destoon_task = '';
}
if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
......
$forward = isset($forward) ? urldecode($forward) : $DT_REF;//用这里的urldecode来绕过。
......


include/global.func.php 0x01

function strip_uri($uri) { //检查了REQUEST_URI,里面有%就解码,解到最后检查敏感字符,我们要引入',即使我们双编码过后,最终还是会被还原成',这里检查了',所以GET提交无解,但是我们POST提交的话,REQUEST_URI就不会接受任何数据,从而绕过了检查。
if(strpos($uri, '%') !== false) {
while($uri != urldecode($uri)) {
$uri = urldecode($uri);
}
}
if(strpos($uri, '<') !== false || strpos($uri, "'") !== false || strpos($uri, '"') !== false || strpos($uri, '0x') !== false) {
dhttp(403, 0);
dalert('HTTP 403 Forbidden', DT_PATH);
}
}
function strip_sql($string) {//一长串过滤。我们绕过了上面,下面的话可以采用URL双编码绕过。比如union就可以写成unoin%256E来绕过,前提是要有urldecode或者rawurldecode。
$search = array("/union/i","/0x([a-z0-9]{2,})/i","/select([[:space:]\*\/\-])/i","/update([[:space:]\*\/])/i","/replace([[:space:]\*\/])/i","/delete([[:space:]\*\/])/i","/drop([[:space:]\*\/])/i","/outfile([[:space:]\*\/])/i","/dumpfile([[:space:]\*\/])/i","/load_file\(/i","/substring\(/i","/substr\(/i","/concat\(/i","/concat_ws\(/i","/ascii\(/i","/hex\(/i","/ord\(/i","/char\(/i");
$replace = array('unio&#110;','0&#120;\\1','selec&#116;\\1','updat&#101;\\1','replac&#101;\\1','delet&#101;\\1','dro&#112;\\1','outfil&#101;\\1','dumpfil&#101;\\1','load_fil&#101;(','substrin&#103;(','subst&#114;(','conca&#116;(','concat_w&#115;(','asci&#105;(','he&#120;(','or&#100;(','cha&#114;(');
return is_array($string) ? array_map('strip_sql', $string) : preg_replace($search, $replace, $string);
}


绕过了上面就简单了。
module/member/chat.inc.php

switch($action) {
......
default:
if(isset($touser) && check_name($touser)) {
if($touser == $_username) dalert('不能与自己对话', 'chat.php');
if(!$MG['chat']) {
login(); //当然要登陆咯。
dalert('您所在的会员组没有权限发起对话', 'grade.php');
}
$user = userinfo($touser);
$user or dalert('会员不存在', 'chat.php');
if($user['black']) {
$black = explode(' ', $user['black']);
if(in_array($chatuser, $black)) dalert('对方拒绝与您对话', 'chat.php');
if(!$_username && in_array('Guest', $black)) dalert('对方拒绝与您对话', 'chat.php');
}
$chat_fromuser = $chatuser;
$chat_touser = $touser;
$chat_id = $chatid = get_chat_id($chat_fromuser, $chat_touser);
$online = online($user['userid']);
$user['type'] = 'member';
$type = 1;
if(!$_userid && !is_file(get_chat_file($chatid))) $type = 4;
$head_title = '与【'.$user['company'].'】对话中';
$chat = $db->get_one("SELECT * FROM {$table} WHERE chatid='$chatid'");
$chat_status = 3;
if($chat) { //第一次创建会话的时候执行下面的else,创建过后执行if下面的。
//对话已经存在
if($chat['touser'] == $_username) {//当前为接收人
if($DT_TIME - $chat['freadtime'] > $MOD['chat_poll']*3) {//发起对话人已经断开
$db->query("UPDATE {$table} SET fromuser='$chat_fromuser',touser='$chat_touser',tgettime=0 WHERE chatid='$chatid'");
} else {//发起人在线
dheader('?chatid='.$chatid);
}
//
} else {//当前为发起人
if($DT_TIME - $chat['treadtime'] > $MOD['chat_poll']*3) {//接收人已经断开
$db->query("UPDATE {$table} SET tgettime=0 WHERE chatid='$chatid'");
} else {//接收人在线
//
}
}
} else {//第一次执行这里。
$forward = dsafe($forward);//过滤某些敏感字符的函数,不跟了。累死懒得贴,反正还是双编码绕过就行了。
if(strpos($forward, $MOD['linkurl']) !== false) $forward = '';
//创建一个新对话
$db->query("INSERT INTO {$table} (chatid,fromuser,touser,tgettime,forward) VALUES ('$chat_id','$chat_fromuser','$chat_touser','0','$forward')"); //关键点!0x00已经贴出来了$forward是urldecode所解码而得到的,所以我们能引入'来进行注射。记得$chat_touser要等于当前用户,这样做是为了下面的可显查询。不然就只能盲注。
}
} else if(isset($chatid) && is_md5($chatid)) {
$chat = $db->get_one("SELECT * FROM {$table} WHERE chatid='$chatid'"); //这里构造我们刚刚插入的$chatid的值就可以查询出来了。
if($chat && $chat['touser'] == $_username) {//等于当前用户。
$chat_id = $chatid;
$chat_status = 3;
if(check_name($chat['fromuser'])) {
if($DT_TIME - $chat['freadtime'] > $MOD['chat_poll']*3) {//发起对话人已经断开
$db->query("UPDATE {$table} SET tgettime=0 WHERE chatid='$chatid'");
dheader('chat.php?touser='.$chat['fromuser']);
}
$user = userinfo($chat['fromuser']);
$online = online($user['userid']);
$user['type'] = 'member';
} else {
$user = array();
$user['type'] = 'guest';
$user['ip'] = $chat['fromuser'];
$user['area'] = ip2area($chat['fromuser']);
if($DT_TIME - $chat['freadtime'] > $MOD['chat_poll']*3) {//发起人是游客,并且已经断开,只能查看记录
$time = $DT_TIME - $MOD['chat_poll']*4;
$db->query("UPDATE {$table} SET freadtime='$time' WHERE chatid='$chatid'");
}
}
$head_title = '与'.($user['type'] == 'guest' ? '【游客】' : $chat['fromuser']).'对话中';


是root权限又能引入单引号的话各显神通吧。

漏洞证明:

1.png


2.png

3.png

4.png

5.png

修复方案:

休息。。。

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2013-12-19 16:06

厂商回复:

已确认存在,我们会尽快修复

最新状态:

2013-12-20:感谢Chora,已修复,详见:http://bbs.destoon.com/thread-55559-1-1.html