Se mostrara como analizar malware altamente ofuscado con tecnicas avanzadas como es la implementacion de una maquina virtual para evitar mostrar el codigo real.
El objetivo es descifrar todos y cada uno de los componentes de este malware obteniendo el codigo original antes de pasar por su VM.
Para ello se ha creado distintas herramientas que facilitan esta tarea, veremos como fueron implementandose.
Por ultimo analizaremos el payload final y las tecnicas que utiliza para realizar sus implantes en distintos procesos del sistema, como es el uso de un sistema de archivos virtual (VFS), utilizado para ocultar los distintos componentes.
2. Presentación
• Abel Valero
• Jugador de CTF con el equipo
Amn3s1a.
• Colaborador del Proyecto R2
• Miembro de la lista MLW.RE
• Analista de malware en PandaLabs
abelvl@gmail.com
@sanguinawer
4. Introducción
• Finfisher: Es un software de vigilancia
desarrollado por Gamma International, una
firma internacional con oficinas en
Reino Unido y Alemania, que a su vez forma
parte de Gamma Group, empresa
especializada en monitoreo y vigilancia y que
vende equipo, software y servicios de
entrenamiento.
5. Introducción
• A finales del 2011 aparece una filtración sobre
este software en WikiLeak.
• En septiembre de 2014 WikiLeaks libera los
binarios para Windows.
6. Introducción
• Desde 2014 hasta la actualidad diversos
investigadores han analizado el código que se
publico en wikileaks.
• En algunos eventos privados se habla sobre el
tema en base a los archivos filtrados por
Wikileak.
• En octubre de 2017 aparece un articulo
haciendo de nuevo referencia a finfisher.
7. Introducción
• “BlackOasis APT and new targeted attacks
leveraging zero-day exploit”
• En este articulo hablan por encima sobre la
existencia de una VM utilizada dentro de
finfisher.
• Ademas proporcionan el MD5 del binario que
han analizado.
• MD5: 4a49135d2ecc07085a8b7c5925a36c0a
11. Dropper: Limpiar Ofuscacion
• Para continuar, será necesario “limpiar” el código.
• Observamos que utiliza saltos condicionales con
destinos idénticos.
• Debemos transformar estos saltos condicionales
en incondicionales.
15. Dropper: Limpiar Ofuscación
• Buscamos 2 patrones:
– “Saltos largos”: 0f 8x xx xx xx xx 0f 8x xx xx xx xx
– “Saltos cortos”: 7x xx 7x xx
• Tenemos que localizarlos todos y cambiarlos a
incondicionales.
18. Dropper: Continua el análisis
• Analizando el código se observan funciones algo
extrañas.
19. • Observamos el inicio de una
función.
• Su código no tiene mas sentido
que llamar a 0x401950 una vez
introduce ciertos valores en la
pila.
• Da la impresión de que el
código original haya sido
“arrancado”.
• Comportamiento clásico de
protectores que “ripean”
funciones.
Dropper: Identificando la VM
20. • Existen múltiples llamadas a 0x401950
• Es la función encargada de inicializar la VM.
– Aloja memoria
– Descifra el algoritmo de descifrado del pcode
– Descifra el pcode
– Inicializa el contexto de la VM
– Obtiene el contexto de ejecución para el hilo
actual.
– VM_DISPATCHER con 0x21 “operaciones”
Dropper: Identificando la VM
21. • Hace apenas un mes se publicaron 2 artículos
sobre este tema
• Rolf Rolles
– http://www.msreverseengineering.com/blog/2018/1/31/finspy-vm-
part-2-vm-analysis-and-bytecode-disassembly
• ESET
– https://www.welivesecurity.com/wp-content/uploads/2018/01/WP-
FinFisher.pdf
• Análisis de VMs (baleful Amn3s1a_team)
– https://github.com/radare/radare2-extras/tree/master/baleful
Dropper: Identificando la VM
23. • Peetool+, es una herramienta creada
únicamente para reconstruir los binarios
ofuscados con la VM de finspy.
• Motivación:
– No depender de otras utilidades (radare2, ida)
– Soportar las distintas configuraciones de las VMs
– Obtener un binario lo mas parecido al original.
– Intentar olvidar que estoy en mi cuarta década.
TOT: Peetool+
24. • Necesidades:
– Parser PE (propio)
– Desensamblador (propio)
– Engine de búsquedas (propio)
– Ensamblador (keystone)
– Rutinas aPLib (Joergen Ibsen)
• Directivas
– Simplicidad y que sepa usarlo pasado 3 meses.
TOT: Peetool+
25. • Lista de TODO`s:
– Obtener la configuracion de la VM:
– Tamaño del pcode descomprimido
– Pcode
– Key descifrado
– Obtener tabla de Operaciones
– Emular la tabla de Operaciones (limpiar JCC)
– Interpretar el Pcode
– Obtener funciones virtualizadas
– Reconstruir funciones a código x86/x64
– Aplicar Relocations
TOT: Peetool+
26. • Obtenemos el ImageBase: 0x00400000
• Buscamos Imagebase en la sección .TEXT
– La primera coincidencia es nuestro objetivo.
– Restamos 8 bytes al offset encontrado
98 07 06 00 VM_CONFIG_SIZE_PCODE = 0x00060798
CD C4 00 00 VM_CONFIG_RVA_VMCODE = 0x0000C4CD
00 00 40 00 VM_CONFIG_BASE = 0x00400000
1D 59 AD 2A VM_CONFIG_XOR_KEY = 0x2AAD591D
TOT - PETOOL+: Configuración VM
27. • Obtenemos el ImageBase: 0x00400000
• Buscamos secuencias seguidas que sus 2 primeros
bytes coincidan con los de imagebase. (xx xx 40 00 xx
xx 40 00)
F2 2C 40 00 = 0x00402CF2 opcode0_CALL_IND
BE 2F 40 00 = 0x00402FBE opcode1_JCC
54 30 40 00 = 0x00403054 opcode2_TMP_ADD_REG
C8 30 40 00 = 0x004030C8 opcode3_JCC
33 31 40 00 = 0x00403133 opcode4_JCC
99 31 40 00 = 0x00403199 opcode5_JCC
FB 31 40 00 = 0x004031FB OPCODE6_JUMP
30 34 40 00 = 0x00403430 Opcode7_CALL_DIR
TOT - PETOOL+: Tabla de Opcodes
28. • Identificar cada opcode de la tabla.
– Necesario limpiar ofuscación.
• Desensamblar cada entrada de la tabla con
este algoritmo:
– NOPs son ignorados
– JMP de tipo disp8/16/32 establecen la siguiente
instrucción a desensamblar.
– Cualquier otro tipo de JMP finaliza el
desensamblado.
– Cualquier otra instrucción se imprime.
– JCC se guarda su destino y se continua
TOT + PETOOL+: Emular Opcodes
29. • Generamos un sig con el resultado.
TOT - PETOOL+: Emular Opcodes
30. • Utilizando el sig identificamos que es cada
opcode de la tabla.
• Se genera una relación entre la tabla actual y
cada opcode.
• Se utiliza un switch para procesar cada
opcode .
TOT - PETOOL+: Emular Opcodes
31. • En este punto emulamos el dispatcher del
propio código de finspy:
– Deciframos cada instrucción con la KEY
– Cada instrucción ocupa 6 DWORDs (24 bytes)
– Al primer DWORD no se le aplica XOR
– Comprobamos si tiene RELOCATION:
– Si es necesario se suma la base a la posición indicada
– Llamamos a nuestra función para obtener una
representación del código VM.
TOT - PETOOL+: Interpretar Pcode
33. • Sera necesario encontrar todas las funciones
que han sido emuladas:
• Buscamos los siguientes patrones de bytes y
guardamos el destino del salto final.
– 68 xx xx xx xx xx xx xx xx 0f 84 xx xx xx xx
– 68 xx xx xx xx e9 xx xx xx xx
TOT - PETOOL+: Obtener Funciones
34. • Con los saltos guardados nos quedamos con
los que mas veces llamen a la misma función
y determinamos que esta es la VMENTRY.
• Realizamos la misma búsqueda filtrando por
llamadas a VMENTRY.
• Guardamos el valor del PUSH y la dirección
donde se encuentra.
TOT - PETOOL+: Obtener Funciones
35. 1. Recorremos la lista de llamadas a la vm
– Si la instrucción tiene reloc lo guardamos.
a) Procesamos la instruccion PCODE actual.
b) Si la instrucción actual tiene un salto miramos si su destino lo hemos
procesado.(seteamos variable booleana)
c) Guardamos el vm_eip como procesado.
d) Avanzamos a la siguiente instrucción
e) Si el vm_eip actual esta en la lista de llamadas a la VM salimos.
f) Si el vm_eip llega al final del buffer salimos.
g) Repetimos el paso 1 hasta que salgamos por c.
TOT - PETOOL+: Reconstruir Funciones
36. 2. Comprobamos si todo el código a podido resolverse
– En el paso “a” se determina si tenemos resueltos todos los
saltos que se poducen en la función procesada.
– Si se ha obtenido todo el código lo guardamos en un
buffer
3. Repetimos el paso 1 hasta obtener todas las
llamadas.
4. Determinamos el tamaño de cada función.
5. Repetimos el proceso pero esta vez a la hora de
generar el código asm indicaremos la base de la
función.
6. Obtenemos un código PERFECTO y funcional.
TOT - PETOOL+: Reconstruir Funciones
38. TOT - PETOOL+: Aplicar Relocs
• Aplicamos la relación entre las instrucciones
que tienen reloc y el código asm generado
●
Buscamos en la lista de que se genero en el paso 1.
●
Obtenemos donde se encuentra ese código en la
interpretación x86.
●
Generamos una entrada en lista de relocations.
42. Analisis Codigo “real”: Dropper
• El código esta reconstruido, y no se aprecia
ninguna ofuscación en el.
• La función principal de este dropper es
descifrar la siguiente fase de infección e
inyectarla en Explorer.exe.
• Incorpora varias técnicas de detección de
depuradores
– SetupApi (red)
– Parche DbgBreakPoint
– NtSetInformationThread, NtQueryInformationProcess,
NtSetInformationProcess
– NtQueryInformationProcess (ProcessDebugPort, ProcessTime)
43. Analisis Codigo “real”: Dropper
• Detecta si el sistema es x32 o x64
• Obtiene el payload correspondiente:
– X32: Resources 1-4
– X64: Resources 5-8
• Descifra el payload
– Algoritmo: Rc4
– Key x32: a8 91 01 b0 (timedatestamp*2)
– Key x64: f8 b4 04 10 (timedatestamp*5)
44. Analisis Codigo “real”: Dropper
• Inyecta el Payload en EXPLORER
– Obtiene address user32 en el proceso actual.
– Lee la dirección obtenida del proceso explorer.
– En el buffer leído parchea la 3ª funcion de user32
– Inyecta el payload en el proceso explorer.
– Inyecta cargador dll en explorer (ofuscado jcc).
– Suspende explorer y desmapea la dirección de
user32.dll
– Mapea el buffer parcheado de user32.dll.
– Reanuda el proceso.
46. Payload x32
• Desciframos o dumpeamos de memoria el
payload.
• Obtenemos una DLL que tiene las imports
destruidas:
• No contine VM ni código ofuscado.
47. Payload x32: Reconstruir IAT
• Para destruir las imports lo que han hecho es
cambiar el FirstThunk de cada entrada de la
IAT por el valor CRC del string.
• Normalmente es un VA que apunta a un
string con el nombre de la función a importar
• Sabiendo la rutina CRC utilizada podemos
reconstruir la IAT
48. Payload x32: TOT imports
• La rutina de CRC utilizada es la siguiente:
49. Payload x32: TOT imports
• Imports TODO´s;
– Recorrer la IAT del payload
– Obtener el nombre de la dll.
– Hacer LoadLibrary de la dll.
– Obtener el valor del FirstThunk (CRC )
– Recorrer IAT dll cargada por loadlibrary
– Calcular el CRC de cada RVA
– Comparar con el crc que buscamos
– Copiar el nombre de la API
– Ajustar el RVA para que apunte al nombre
50. Payload x32: IAT OK
• Una vez reconstruida podemos ver las
importaciones correctamente:
52. Payload x32: Config files
.text
.data
.rsrc
BIN
101 - Driver y/o DLL
103 - crtcli.dll
Icons
1 - Configuracion
Seccion sin nombre
Virtual File System
• Descifra el rsrc Icons (xor)
– Nombre directorio (hidservice)
– Nombre ficheros
– Keys cifrado/descifrado
• Escribe en disco y se cifra con
rc4 (xxxxxx.cab) .
– Key: nombre dir (hidservice)
• Descifra la sección sin
nombre(xor)
– Se obtiene el nombre a crear del
archivo config descifrado.(Offset
0x628)
• Se escribe en disco y se cifra
con rc4 (setup.cab)
– Key de 256 bytes obtenida del
fichero config. (0ffset 0x1050)
53. Payload x32: Infeccion/Persistencia
• Windows 7 Admin (permite drivers sin firmar)
– Se extrae y decodifica el rsrc 101 usa un algoritmo Xor.
– Se escribe en disco con el nombre indicado en el Offset 0x10 del archivo
de config. (hidservice.sys)
– Se instala el servicio en el sistema.
• Windows 7 User
– Se extrae y decodifica rsrc 101 (hidservice.sys)
– Se busca dentro del hidservice.sys por la marca 0xffffffffffffffff, descifra,
mapea y obtiene el resource 101 de driverX.sys .
– Escribe el resource leído en disco (msvcr90.dll)
– Se extrae el rsrc 103 (crtcli.dll) y se escribe a disco
– Crea clave registro:
– KEY: HKCUSoftwareMicrosoftWindowsCurrentVersionrun
– Value: rundll32.exe “c:Users??appdatalocalHidServicecrtcli.dll”,Control_RunDLL
– Descifra y mapea msvcr90.dll dentro de explorer.exe
54. Payload x32: Resumen
• Archivos Configuracion
– xxxxx.cab (GetTickCount)
– Setup.cab
• Archivos Binarios
– Crtcli.dll
– HidService.sys msvcr90.dll
• Objetivo
– Crear archivos de configuración
– Crear persistencia adecuada
– Mapear msvcr90.dll dentro de
explorer.exe
.text
.data
.rsrc
BIN
101 - HidService/msvcr90.dll
103 - crtcli.dll
Icons
1 - xxxxxx.cab
Seccion sin nombre
Setup.cab
58. Crtcli.dll
• Objetivo
– Leer de disco y descifrar msvcr90.dll
– Inyectar la dll en explorer
• Tecnica de inyección idéntica a la del dropper
• Incorpora antihook
– Restaura las entradas en apis desde disco
• Ofusca llamadas API
– Mapea las librerías manualmente y crea
trampolines a memoria
62. HidService.sys
• Objetivo
– Descifrar otro driver que contiene una dll en su
resource.
– Cargar y ejecutar el driverX.
• No es necesario ejecutar nada de este driver
• Payload32 sabe descifrarlo y mapearlo
• Usamos el mismo método y obtenemos
driverx.sys
66. DriverX.sys
• Objetivo
– Descifrar la dll (msvcr90.dll) en su resource
– Inyectar la dll desde r0 en winlogon.exe
• No es necesario ejecutar nada de este driver
• El Payload32 sabe obtener la dll del resource
• Usamos el mismo método y obtenemos
mscvr90.dll
70. Msvcr90.dll
• Objetivo
– Descifrar FINFISHER.DLL
– Mapear finfisher.dll en el proceso actual.
– Proteger la dll mapeada
• Resource
– Contine Finfisher.dll
– Cifrada con XOR
– Comprimida con APLIB
71. Msvcr90.dll: Protecciones
• Hook en KiUserExceptionDispatcher
– Cualquier excepción dentro de explorer sera
tratada por el código implantado.
• Durante la resolución de finfisher.dll se
interceptan 3 apis
– VirtualProtect
– ResetDCW
– DeleteDC
• En el análisis de Finfisher.dll habrá que tener
en cuenta estos hooks
72. Msvcr90.dll: Hook VirtualProtect
• Realiza un VirtualQuery
• Comprueba Tipo
– MEMORY_BASIC_INFORMATION.Type == MEM_IMAGE
• Si coincide llama a NtProtectVirtualMemory
dejando que se establezcan los permisos.
• Si no retorna 1
• Llamada a VirtualProtect en finfisher.dll
funcionara normalmente mientras la
memoria sea de tipo MEM_IMAGE
73. Msvcr90.dll: Hook DeleteDC
• Este hook al invocarse establece otros hooks:
– CreateThread
– TerminateThread
– ExitThread
• Se le pasa como parámetro puntero a código
• Crea hilo suspendido con el codigo
• Cifra el código
• Establece la protección del código a
PAGE_NOACCESS
74. Msvcr90.dll: Hook ResetDCW
• Este hook al invocarse desactiva y libera toda
la memoria que se le indique.
• Es el encargado de “finalizar” la proteccion
75. Msvcr90.dll: Resumen HOOKS
• VirtualProtect se hookea para que no moleste.
• DeleteDC se encarga de proteger payloads en
memoria, cifrándolos y eliminando el permiso
de lectura a la pagina de memoria.
• ResetDCW se encarga de revertir y liberar la
memoria/payload protegidos.
• KiUserExceptionDispatcher será el encargado
de manejar las excepciones que se produzcan
y restaurar los permisos originales
79. Finfisher.dll
• Todo el código es completame legible
• Su proteccion reside en todas las fases anteriores.
• Hay que tener en cuenta los hooks que se establecen.
• Consta de 2 fases
– Dllmain:
– RunDll:
• Resource con 3 entradas
• !!! Sin VM ni ningún tipo de ofuscación!!!!
80. Finfisher.dll: DllMain
• Dllmain:
– Inicialización leyendo carpeta hidservice
– Hook de varia apis para controlar los acceso a disco
• CreateFileW
• DeleteFileW
• GetCurrentDirectoryW
• CopyFileW
• …
– Hook a CreateProceesW
• Todos los procesos son creados suspendidos
– Hook a CreateRemoteThread
• Todos los hilos son creados suspendidos
• Resource con 3 entradas
• !!! Sin VM ni ningún tipo de ofuscación!!!!
81. Finfisher.dll: DllMain
• Los hooks a las apis de acceso a disco se
establecen para poder utilizar un sistema de
archivos virtuales cifrado
• El resto de hooks es para que el sistema de
protección que brinda msvcr90.dll funcione
correctamente.
82. Finfisher.dll: RunDll
• Ejecuta finfisher y comienza sus tareas de
espionaje.
• Extrae del resource los componentes
principales
– Res 101: Proxy de comunicaciones
– Inyectado en explorer.exe y rshell.exe
– Res 103: Networkmap.arj
– Inyectado en todos los procesos
• Setup.cab en la capeta hidservice es el
contenedor para el VFS
83. Finfisher.dll: VFS
• Dentro existen varios archivos
– Payloads que se inyectaran en procesos
específicos
– Configuraciones, C&C, procesos a interceptar.
• Desde dentro del propio finfisher es trivial
dumpear setup.cab completamente
decodificado.
85. Finfisher.dll: VFS
• Los ficheros con sufijo 0 son configuraciones:
– fe_0
– 16_0
– 7f_0
– aa_0
• Los ficheros con sufijo 2 son payloads que se
inyectaran utilizando el sistema de protección.
– 16_2
– 7f_2
87. Finfisher.dll: 7f_0
• Este archivo es una especie de json compilado
agrupa varias categorías:
– TA_mil10f0
– 41.255.166.169
– 191.101.251.200
– 185.82.217.219
– Monitoring
– taskmgr
– Windows Task Manager
– AccessEnum
– …
limpio.txt
88. Finfisher.dll: Esto se acaba
• Esto es todo lo que me da tiempo a contaros
• Podria seguir un rato mas mostrando los
payloads de finfisher.
• El payload para x64 es casi idéntico
– Simplemente han reimplementado la VM para
que soporte instrucciones de x64
– Adaptar petool+ a peetool64+ es trivial
– Recuperar el código es incluso mas fácil.
89. Finfisher.dll: Esto se acaba
• Hemos visto como los chicos de Gamma han
implementado muchísimas defensas para
ocultar la dll final.
• Desgraciadamente no han sido suficientes y
aunque muy bien implementada la VM en una
escala de 1 a 10 estaría en 4