Fakes App
Fakes App
Fakes App
7 de agosto de 2018
Investigación Por: Dikla Barda, Roman Zaikin y Oded Vanunu
A partir de principios de 2018, la aplicación de mensajería propiedad de Facebook, WhatsApp, tiene más de 1.500 millones de
usuarios con más de mil millones de grupos y 65 mil millones de mensajes enviados todos los días. Con tanta charla, el potencial de
estafas en línea, rumores y noticias falsas es enorme. Entonces, no ayuda si los actores de amenazas tienen un arma adicional en su
arsenal para aprovechar la plataforma con sus intenciones maliciosas.
Sin embargo, Check Point Research recientemente reveló nuevas vulnerabilidades en la popular aplicación de mensajería que podría
permitir a los actores amenazar interceptar y manipular los mensajes enviados tanto en conversaciones privadas como grupales, dando
a los atacantes un inmenso poder para crear y difundir desinformación de fuentes aparentemente confiables.
Nuestro equipo observó tres posibles métodos de ataque que explotan esta vulnerabilidad, todos los cuales implican tácticas de
ingeniería social para engañar a los usuarios finales. Un actor de amenaza puede:
1. Use la función 'citar' en una conversación grupal para cambiar la identidad del remitente, incluso si esa persona no es
miembro del grupo.
2. Altere el texto de la respuesta de otra persona, esencialmente poniéndole palabras en la boca.
3. Envíe un mensaje privado a otro participante del grupo que esté disfrazado como un mensaje público para todos, de modo
que cuando la persona objetivo responda, estará visible para todos los participantes de la conversación.
Tras el proceso de divulgación responsable, Check Point Research informó a WhatsApp de sus hallazgos. Desde la perspectiva de
Check Point Research, creemos que estas vulnerabilidades son de suma importancia y requieren atención.
Análisis técnico
Como es bien sabido, WhatsApp encripta cada mensaje, imagen, llamada, video o cualquier otro tipo de contenido que envíe para que
solo el destinatario pueda verlo. Además, ni siquiera WhatsApp tiene la capacidad de ver esos mensajes.
Estos procesos de cifrado llamaron nuestra atención y decidimos tratar de invertir el algoritmo de WhatsApp para descifrar los
datos. De hecho, después de descifrar la comunicación de WhatsApp encontramos que WhatsApp está usando el " protocolo
protobuf2 " para hacerlo.
Al convertir estos datos de protobuf2 en Json, pudimos ver los parámetros reales que se envían y manipularlos para verificar la
seguridad de WhatsApp.
El resultado de nuestra investigación es una extensión de traje de Burp y 3 métodos de manipulación .
Sin embargo, para comenzar la manipulación, primero tenemos que obtener la clave privada y pública de nuestra sesión y completarla
en nuestra extensión de traje de bursuit.
Si está interesado en una explicación detallada sobre cómo funciona realmente el cifrado entre bastidores, lea el párrafo de
encriptación al final de esta publicación de blog.
Las claves se pueden obtener desde la fase de generación de claves desde WhatsApp Web antes de que se genere el código QR:
Después de tomar estas claves, debemos tomar el parámetro "secreto" que envía el teléfono móvil a la Web de WhatsApp mientras el
usuario escanea el código QR:
Figura 3: La clave secreta de WebSocket
Después de hacer clic en "Conectar", la extensión se conecta al servidor local de la extensión, que realizará todas las tareas requeridas
para la extensión.
Manipulando WhatsApp
Al descifrar la comunicación de WhatsApp, pudimos ver todos los parámetros que realmente se envían entre la versión móvil de
WhatsApp y la versión web. Esto nos permitió manipularlos y comenzar a buscar problemas de seguridad.
Esto nos permitió realizar una variedad de tipos de ataques, que se describen a continuación.
Ataque 1: cambiar la identidad de un remitente en un chat grupal, incluso si no es miembro del grupo
En este ataque, es posible falsificar un mensaje de respuesta para suplantar a otro miembro del grupo e incluso a un miembro del
grupo no existente, por ejemplo, 'Mickey Mouse'.
Para suplantar a alguien del grupo, todo lo que el atacante necesita es capturar el tráfico cifrado:
Una vez que se captura el tráfico, simplemente puede enviarlo a una extensión que luego descifrará el tráfico:
Figura 6: descifrar el mensaje de WhatsApp
utilizando nuestra extensión
Por ejemplo, podemos cambiar la conversación a otra cosa. El mensaje con el contenido " ¡Genial! "Enviado por un miembro de un
grupo, por ejemplo, podría cambiarse por algo más como:" Voy a morir, en un hospital en este momento "y el parámetro del
participante también podría cambiarse a otra persona del grupo:
Figura 7: un mensaje de respuesta falso
Tenga en cuenta que tenemos que cambiar el ID a otra cosa porque ya está enviado y aparece en la base de datos.
Para hacer que todos vean el nuevo mensaje falso, el atacante debe responder al mensaje que falsificó, citando y cambiando ese
mensaje ("Excelente") para que se envíe a todos los integrantes del grupo.
Como puede ver en la siguiente captura de pantalla, creamos un nuevo grupo donde no se enviaron mensajes anteriores, y al usar el
El parámetro 'participante' también puede ser un texto o un número de teléfono de alguien que no está en el grupo, lo que provocaría
que todos en el grupo creyeran que realmente se envió desde este participante.
Por ejemplo:
Figura 9: Cambio del contenido del mensaje
mediante nuestra herramienta de depuración
En este ataque, el atacante puede manipular el chat enviándole un mensaje a él mismo en nombre de la otra persona, como si hubiera
venido de ellos. Al hacerlo, sería posible incriminar a una persona o cerrar un trato fraudulento, por ejemplo.
Para falsificar los mensajes, debemos manipular el parámetro ' fromMe ' en el mensaje, que indica quién envió el mensaje en el chat
personal.
Esta vez capturaremos el mensaje saliente de WhatsApp Web antes de que se envíe a nuestro Burp Suite. Para hacerlo, podemos
poner un punto de corte en la función aesCbcEncrypt y tomar los datos del parámetro 'a':
Tenemos que modificar el parámetro 'a' en nuestro navegador, y el resultado será una notificación automática con el contenido. De
esta manera, incluso es posible falsificar toda la conversación.
Ataque 3: envíe un mensaje privado en un grupo de chat, pero cuando el destinatario responda, todo el grupo lo verá.
En este ataque, es posible enviar un mensaje en un chat grupal que solo verá una persona específica, aunque si responde a este
mensaje, todo el grupo verá su respuesta.
De esta manera, es posible manipular a un determinado miembro del grupo y "tripitarlo" para que revele información al grupo que de
otro modo no querría que ellos supieran.
Encontramos este vector de ataque mientras invertimos la aplicación móvil Android. En esta instancia, encontramos que si el atacante
manipula un mensaje simple en el grupo, como "Somos el equipo", en realidad encontraremos este mensaje en
'/data/data/com.whatsapp/databases/msgstore.db'. base de datos - como se ve a continuación.
Para enviar un mensaje al grupo, pero restringirlo solo a un miembro específico del grupo, tenemos que establecer su número bajo
el parámetro ' remote_resource ' .
mensajes de actualización establecidos key_from_me = 1, data = "¡Todos sabemos lo que has hecho!", donde _id = 2493;
El atacante debe cerrar y volver a abrir su WhatsApp para forzar a la aplicación a enviar el nuevo mensaje. Después de hacerlo, el
resultado será el siguiente:
Si la víctima escribe algo como respuesta, todos en el grupo recibirán su respuesta, pero si responde el mensaje, solo verá el
contenido contestado y todos los demás verán el mensaje original ...
Código fuente: https://github.com/romanzaikin/BurpExtension-WhatsApp-Decryption-CheckPoint
Comencemos con WhatsApp Web. Antes de generar el código QR, WhatsApp Web genera una clave pública y privada que se utiliza
para el cifrado y descifrado.
Figura 23: Clave pública y privada de la conversación
Para descifrar los datos, comenzaremos a crear un código de descifrado. Esto tomará la clave privada de WhatsApp Web en lugar de
los bytes aleatorios porque necesitamos las mismas claves para descifrar los datos:
Luego, después de crear el código QR, luego de escanearlo con un teléfono, podemos enviar la siguiente información a la Web de
Whatsapp a través de un websocket:
Figura 25: La clave secreta de WebSocket
El parámetro más importante aquí es el secreto que luego pasa a setSharedSecret. Esto dividirá el secreto en partes múltiples y
configurará todas las funciones criptográficas que necesitamos para descifrar el tráfico de WhatsApp.
Primero, podemos ver que hay una traducción de String 'e' en Array y algunas divisiones que dividen el secreto en dos partes: 'n', que
son los primeros 32 bytes y 'a', que son los caracteres del 64 ° byte hasta el final de la 't'.
Y si profundizamos en la función '' E.SharedSecret '' , podemos ver que usa dos parámetros, los primeros 32 bytes y la clave
privada de la generación QR:
Figura 27: Obtener el SharedSecret
Después de esto, podemos actualizar nuestro código python y agregar la siguiente línea:
Al sumergirse podemos ver que la función usa la función HKDF. Así que encontramos la función 'pyhkdf' y la usamos en nuestro
código para gastar la clave de la misma manera que lo hizo WhatsApp:
A continuación tenemos la función de validación de hmac que toma los datos gastados como parámetro 'e' y los divide en 3
parámetros:
Figura 29: HmacSha256
Entonces se llamará a la función HmacSha256 con el parámetro 'r' y firmará los datos con el parámetro 's', después de eso 'n'
recibiremos el verificador de hmac que se comparará con 'r', que es un corte de 't' de 32 bytes a 64 bytes, y 't' es nuestro secreto en el
formato de matriz, como se vio anteriormente.
Figura 30: Comprobación de la validez de los mensajes
La última función relacionada con el cifrado en este bloque es 'aesCbcDecrypt' que usa el parámetro 's' que es una concatenación
entre los datos del byte 64 hasta el final de los compartidos expendidos y los datos del byte 64 del secreto, y 'i' que son los primeros
32bytes de gastos compartidos.
El resultado es la clave descifrada que usaremos más tarde. Entonces, si traducimos el código, se verá así:
keysDecrypted = AESDecrypt (shared_expended [: 32], shared_expended [64:] + self.conn_data [ "secret" ] [64:]) Después del
descifrado, tendremos la nueva 't' que es los primeros 32 bytes, que es la clave de cifrado y los siguientes 32 bytes, que es la clave
mac:
Entonces, después de tener el código que puede regenerar todos los parámetros de encriptación necesarios, podemos continuar con el
proceso de descifrado.
Como puede ver, el mensaje se divide en dos partes: la etiqueta y los datos. Usaremos la siguiente función para descifrar el mensaje:
return self.decrypted_seralized_content
Como puede ver, recibimos los datos en formato base64 para copiar los datos Unicode fácilmente, En Burp podemos codificar los
datos a base64 simplemente presionando ctrl + b y pasándolos a la función decrypt_incomping_message. Esta función divide la
etiqueta del contenido y comprueba si nuestra clave puede descifrar los datos comparando el hmac_sha256 (self.conn_data
[" mac_key "], el contenido [32:]) con el contenido [: 32].
Si todo encaja, podemos continuar con el paso de descifrado de AES que utiliza nuestra clave aes y el contenido de 32bytes.
Este contenido contiene primero el IV, que es del tamaño del tamaño del bloque aes, y luego los datos reales:
Para descifrar un mensaje, primero tenemos que entender cómo funciona el protocolo de WhatsApp, así que comenzamos depurando
la función e.decrypt :
Traducimos todo el código a python para representar la misma función que se ve así:
Este código primero lee un byte de la secuencia y lo mueve a char_data. A continuación, intenta leer el tamaño de la lista de la
secuencia entrante mediante la función read_list_size.
Este código usa getToken y pasa nuestro parámetro como una posición en la matriz token:
Figura 37: Función getToken
Este es el primer elemento que WhatsApp envía en la comunicación, luego traducimos todas las funciones en la
función readString y continuamos con la depuración:
Esta función simplemente sigue leyendo más bytes de la secuencia y los analiza a través de la misma lista de símbolos que vimos
antes cuando procesamos el token de "acción", que se verá así:
Entonces, el segundo parámetro que envía WhatsApp es la acción real al messenger donde podemos ver que WhatsApp envió {add:
"replay"} lo que significa que llegó un nuevo mensaje.
Básicamente, continuaremos con el código hasta que lleguemos al final de readNode, que nos dará las tres partes del mensaje que se
envió:
1. alguna ficha
2. algunos atributos de tokens
3. el mensaje protobuf codificado
Entonces, hasta este punto obtuvimos la primera y la segunda parte fácilmente reescribiendo todas las funciones a Python, lo cual es
muy directo.
A continuación tenemos que lidiar con el tercer parámetro que es el protobuf y descifrarlo.
Para obtener el protobuf podemos ver el esquema de protobuf implementado por Whatsapp y simplemente copiarlo en un archivo
.proto limpio que se puede obtener desde aquí:
Figura 40: protobuf
Los índices también se pueden copiar desde el esquema de protobuf de Whatsapp y compilarse en el archivo de protobuf de Python
utilizando:
Entonces podemos traducir el protobuf a json fácilmente mediante el uso de las funciones de python generadas por el protobuf ...
... y el resultado se verá así:
El proceso de cifrado es prácticamente el mismo que el cifrado, pero en el orden opuesto, por lo que esta vez invertiremos
la función writeNode :
Como puede ver esta vez, ya tenemos el token y los atributos del token que tenemos que traducir a su posición en las listas de tokens,
y luego simplemente volver a implementar toda la función de la misma manera que lo hicimos en readNode:
El código es muy directo; primero comprobamos si el nodo que tenemos tiene una longitud de tres. Luego multiplicamos el número
de atributos de token por dos y lo pasamos a writeListStart, que escribirá el inicio del carácter de lista y luego el tamaño de la lista
(lo mismo que vimos en readNode ):
Después de tener la lista de inicio, entraremos en writeString que realiza lo mismo que readString , ya que puede ver "acción"
traducida a diez, que es la posición de "acción" en el índice de tokens, y así sucesivamente:
Figura 45: función writeToken
luego el código entra en writeAttributes que traducirá los atributos y de ahí en writeChildren que traducirá los datos reales.
Figura 46: función writeChildren
De esta forma, creamos los datos, de modo que nuestro código que descifra y encripta los mensajes se verá así:
Para simplificar el proceso de cifrado, cambiamos la función real writeChildren y añadimos otro tipo de instancia para simplificar el
cifrado:
https://github.com/romanzaikin/BurpExtension-WhatsApp-Decryption-CheckPoint