利用XSS过滤器:一个^符号引发的跨站脚本攻击(CVE-2016-3212)

本文详细分析了IE浏览器XSS过滤器的安全漏洞CVE-2016-3212,展示了如何利用过滤器将点号替换为^符号实现跨站脚本攻击,包含Google域内的实际案例和漏洞复现方法。

滥用XSS过滤器:一个^符号导致XSS(CVE-2016-3212)

过去,我在日本信息安全会议CODE BLUE上讨论了利用IE XSS过滤器进行XSS攻击的方法。类似的漏洞在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攻击的可能性。我将在下一篇文章中详细说明:)

谢谢!

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计