Bypassing SOP with Iframes - 2

Iframes in SOP-2

In the solution for this challenge, @Strellic_ proposes a similar method to the previous section. Let's check it.

In this challenge the attacker needs to bypass this:

if (e.source == window.calc.contentWindow && e.data.token == window.token) {

If he does, he can send a postmessage with HTML content that is going to be written in the page with innerHTML without sanitation (XSS).

The way to bypass the first check is by making window.calc.contentWindow to undefined and e.source to null:

  • window.calc.contentWindow is actually document.getElementById("calc"). You can clobber document.getElementById with <img name=getElementById /> (note that Sanitizer API -here- is not configured to protect against DOM clobbering attacks in its default state).

    • Therefore, you can clobber document.getElementById("calc") with <img name=getElementById /><div id=calc></div>. Then, window.calc will be undefined.

    • Now, we need e.source to be undefined or null (because == is used instead of ===, null == undefined is True). Getting this is "easy". If you create an iframe and send a postMessage from it and immediately remove the iframe, e.origin is going to be null. Check the following code

let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
window.target = window.open("http://localhost:8080/");
await new Promise(r => setTimeout(r, 2000)); // wait for page to load
iframe.contentWindow.eval(`window.parent.target.postMessage("A", "*")`);
document.body.removeChild(iframe); //e.origin === null

In order to bypass the second check about token is by sending token with value null and making window.token value undefined:

  • Sending token in the postMessage with value null is trivial.

  • window.token in calling the function getCookie which uses document.cookie. Note that any access to document.cookie in null origin pages tigger an error. This will make window.token have undefined value.

The final solution by @terjanq is the following:

Last updated