Hola a tod@s!!
Me he encontrado últimamente con artefactos cuyo objetivo es comprometer equipos con artefactos de Havoc (Framework de Post-explotación), salvando las distancias, una alternativa a Cobalt Strike del que tanto hemos hablado.
Veremos este en concreto:
Como podemos observar, varios motores Antivirus lo detectan bien, eso sí 10 de 60 detecciones, pocas en mi opinión, a medida que pase el tiempo esto aumentará según se vaya reanalizando.
Si lo editamos veremos que no es un EXE o una DLL, según nos decía Virus Total, se trata de un fichero GZIP:
Este tipo de artefactos, no son directamente ejecutados, sino que son utilizados por un Downloader, descarga, trata y ejecuta.
Si prestamos atención al fichero, podemos ver que hay un magic number familiar MZ dentro del mismo, lo extraemos, abrimos un editor hexadecimal y eliminamos todo hasta ese MZ.
Y ya tenemos una DLL que podemos analizar, sería el implante DLL “Demon”, en adelante.
Lo primero que podemos hacer es echarle un vistazo a las cadenas o strings:
Vemos funciones de API como "SeImpersonatePrivilege" y "SeDebugPrivilege," que están relacionadas con los privilegios de seguridad en el sistema operativo Windows. Estos privilegios son utilizados para permitir o restringir ciertas operaciones críticas y de seguridad en el sistema.
Vemos referencias a Winlogon y kerberos, un user-agent, lo que parece un dominio y un par de rutas de la aplicación bloc de notas (32 y 64 bits).
Algo interesante es que aparece el nombre de una DLL y lo que parece una función:
Lo abrimos con PE Bear y vemos lo siguiente, el nombre que se le puso a esa DLL y una función. Exports llamada Start, como veíamos en la anterior captura:
Normalmente, suelen venir acompañadas de multitud de funciones Imports, pero en este caso, no vemos ninguna.
¿Qué está pasando entonces? Si vamos a esa función Start, por ejemplo, podemos comprobar como aparecen valores en hexadecimal, por ej. 0xADD31DF0
Si buscamos este valor en el código de Havoc, vemos la forma que utilizan para ir cargando las diferentes API sin tener que llamarlas directamente:
Según su código fuente, la rutina API Hashing se utiliza para encontrar la ubicación en memoria de varias funciones del Sistema de Programación de Aplicaciones de Windows (NTAPI). Esto se logra examinando la tabla de direcciones de exportación en la DLL "ntdll.dll", específicamente utilizando una función llamada "LdrFunctionAddr". Para empezar, la dirección virtual de la biblioteca "ntdll.dll" se recupera al examinar la información contenida en el PEB o Bloque de Entorno de Proceso.
Y si profundizamos en el código vemos que el algoritmo de hash utilizado para este propósito es una variante modificada del algoritmo "DJB2", y se basa en la constante numérica "5381".
Pero nos falta algo, y es la shellcode que carga todo esto y que no se encuentra en la DLL sino que se encuentra antes de la misma, en el payload inicial. Me refiero a esto que puede verse en el Github del Framework.
Y, efectivamente, podemos ver como se encontraba antes de la DLL:
Continuando con el código fuente, se emplea una técnica de búsqueda del tipo API Hashing para encontrar las direcciones virtuales correspondientes a un módulo específico y a las funciones del Sistema de Programación de Aplicaciones de Windows (NTAPI). En este proceso, se compara un valor hash generado a partir del algoritmo DJB2 con los hashes previamente codificados.
Adicionalmente, se carga en memoria la biblioteca DLL "Demon” embebida, y si es necesario, se calculan las reubicaciones de base. Esto implica ajustar las ubicaciones de memoria asignadas para que coincidan con la biblioteca. En caso de requerirse, las medidas de seguridad de la página de memoria se modifican mediante múltiples llamadas a la función "NtProtectVirtualMemory", que se encarga de establecer los permisos adecuados para proteger la memoria asignada. Este proceso se realiza de forma dinámica para garantizar que las operaciones se realicen de manera segura y eficiente.
Volviendo a la DLL extraída del artefacto inicial, si vamos al EntryPoint, y buceamos en sus funciones podemos ver cómo son utilizados esos hashes de API:
Se obtiene las direcciones virtuales de funciones de módulos como "ntdll.dll" y "kernel32.dll" llamando a la Rutina de Hashing de API que vimos anteriormente.
Recupera los "Syscall stubs" (bloques de código para llamadas al sistema) para diversas funciones del Sistema de Programación de Aplicaciones de Windows (NTAPI).
Se carga varios módulos recorriendo las estructuras de datos del PEB o Entorno de Bloque de Proceso con cadenas de texto recopiladas.
Inicializa objetos de sesión y configuración de la DLL "Demon".
La de la configuración podemos obtener lo que se mencionó al ver las cadenas, en qué aplicación se inyectará el proceso, notepad.exe, el user-agent utilizado, el dominio, aunque no se ve en la captura siguiente, utilizando el método POST.
Vamos a la parte de la detección, encontré un par de reglas Yara para detectar este tipo de artefactos:
rule win_havoc_djb2_hashing_routine_oct_2022
{
//Detects the hashing routine used in Havoc C2
meta:
author = "embee_research @ HuntressLabs"
vendor = "Huntress Research"
date = "2022/10/11"
strings:
// Hashing Routine of DLL
$dll = {b8 05 15 00 00 0f be 11 48 ff c1 84 d2 74 07 6b c0 21 01 d0 eb ef}
//Hashing Routine of Shellcode
$shellcode = {41 80 f8 60 76 04 41 83 e8 20 6b c0 21 45 0f b6 c0 49 ff c1 44 01 c0 eb c4}
condition:
//PE or Shellcode or Shellcode
//Leave as "any of them" for more robust (but compute expensive) searching
(any of them) and (uint16(0) == 0x5a4d or uint16(0) == 0x00e8 or uint16(0) == 0x4856)
}
rule win_havoc_ntdll_hashes_oct_2022
{
//Detects ntdll API hashes used in Havoc C2 Demon payloads
meta:
author = "embee_research @ HuntressLabs"
vendor = "Huntress Research"
date = "2022/10/11"
description = "Detection of havoc demons via hardcoded ntdll api hashes"
strings:
// Syscall Hashes
$nt_hash1 = {53 17 e6 70} //0x70e61753 == ntdll.dll
$nt_hash2 = {43 6a 45 9e} //0x9e456a43 == LdrLoadDll
$nt_hash3 = {ec b8 83 f7} //0xf783b8ec == NtAllocateVirtualMemory
$nt_hash4 = {88 28 e9 50} //0x50e92888 == NtProtectVirtualMemory
$nt_hash5 = {f6 99 5a 2e} //0x2e5a99f6 == LdrGetProcedureAddress
$nt_hash6 = {da 81 b3 c0} //0xc0b381da == NtAllocateHeap
$nt_hash7 = {d7 71 ba 70} //0x70ba71d7 == RtlFreeHeap
$nt_hash8 = {88 2b 49 8e} //0x8e492b88 == RtlExitUserThread
$nt_hash9 = {ef f0 a1 3a} //0x3aa1f0ef == RtlExitUserProcess
$nt_hash10 = {f5 39 34 7c} //0x7c3439f5 == RtlRandomEx
$nt_hash11 = {70 f2 ab 35} //0x35abf270 == RtlNtStatusToDosError
$nt_hash12 = {1d aa a3 3c} //0x3ca3aa1d == RtlGetVersion
$nt_hash13 = {11 b2 8f f7} //0xf78fb211 == RtlCreateTimerQueue
$nt_hash14 = {4c 7c de a5} //0xa5de7c4c == RtlCreateTimer
$nt_hash15 = {90 fe 61 95} //0x9561fe90 == RtlDeleteTimerQueue
$nt_hash16 = {d0 ee 33 77} //0x7733eed0 == RtlCaptureContext
$nt_hash17 = {a9 af 4b 55} //0x554bafa9 == RtlAddVectoredExceptionHandler
$nt_hash18 = {0e 21 0c 88} //0x880c210e == RtlRemoveVectoredExceptionHandler
$nt_hash19 = {3d 13 8e 8b} //0x8b8e133d == NtClose
$nt_hash20 = {7d 74 58 ca} //0xca58747d == ZwCreateEvent
condition:
//PE or Shellcode or Shellcode
//Leave as "3 of them" for more robust (but compute expensive) searching
(3 of them) and (uint16(0) == 0x5a4d or uint16(0) == 0x00e8 or uint16(0) == 0x4856)
}
Vemos como solamente 1 de ellas funciona en este caso, detecta la DLL extraída:
$ yara win_havoc_ntdll_hashes_oct_2022.yar .
win_havoc_ntdll_hashes_oct_2022 ./ClarisseMathilda.dll
Sobre esta, rule win_havoc_djb2_hashing_routine_oct_2022.yar, la vamos a modificar, quitamos “and (uint16(0) == 0x5a4d or uint16(0) == 0x00e8 or uint16(0) == 0x4856)”, dejando solamente “(any of them)” y la probamos:
$ yara win_havoc_djb2_hashing_routine_oct_2022.yar .
win_havoc_djb2_hashing_routine_oct_2022 ./Tibia_of_Sabnock.tar.gz
Ahora ya sí lo detecta. Espero que os haya gustado y nos vemos en el próximo POST!
Hasta otra!!