DigiNinja postMessage - Sender Lab

2023/08/25 10:18PM

Description

This page logs usage to the iframe, setup an environment where it is possible to spoof log messages from your own domain.

Step 1
Step 2

Using the parent `iframe` we can send log messages to the child `iframe`.

Checking out the "Sources" tab in chrome dev tools we can see that the child `iframe` along with its JS files.

Looking at the code in the parent, we can see the child `iframe` is called "`s_iframe`".

Looking at the parent JS files, we can see that we are getting a reference to the child `iframe` and sending it a `postMessage`.

Checking out the child `iframe` code we can see that the child `iframe` is accepting a `postMessage`.

Step 3

Before we can exploit this `postMessage` vulnerability, we first need to check if we can put the child `iframe` on to our own website. The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a `<frame>, <iframe>, <embed> or <object>.`

To check if the `X-Frame-Options` HTTP header is being set on a child `iframe` we can use chrome dev tools network tab and filter for Doc.

Clicking on the child document we can see that there is no `X-Frame-Options` header in the response headers. This means we can host this document on our own website with the child document in an `iframe`.

Step 4

Using the following code, I will host the child `iframe` on my localhost using python webserver.


    <html>
        <head>
            <title>PostMessage Lab</title>
        </head>
        <h1>Shelled's Website</h1>
        <input type="text" id="message" name="message" value="hi">
        <input type="button" id="send_message_button" value="Send Message">
        <body>
            <iframe id="child_i" src="https://html5server.digi.ninja/s_child.html?origin=https://html5.digi.ninja" width="500" height="500"></iframe>
            <script>
                const sendMessage = () => {
                    const childFrame = document.getElementById('child_i');
                    const messageInput = document.getElementById('message');

                    childFrame.contentWindow.postMessage(messageInput.value, '*')
                }

                const sendMessageButton = document.getElementById("send_message_button");
                sendMessageButton.addEventListener("click", sendMessage, false);
            </script>
        </body>
    </html>
Step 5

When sending a request, you will notice that an alert will pop-up indicating that the origin is incorrect.

Inspecting the code in the child `iframe` we can see that there is a check to see if the origin is same as CLIENT_DOMAIN.


    const regex = /https?:\/\//gi
	const CLIENT_DOMAIN='https://html5.digi.ninja';
	
	let messages = document.getElementById("s_messages");
	let just_domain = CLIENT_DOMAIN.replace(regex, '');

	if (!e.origin.match(just_domain)) {
		alert ("Message came in from wrong origin");
		return;
	}

The check is done using `origin.match()`. The match method retrieves the result of matching the string against a regular expression. This is what the call looks like:

if(!'http://localhost'.match('html5.digi.ninja'))

This may not seem like it, but there is a vulnerability in here. The `.match` function will check against regex and the `.` (period) character is not being escaped properly. The dot matches a single character, without caring what that character is. The only exception are line break characters.

Therefore, we can use the following, and the regex will match:

As you can see, we can place any character where the `.` (period) used to be in order to get a match. The `.match()` also will not check if the regex is starting or ending with that regex meaning we can also put the regex check as a subdomain of our own website.

Step 6

I will edit my `hosts` file (no need to buy a new domain) to be `html5xdigixninja.com`.

Now, when the postMessage is sent to the child `iframe` the origin check will be bypassed.

To see a video view here: https://www.youtube.com/watch?v=6F4SRcUoEgE&ab_channel=Shelled

Shoutout to [DigiNinja](https://twitter.com/digininja) for the awesome lab. You can try it out here: https://html5.digi.ninja/s_parent.html