滥用XSS过滤器:一个^符号引发的XSS漏洞(CVE-2016-3212)
过去,我在日本的CODE BLUE信息安全会议上讨论了利用IE XSS过滤器进行XSS攻击的方法。类似的漏洞在2016年6月的补丁中作为CVE-2016-3212被修复。本文将详细解释这个漏洞的细节。
如我的幻灯片所述,通过将XSS过滤器规则应用于不相关的上下文,即使页面本身没有XSS漏洞,我们也可以利用过滤器将.
替换为#
的行为进行XSS攻击。
为了防止此类攻击,微软在2015年12月的补丁中更改了过滤器行为。此后,^
被用作.
的替换字符,而不是#
。这确实可以防止上述攻击,但也带来了另一个问题。几个月后,我在Google的域中确认了利用此行为的XSS,并通过Google VRP获得了3133.7美元的奖励。
Google几乎在所有服务中都设置了X-XSS-Protection: 1;mode=block
头,但并非全部。因此,我仔细检查了一些没有mode=block
的页面,结果发现cloud.google.com上的Javadoc存在漏洞页面。
我放置了一个近似副本:
http://vulnerabledoma.in/xxn/xss_javadoc.html
当XSS过滤器将一个.
替换为^
时,此页面就容易受到XSS攻击。你能找到是哪里吗?
答案是黄色部分的.
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<!-- NewPage -->
<html lang="en">
<head>
<title>javadoc</title>
<script type="text/javascript">
targetPage = "" + window.location.search;
if (targetPage != "" && targetPage != "undefined")
targetPage = targetPage.substring(1);
if (targetPage.indexOf(":") != -1 || (targetPage != "" && !validURL(targetPage)))
targetPage = "undefined";
function validURL(url) {
try {
url = decodeURIComponent(url);
}
catch (error) {
return false;
}
var pos = url.indexOf(".html");
if (pos == -1 || pos != url.length - 5)
return false;
var allowNumber = false;
var allowSep = false;
var seenDot = false;
for (var i = 0; i < url.length - 5; i++) {
var ch = url.charAt(i);
if ('a' <= ch && ch <= 'z' ||
'A' <= ch && ch <= 'Z' ||
ch == '$' ||
ch == '_' ||
ch.charCodeAt(0) > 127) {
allowNumber = true;
allowSep = true;
} else if ('0' <= ch && ch <= '9'
|| ch == '-') {
if (!allowNumber)
return false;
} else if (ch == '/' || ch == '.') {
if (!allowSep)
return false;
allowNumber = false;
allowSep = false;
if (ch == '.')
seenDot = true;
if (ch == '/' && seenDot)
return false;
} else {
return false;
}
}
return true;
}
function loadFrames() {
if (targetPage != "" && targetPage != "undefined")
top.classFrame.location = top.targetPage;
}
</script>
</head>
<frameset cols="20%,80%" title="Documentation frame" onload="top.loadFrames()">
<frameset rows="30%,70%" title="Left frames" onload="top.loadFrames()">
<frame src="/" name="packageListFrame" title="All Packages">
<frame src="/" name="packageFrame" title="All classes and interfaces (except non-static nested types)">
</frameset>
<frame src="/" name="classFrame" title="Package, class and interface descriptions" scrolling="yes">
<noframes>
<noscript>
<div>JavaScript is disabled on your browser.</div>
</noscript>
<h2>Frame Alert</h2>
<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="overview-summary.html">Non-frame version</a>.</p>
</noframes>
</frameset>
</html>
|
在<script>
中,它检查通过location.search
给定的字符串是否安全。例如,以下不安全的URL被阻止:
http://vulnerabledoma.in/xxn/xss_javadoc.html?javascript:alert(1)
那么,当黄色部分的.
被替换为^
时会发生什么?
让我们实际尝试一下。如果你在目标URL中放入以下字符串,页面内容会被强制匹配XSS过滤器规则,我们可以将目标的.
替换为^
:
你可以使用未安装2016年6月补丁的IE/Edge从以下URL重现此漏洞:
http://vulnerabledoma.in/xxn/xss_javadoc.html?javascript:alert(1)//"++++++++++++.i+++=
我还为已应用补丁的用户放置了替换后的页面,你可以确认相同的行为:
http://vulnerabledoma.in/xxn/xss_javadoc2.html?javascript:alert(document.domain)
#
和^
的一个关键区别是:#
在JavaScript中不是运算符,但^
是运算符。例如,如果页面中有a.b;
,它被替换为#
和^
,a#b;
是语法错误,但a^b;
是有效语法。这就带来了XSS漏洞。
在2016年6月补丁之后,当XSS过滤器替换.
时,即使页面没有X-XSS-Protection
头,也会强制执行mode=block
行为。
当我看到^
显示时,我感到惊讶和厌恶,但无论如何,它终于平静下来了!
此外,在最近的补丁(2016年7月)中,微软似乎几乎杀死了利用XSS过滤器进行XSS攻击的可能性。我将在下一篇文章中详细说明这一点:)
谢谢!
发布时间:2016年7月15日星期五上午7:10
作者:Masato Kinugawa