DESMANTELANDO WEBEX
Análisis de datos en bruto y reconstrucción del formato.
¿Quien soy?
- Abel Valero
- Mr.Snow/SkUaTeR
- @sanguinawer
- @amn3s1a_team
- Colaborador del proyecto r2
- +20 años analizando binarios
Plataforma
Plataforma
- Soporta reuniones de varias personas.
- Comparte video, audio, archivos, pizarras ...
- Incorpora sistema de mensajería online (chat).
- Permite al creador de la reunión guardar el contenido para posteriormente compartirla.
- Permite reproducir las sesiones en streaming a través de un reproductor propio.
Reproductor
- Se encarga de reproducir las sesiones en modo streaming.
- Puede realizar la reproducción sin necesidad de recibir un flujo “streameado“.
- Se ejecuta mediante un plug-in en el navegador si se recibe en modo streaming.
Manos a lo obra
Recuperación de archivos
- Asumo que en algún momento se han tenido que generar archivos para alimentar de datos al reproductor.
- Deberían localizarse en el directorio de temporales de internet.
- Usamos alguna herramienta forense para recuperar los datos.
- http://www.digital-forensic.org/
Recuperación de archivos
Gracias a un archivo con extensión “.wav” pude determinar que esta era mi conferencia
Recuperación de archivos
- Durante el proceso de recuperación, encontré unos sectores que contenían información muy parecida a la alojada en los archivo recuperados.
- Gracias a “Radare2” pude analizar un volcado (“raw dump”) de mi disco duro.
- Realizando búsquedas binarias pude recuperar la mayor parte del contenido de este archivo desconocido.
Análisis en bruto
Análisis en bruto- Asumimos que no podemos confiar en los datos recuperados,
por lo menos no a partir de la mitad del flujo de datos.
- Verificamos que existe la estructura de un archivo “wav” entre los datos recuperados.
- Observamos algo parecido a una cabecera en el inicio de los datos recuperados.
- En los archivos recuperados no tenemos nada parecido a esta cabecera
Análisis en bruto
Marca “WAV” dentro de los datos en bruto
Análisis en bruto
Cabecera no identificada. Se puede intuir el alineado de ciertos datos debe ser a 32
Análisis en brutoSe ha recuperado sobre los 5.001.891 bytes (4C52A3 Hex)
Mostrando un volcado en modo 32bits localizamos este valor en el offset 8
Análisis en brutoVisualizando en 32bits se puede ver de forma mas clara los valores.
E incluso distinguir lo que podrían ser: Identificadores, offsets ….
.... y tamaños:
Análisis en bruto
Desplazandonos a uno de estos posibles offsets (0x378) vemos su contenido:
Este contenido se puede relacionar con alguno de los archivos recuperados.
Repitiendo el proceso podremos obtener la estructura de lo que sin duda es la cabecera cuya función es describir el tipo de medios, alojados en este contenedor desconocido.
Recopilación de datos obtenidos
Recopilación de datos obtenidos
00-03= MAGIC 01 00 02 00 DWORD 4-bytes (0)
04-07= desconocido DWORD 4-bytes (4)
08-0b= Tamaño del contenedor DWORD 4-bytes (8)
0c-0f= NULL DWORD 4-bytes (12)
10-13= Numero secciones DWORD 4-bytes (16)
14-17= NULL DWORD 4-bytes (20)
Cabecera
Recopilación de datos obtenidos
struct UNKNOW_HEADER {
public UInt32 e_magic;
public UInt32 e_unknow;
public UInt32 e_filesize;
public UInt32 e_reserved0;
public UInt32 e_nsections;
public UInt32 e_reserved1;
}
Cabecera en C#
Recopilación de datos obtenidos
ARRAY[0 to Numero Secciones]
18-1b = ID Tipo Bloque DWORD 4-bytes
1c-1f = Indice Bloque * DWORD 4-Bytes
20-23 = Tamaño Bloque DWORD 4-bytes
24-27 = NULL DWORD 4-bytes
28-2b = Offset Bloque en el archivo DWORD 4-bytes
2c-2f = null DWORD 4-bytes
30-33 = null DWORD 4-bytes
34-37 = null DWORD 4-bytes
* El indice de bloque se usa cuando hay mas de un bloque del mismo tipo, en ese caso se incrementa en 1 por cada bloque.
Secciones (Items)
Recopilación de datos obtenidos
struct UNKNOW_ITEMS {
public UInt32 e_id;
public UInt32 e_indice;
public UInt32 e_len;
public UInt32 e_reserved0;
public UInt32 e_offset;
public UInt32 e_reserved1;
public UInt32 e_reserved2;
public UInt32 e_reserved3;
}
Secciones (Items)en C#
Recopilación de datos obtenidos
Id Secciones (Items)IDS Tipo Archivo/Extension
70100 chat "_1_.std"
70103 file "_10_.std"
70112 conf ".conf"
7010c video "_4_.dat"
7010d video idx "_4_.idx"
70105 sonido "_5_.wav"
70114 finV "_6_.dat"
70115 quick/desc "_6_.idx"
7010A "_6_.cad"
7010B "_6_.cai"
70110 backup "_21_.dat"
70111 base64 "_21_.idx"
Recopilación de datos obtenidos
enum tipoSegmento {
chat = 0x70100, // "_1_.std"
file = 0x70103, // "_10_.std"
cfg = 0x70112, // ".conf"
video = 0x7010c, // "_4_.dat"
video_idx = 0x7010d, // "_4_.idx"
snd = 0x70105, // "_5_.wav"
mmfin = 0x70114, // "_6_.dat"
mmfin_idx = 0x70115, // "_6_.idx"
mmfin_cad = 0x7010A, // "_6_.cad"
mmfin_cai = 0x7010B, // "_6_.cai"
backup = 0x70110, // "_21_.dat"
backup_idx =0x70111 // "_21_.idx"
};
Id Secciones (Items) en C#
Reconstrucción
Reconstrucción- Después de haber obtenido toda la información, podemos
“juntar” todos los archivos en un contenedor.
- Con la las estructuras obtenidas, generamos cada una de las secciones (items) de la cabecera y hacemos que apunte al contenido correspondiente dentro del archivo contenedor.
- Todo el proceso es sencillo de implementar por lo tanto, lo mejor sera crear una utilidad que se encargue de hacer todo el trabajo.
Reconstrucción1) Ordenamos los archivos obtenidos. (El orden es el mismo
que el de enum tipoSegmento)
2) Obtenemos el tamaño de cada archivo.
3) Creamos un buffer de memoria.
4) Añadimos la estructura struct UNKNOW_HEADER.
5) Inicializamos el campo public UInt32 e_magic a 0x00020001.
6) Inicializamos el campo public UInt32 e_nsections con el numero de archivos obtenidos multiplicado por 2. (Estas secciones de más serán inicializadas a 0)
Reconstrucción7) Añadimos una entrada de la estructura UNKNOW_ITEMS por
cada archivo y rellenamos los campos:public UInt32 e_id;
public UInt32 e_indice;
public UInt32 e_len;
• e_id Contendrá el tipo de sección que podemos relacionar mediante la extensión del archivo y enum tipoSegmento.
• e_indice Siempre vale 0 salvo si existe mas de una sección del mismo tipo en este caso se va incrementado su valor.
• e_len Lo inicializamos al tamaño del archivo/sección.
Reconstrucción8) Alineamos a 4 bytes e insertamos el contenido del primer
archivo.
9) Actualizamos el campo e_offset correspondiente, indicando la dirección donde hemos insertado este primer bloque de datos.
10) Repetimos los pasos 8 y 9 con cada archivo.
11) Calculamos el tamaño total de todos los archivos insertados + alineaciones + la cabecera y actualizamos el campo e_filesize de la struct UNKNOW_HEADER, con el tamaño calculado.
12) Guardamos el buffer.
PoC
Prueba de concepto
- Usamos los archivos obtenidos.
- Usamos la utilidad indicándole dónde se encuentran los archivos recuperados.
- Ejecutamos el reproductor con nuestro archivo generado.
- Cruzamos los dedos
Conclusión final: Estos chicos tienen un gran agujero ....