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

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

缺陷编号:wooyun-2015-0150916

漏洞标题:QQ浏览器9内置帐号助手代码缺陷导致可获取记住的其它网站密码

相关厂商:腾讯

漏洞作者: gainover

提交时间:2015-10-31 20:57

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

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

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

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

之前版本8时,已经发过一个可以获取记住的密码的问题,但现在QQ浏览器从8升级到版本9了,内核已换成webkit了,扩展机制也不是自己实现的那一套了。然而QQ浏览器9中,记住密码的功能依然是通过扩展来实现,并且由于扩展的实现代码存在缺陷,依然可以导致跨域获取记住的其他网站密码。

详细说明:

1. 下载QQ浏览器9 最新版本

2.png


2. 首先,随便打开一个页面,我们可以看看QQ浏览器里内置了哪些扩展会使用到content script,发现有一个account helper,这不又是帐号助手么,这个内置的帐号助手会不会又存在问题?

1.png


从代码里可以看到记住密码的填充流程:
a. 建立一个connect,
b. 向背景页发送一个消息,用于获取需要填充的密码,
c. 背景页根据消息获得数据后,发回给当前页面的content script,
d. 当前页的content script的接受fill指令后,执行setData函数存储获取的密码数据。。最后执行fill()函数进行表单填充。
3. 来看看这个流程里会不会有什么缺陷。。
从步骤2可以看出,获取填充密码的流程位于背景页中,所以我们根据
chrome-extension://dbjbbhdmofcmcjdmfolgmgcihbjbaali/account_helper.js
这个地址可以得到背景页地址:
chrome-extension://dbjbbhdmofcmcjdmfolgmgcihbjbaali/background.html
定位background.html里与获取填充密码相关的代码:

var map = {}
, blackListMap = {};
chrome.extension.onConnect.addListener(function(a) {
/^accountHelper/.test(a.name) && a.onMessage.addListener(function(b) {
var c, d;
if (b && b.cmd) {
if (d = getDomain(a.sender.tab.url),
"get" !== b.cmd && isBlackList(d))
return void chrome.contextMenus.update(menuParentId, {
enabled: !1
});
.....
case "get":
get(d, {
id: a.sender.tab.id,
url: a.sender.tab.url,
title: a.sender.tab.title
}, function(b) {
if (b && b.length) {
if ("1" == b[0].isBlackList)
return void (blackListMap[b[0].domainURL] = 1);
blackListMap[b[0].domainURL] = 0,
b = sortByHostURL(b, getHostname(a.sender.tab.url)),
a.postMessage({
cmd: "fill",
passwordData: b
})
}
}
);
break;


从代码可以看到,get密码的函数调用, get(d, {...}, 回调函数);
d变量为需要获取密码的域名,并且,d = getDomain(a.sender.tab.url)
也就是说,我们所要获取哪个域名下记住的密码,是通过getDomain函数从页面URL里取出来的。
那么,getDomain函数会不会存在问题呢?
4. 为了看看getDomain是如何工作的,我们打开QQ空间的登录页面,并且记住密码,

3.png


然后,我们在background.html的getDomain函数里下断点:

4.png


继续跟进tld.getDomain函数:

5.png


在这个函数里,url会经过 isValid --> cleanHostValue --> extractTldFromHost 进入b变量,b进入f变量,最终函数返回f.
其中isValid比较简单,不管了,
所以,我们跟进 d.cleanHostValue函数:

6.png


5. 如上图所示,cleanHostValue函数里,是通过正则i,从url里来进行匹配,最终返回正则匹配结果的第4个group,b[4],因此正则i成了关键,我们看看正则i是啥?

/(^https?:?\/\/|^\/\/)?([^:]+(:[^@]+)?@)?([^:@\/]+)(:|\/|$)/


正则的第4个括号是 host,对正则认真分析一下,不难构造出下面的URL:
http://**.**.**.**:8080/?@**.**.**.**
和正则对应一下,如下图所示:

7.png


可见,我们的地址虽然是**.**.**.**:8080 下的,但 host 会被认为是**.**.**.**
6. 接下来的extractTldFromHost等函数关系并不大,我们为了验证结果,本地搭建一个8123的服务,然后页面内容就是QQ空间同样的表单。
用QQ浏览器访问:http://**.**.**.**:8123/?@**.**.**.**
可以看到密码会被自动填充。

8.png


并且这个密码可以通过脚本被获取:
测试代码见测试代码区域。
具体效果见漏洞证明。
7. 虽然已经可以获取密码了,我们还是继续看下剩下的处理流程:

9.png


可以看到被绕过的host为**.**.**.**,最后经过extractTldFromHost函数后, 返回 **.**.**.**
8. 继续:

10.png


可以看到,到了get函数时, d 就是 getDomain的返回值 **.**.**.**,
而a.sender.tab.url就是我们页面的url地址:"http://**.**.**.**:8123/?@**.**.**.**/"
get函数的回调内容,就是存储的密码信息,随后就是发送fill指令回content script

11.png


9. 差不多就是这样了。。

漏洞证明:

如下图所示:
图片地址:http://**.**.**.**/lc/35JrkTMSnntgxz3Em4N 密码:Q0UE

修复方案:

从URL里获取主机域名,不需要用正则吧? 显然有其它更保险的获取办法。。。

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:10

确认时间:2015-11-02 15:06

厂商回复:

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

最新状态:

暂无