漏洞概要 关注数(24) 关注此漏洞
缺陷编号:wooyun-2015-0111199
漏洞标题:QQ浏览器扩展机制设计缺陷可获取内置帐号助手功能所记住的其它网站密码
相关厂商:腾讯
漏洞作者: gainover
提交时间:2015-04-30 05:34
修复时间:2015-07-29 10:48
公开时间:2015-07-29 10:48
漏洞类型:设计错误/逻辑缺陷
危害等级:高
自评Rank:15
漏洞状态:厂商已经确认
漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]
Tags标签: 无
漏洞详情
披露状态:
2015-04-30: 细节已通知厂商并且等待厂商处理中
2015-04-30: 厂商已经确认,细节仅向厂商公开
2015-05-03: 细节向第三方安全合作伙伴开放
2015-06-24: 细节向核心白帽子及相关领域专家公开
2015-07-04: 细节向普通白帽子公开
2015-07-14: 细节向实习白帽子公开
2015-07-29: 细节向公众公开
简要描述:
祝贺某人大婚-QQ浏览器扩展机制设计缺陷可获取内置帐号助手功能所记住的其它网站密码
预祝某人新婚快乐!
别人笑我太猥琐,我笑着像一个红苹果:“不猥琐怎么混乌云!”
详细说明:
1. 首先说说chrome扩展开发里的content script,引用360浏览器开放平台里的翻译文字(http://open.chrome.360.cn/extension_dev/content_scripts.html)
“Content script是在一个特殊环境中运行的,这个环境成为isolated world(隔离环境)。它们可以访问所注入页面的DOM,但是不能访问里面的任何javascript变量和函数。 对每个content script来说,就像除了它自己之外再没有其它脚本在运行。 反过来也是成立的: 页面里的javascript也不能访问content script中的任何变量和函数。”
2. 简言之,content script需要与WEB页面之间需要一定的隔离措施,否则会产生问题。QQ浏览器自己实现了一套类似于chrome扩展的机制,也有content script,那么QQ浏览器的content script是否做好了隔离措施呢?
3. 带着这个疑问,首先看看QQ浏览器注入的某一段content script:
可以看到调用了
var scriptId = document.documentElement.getAttribute('ecdfbieajbfacebidaiabaibbcddbcfi_h');
4. 如果没有做好隔离,我们自己写一个简单的页面来测试一下?
利用此段代码来覆盖 document.documentElement.getAttribute 函数,
document.documentElement.getAttribute=function(a){
alert(a);
}
如下图所示:
可以看到,这说明QQ浏览器并没有做好隔离措施,页面JS代码覆盖后的getAttribute函数,被content script成功调用!
5. 但是,就算我们能通过覆盖某个函数来劫持content script里的调用,我们可以做什么有“危害”的事情呢?
有哪些利用方式,你们自己想!本案例说的就是其中一种情况!
首先我们hook住某个可能被content script调用的函数 比如:setTimeout
var m=setTimeout;
window["setTimeout"]=function(a,t){
alert(a)
m(a,t);
}
看看弹出的内容:
看起来并没有什么用途!
6. 我们换个姿势,看看setTimeout的caller是什么函数?
var m=setTimeout;
window["setTimeout"]=function(a,t){
alert(arguments.callee.caller)
m(a,t);
}
这一次弹出了一个handleInit函数,
这个函数有没有什么用处呢?通过一段时间分析发现,这段content script是来自QQ浏览器的帐号助手功能。
它首先会调用 handleInit 函数去初始化GlobalVar 这个配置变量的值,
之后则会调用handleFill 函数去填充当前的表单!
7. 注意看以下这些代码:
function handleInit(response){
...
GlobalVar.tabUrl = response.data.tabUrl;
GlobalVar.tabHostname = response.data.tabHostname;
GlobalVar.tabTitle = response.data.tabTitle;
...
}
...
sendBG({
cmd : "fill"
});
...
function sendBG(msg) {
//TODO:指定top有farm跨域问题,不指定可能会导致记录错页面
// msg.title = window.top.document.title;
// msg.url = window.location.href;
msg.title = GlobalVar.tabTitle||document.title;
msg.url = GlobalVar.tabUrl||window.location.href;
msg.hostname = GlobalVar.tabHostname||window.location.hostname;
//msg.title = window.document.title;
qqbrowser.extension.sendMessage(msg, function(response) {
handleResponse(response);
});
}
可以看到sendBG发送填充命令时,发送的msg参数里的title,url,hostname等值均是来自 GlobalVar,只有当GlobalVar里相应属性不存在时,才会从document.title、window.location.href与window.location.hostname里取值。
8. 问题来了,如果我们在自己的页面调用一次 handleInit ,就可以任意修改下面这3个属性的值。
GlobalVar.tabUrl = response.data.tabUrl;
GlobalVar.tabHostname = response.data.tabHostname;
GlobalVar.tabTitle = response.data.tabTitle;
最终页面填充表单的数据,将会根据GlobalVar.tabHostname,GlobalVar.tabUrl等值来获得!
怎么调用handleInit?上面已经说到了arguments.callee.caller其实就是指向的handleInit函数:
代码如下:
var i=0;
var m=setTimeout;
window["setTimeout"]=function(a,t){
//防止重复调用,陷入死循环
..
//见最后测试代码部分
}
运行后,可以看到QQ空间的登录QQ号和密码都出现在了我们当前页面的文本框中!
当然,在此之前,你需要登录过QQ空间,并且记住了密码!
9.至于从文本框里读取所获取的密码,就不表了!
10. 进一步,可能会有一个网站有多个帐号,比如QQ空间有好几个人登录过!
我们怎么获取所有该网站下所有记住的密码呢?比如下面QQ空间这种有2个登录帐号的情况!
11. 嗯!方法是有的,进一步劫持内部函数!原理一样,这次劫持JSON.parse
var JSON2=JSON;
var JSON={};
JSON.parse=function(a){
alert(a);
return JSON2.parse(a);
};
JSON.stringify=function(a){
return JSON2.stringify(a);
};
可以看到,这次可以截获到2个登录密码数据!
12. 继续!如果你拿着上面的劫持代码,到装有IE8的机器上,可能会看不到效果!这是因为,在IE8中,
setTimeout=function(){alert(1)}
这种覆盖操作,是不会成功的!
因此,我们需要小小的绕过一下,
eval("var setTimeout;");
setTimeout=function(){alert(1)}
漏洞证明:
在线测试地址见测试代码部分。
见:http://v.youku.com/v_show/id_XOTQ0NzgyNDc2.html
本例可能只是此设计问题能导致的安全问题之一。
那个帐号助手,在XP下好像本身功能就不太稳定,QQ空间登录不会提示“记住密码”。
最好在WIN7+高版本IE下测试!
修复方案:
自己翻chrome扩展的那篇论文。
版权声明:转载请注明来源 gainover@乌云
漏洞回应
厂商回应:
危害等级:高
漏洞Rank:15
确认时间:2015-04-30 10:47
厂商回复:
非常感谢您的报告,问题已着手处理,感谢大家对腾讯业务安全的关注。如果您有任何疑问,欢迎反馈,我们会有专人跟进处理。
最新状态:
暂无