Volatility VS Citadel 1.3.4.5
Como analista forense y de malware siempre he sido un gran fan de Volatility, la ya archiconocida herramienta de análisis de memoria escrita en Python que sigue creciendo día a día. Por ese motivo, desde que hace algo más de un año vi el artículo de Michael Ligh en su blog sobre la extracción de las claves de cifrado de ZeuS siempre había querido probar eso mismo con otras familias de malware.
En este caso he elegido Citadel, que es una de las variantes de ZeuS que más guerra están dando desde la filtración del código fuente del mismo. En concreto la versión 1.3.4.5 que, aún no siendo la última, nos servirá de base para las siguientes versiones (Aunque se rumorea que la 1.3.5.1 podría ser la última que veamos) u otras familias.
Cuando juntamos Volatility con Yara, la potencia disponible para el procesamiento automático de malware se multiplica. En ambas cosas se basa zeusscan2, uno de los plugins resultantes del artículo comentado anteriormente. El mismo hace uso de reglas Yara sobre la memoria de una máquina infectada para detectar y acceder a las zonas de memoria susceptibles de contener la información que nos interesa extraer del binario. Para ello es necesario un exhaustivo análisis previo sobre la familia a “automatizar”, que en este caso, al tratarse de una variante de la familia ZeuS de sobra conocida y documentada, el trabajo se limitará a detectar las diferencias existentes con la misma.
De entrada sabemos que ZeuS 2.X contiene la siguiente información embebida en el binario:
- URL de descarga inicial del fichero de configuración
- Clave RC4 usada para descifrar el fichero de configuración
- Información sobre la localización del binario y la configuración en la máquina infectada
Los dos primeros datos se encuentran en una zona del binario codificada mediante XOR con los bytes contenidos al comienzo de la última sección del fichero PE, mientras que la última es una zona cifrada mediante la clave RC4 con una estructura fija (En adelante nos referiremos a ello como el “objeto mágico”, para seguir la convención usada en el plugin para Volatility de ZeuS).
Nota: En el caso de ZeuS existe una segunda clave RC4 contenida en la última estructura comentada, pero dado que Citadel carece de ella, no es relevante para el objetivo del artículo.
De esta forma el flujo de extracción y procesamiento de los datos que buscamos sería algo como:
- Localización de la configuración embebida
- Decodificación de la misma mediante un XOR con los bytes situados al comienzo de la última sección del fichero PE
- Extracción de la URL de descarga de la configuración y la clave RC4
- Localización y decodificación del “objeto mágico”
- Extracción de los datos restantes
Ahora que sabemos la base sobre la que se asienta Citadel, podemos estudiar las diferencias para adaptar el plugin a la nueva familia. Las similitudes (a nivel de binario al menos) son más que las diferencias, así que una vez entendido lo anterior, los cambios no revisten demasiada complicación.
La principal diferencia viene marcada por el cifrado usado en los ficheros de configuración descargados, que pasa de RC4 a AES, pero para el “objeto mágico” se mantiene RC4. Dicha clave AES no está contenida en el binario como tal, sino que es calculada en tiempo de ejecución de la siguiente forma:
RC4(md5(BO_LOGIN_KEY)) |
La BO_LOGIN_KEY o binary key, se trata de una clave de 16 bytes en hexadecimal que sí está contenida en el binario y que además de para el cálculo de la clave AES se usa para la comunicación con su panel de control, por lo que, a la localización de la configuración embebida y el “objeto mágico”, hemos de añadir la de dicha clave “hardcodeada”.
Al flujo anterior habría que añadirle por otro lado:
- Localización de la BO_LOGIN_KEY
- Cálculo de la clave AES
Con todo esto, elegimos el siguiente código desensamblado para generar las nuevas reglas Yara que nos ayuden a localizar las variables comentadas en memoria:
8BEC MOV EBP,ESP 83EC 0C SUB ESP,0C 8A82 00010000 MOV AL,BYTE PTR DS:[EDX+100] 8845 FE MOV BYTE PTR SS:[EBP-2],AL 8A82 01010000 MOV AL,BYTE PTR DS:[EDX+101] 8845 FD MOV BYTE PTR SS:[EBP-3],AL 8A82 02010000 MOV AL,BYTE PTR DS:[EDX+102] B9 801A1300 MOV ECX,131A80 ; BO_LOGIN_KEY 8845 FF MOV BYTE PTR SS:[EBP-1],AL E8 BEF2FFFF CALL 0015BC16 ——————————————————————————— 56 PUSH ESI BA 54050000 MOV EDX,554 ; Embedded configuration length 52 PUSH EDX 68 602A4000 PUSH pyko.00402A60 ; Embedded configuration 50 PUSH EAX E8 47E30100 CALL pyko.004290C1 8B0D B4394300 MOV ECX,DWORD PTR DS:[4339B4] 030D 943D4300 ADD ECX,DWORD PTR DS:[433D94] 8BF2 MOV ESI,EDX 2BC8 SUB ECX,EAX ——————————————————————————— 68 03010000 PUSH 103 8D85 10FBFFFF LEA EAX,[LOCAL.316] 50 PUSH EAX 8D85 FCFEFFFF LEA EAX,[LOCAL.65] 50 PUSH EAX E8 B4E20100 CALL pyko.004290C1 B8 1C010000 MOV EAX,11C 50 PUSH EAX 68 283C4300 PUSH pyko.00433C28 ; Magic object |
Una vez que llegamos al punto del flujo de procesamiento en el que se decodifica el “objeto mágico” nos encontramos con una estructura con un aspecto similar al siguiente:
Este objeto, al igual que pasaba con ZeuS 2.X, tiene una longitud fija en la mayoría de los casos y una estructura como la que sigue:
{‘_ZEUS_MAGIC’ : [ 0x11C, { 'struct_size' : [ 0x0, ['unsigned int']], \ ‘guid’ : [ 0x4, ['array', 0x30, ['unsigned short']]], \ ‘guid2′ : [ 0x7C, ['array', 0x10, ['unsigned char']]], \ ‘exefile’ : [ 0x9C, ['array', 0x14, ['unsigned char']]], \ ‘keyname’ : [ 0xEC, ['array', 0xA, ['unsigned char']]], \ ‘value1′ : [ 0xF6, ['array', 0xA, ['unsigned char']]], \ ‘value2′ : [ 0x100, ['array', 0xA, ['unsigned char']]], \ ‘value3′ : [ 0x10A, ['array', 0xA, ['unsigned char']]], \ ‘guid_xor_key’ : [ 0x114, ['unsigned int']], \ ‘xorkey’ : [ 0x118, ['unsigned int']], \ }]} |
Por lo tanto ya disponemos de todo lo que buscábamos:
Espero que este ejemplo ayude a ver un poco más claramente las posibilidades que nos ofrecen Yara y Volatility para el análisis y automatización de malware cuando trabajan en conjunto.
El plugin para la versión 1.3.4.5 lo podéis encontrar aquí. Michael Ligh lo ha integrado, además, con las versiones del plugin para ZeuS 1 y 2.X, por lo que en adelante estará disponible también en la rama principal de Volatility, aunque no activado por defecto; para su uso habrá que lanzar Volatility de la siguiente forma:
$ python vol.py –plugins=contrib/plugins/malware citadelscan1345 -f …. |
En cuanto a la versión 1.3.5.1, el proceso a seguir sería similar excepto porque habría que localizar una nueva clave “hardcodeada” y tener en cuenta que el tamaño y estructura del “objeto mágico” cambia en cada muestra.
Feliz análisis!