Bypassing SOP with Iframes - part 1

Iframes in SOP - part 1

In this challengearrow-up-right created by NDevTKarrow-up-right and Terjanqarrow-up-right you need you need to exploit a XSS in the coded

const identifier = '4a600cd2d4f9aa1cfb5aa786';
onmessage = e => {
  const data = e.data;
  if (e.origin !== window.origin && data.identifier !== identifier) return;
  if (data.type === 'render') {
    renderContainer.innerHTML = data.body;
  }
}

The main problem is that the main pagearrow-up-right uses DomPurify to send the data.body, so in order to send your own html data to that code you need to bypass e.origin !== window.origin.

Let's see the solution they propose.

SOP bypass 1 (e.origin === null)

When //example.org is embedded into a sandboxed iframe, then the page's origin will be null, i.e. window.origin === null. So just by embedding the iframe via <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php"> we could force the null origin.

If the page was embeddable you could bypass that protection that way (cookies might also need to be set to SameSite=None).

SOP bypass 2 (window.origin === null)

The lesser known fact is that when the sandbox value allow-popups is set then the opened popup will inherit all the sandboxed attributes unless allow-popups-to-escape-sandbox is set. So, opening a popup from a null origin will make window.origin inside the popup also null.

Challenge Solution

Therefore, for this challenge, one could create an iframe, open a popup to the page with the vulnerable XSS code handler (/iframe.php), as window.origin === e.origin because both are null it's possible to send a payload that will exploit the XSS.

That payload will get the identifier and send a XSS it back to the top page (the page that open the popup), which will change location to the vulnerable /iframe.php. Because the identifier is known, it doesn't matter that the condition window.origin === e.origin is not satisfied (remember, the origin is the popup from the iframe which has origin null) because data.identifier === identifier. Then, the XSS will trigger again, this time in the correct origin.

Last updated