Hola a tod@s!!
Seguro que últimamente habéis oído hablar de Lumma Stealer, parece estar de moda y su uso ha subido como la espuma así que vamos a hablar un poco de él.
Si buscamos a Lumma en Malware Trends de Any.run lo tenemos nada más y nada menos que en el TOP 1.

Aprovechando la información que ofrece esta plataforma tenemos la siguiente descripción del malware:
“Lumma es un stealer ampliamente accesible que se vende abiertamente en foros de la Dark Web y canales de Telegram. Aunque no es tan popular como otros (RedLine y Formbook), ha ganado una tracción considerable entre los ciberdelincuentes que se centran en exfiltrar información confidencial de víctimas desprevenidas. Operado por un grupo que se cree que se originó en países de la ex URSS, Lumma Stealer ha estado evolucionando activamente desde su aparición inicial en 2022, recibiendo actualizaciones sustanciales que mejoran sus capacidades.”
Si queremos ir a tiro hecho, buscaremos detecciones en el que solamente aparezca una mención a Lumma y ninguno más o correremos el riesgo de perdernos en el bosque.

Seleccionamos un par de ellos al azar:
- https://app.any.run/tasks/e10cb2f0-5400-45a1-939b-2ded96ef51e3
- https://app.any.run/tasks/cdf33f86-2ae1-4567-9a5a-f5520e2d0151
$ sha256sum *
c3b2dc36b6413c733de9d97ae5b52b48e12676cf591530f1ce26b2a7de6ab2cd Solara.exe
79bf1f088f590b8e24eaf5eb4b654bd7534102593a30af3475dd8dd57aed1d2b Yanto.exe
Lo primero, identificamos que tipo de ficheros estamos tratando así como con qué herramienta fueron compilados.
$ file *
Solara.exe.bin: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows
Yanto.exe.bin: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows
$ diec --heuristicscan *
Solara.exe:
PE32
Linker: Microsoft Linker
Library: .NET Framework(v4.7.2, CLR v4.0.30319)
(Heur)Packer: Compressed or packed data
Yanto.exe:
PE32
Linker: Microsoft Linker
Library: .NET Framework(v4.7.2, CLR v4.0.30319)
(Heur)Packer: Compressed or packed data
Tenemos un par de aplicaciones .NET y para analizar este tipo de aplicaciones tenemos DnSpy. Abrimos cualquiera de ellos (siguiente ejemplo Solara.exe) y buscamos signos de ofuscación ya que como os podéis imaginar, Lumma Stealer no estará directamente accesible, sino que lo extraerá o descargará, pronto lo comprobaremos.

El EntryPoint parece estar sin ofuscar, no vemos nada raro, así que pulsamos sobre el mismo y apareceremos en el Main.

A modo de resumen, este código inspecciona el propio archivo ejecutable en busca de una sección específica en su encabezado PE (una sección con el nombre o formato relacionado con "CS"). Si encuentra la sección, extrae su contenido y lo almacena en un arreglo de bytes. Al final, si se cumple esta condición, crea un objeto de la clase Publisher.
Abrimos el fichero con Radare2 y mostramos las secciones:

Tenemos una coincidencia y comprobamos qué tipo de datos hay en esa sección.

Entramos dentro de la clase Publisher para ver qué va a hacer con los datos anteriores.

Por lo tanto, la clase Publisher esta diseñada para manipular y ejecutar código desde la memoria:
- Aplica cambios de permisos en regiones de memoria utilizando la API VirtualProtect para permitir que se ejecute código que ha sido cargado o descifrado en la memoria.
- Utiliza claves almacenadas en el código para operar sobre los datos en memoria.
- Ejecución de código dinámico: Utiliza CallWindowProcA, que indica que está ejecutando código dinámico desde el contenido de memoria que ha modificado previamente.
Si nos fijamos en el código de la captura y prestamos atención al bucle, tenemos que llama dos veces al método Program.ApplySettings:
- La primera vez, pasa como parámetros los datos almacenados en Program.inputData, su longitud, y una clave (Program.dataKey).
- La segunda vez, pasa como parámetros el contenido de la sección (Program.sectionContent), su longitud, y una clave (Publisher._key), que es un array de bytes definido en la clase.
Los datos utilizados para descifrar el contenido de “algo” estaba justo debajo del EntryPoint, serían estos:

Ponemos unos breakpoint en las líneas siguientes y vamos viendo como se van completando las variables con los datos que finalmente nos serán de utilidad, así vemos qué hace con esa sección que vimos antes:

Después del último breakpoint tenemos en la variable array el propio ejecutable.

En la siguiente captura vemos la zona de código utilizada para poner todo en su sitio, es decir, Lumma Stealer en memoria.

Estas dos últimas funciones cargan dinámicamente la API VirtualProtect desde la biblioteca kernel32.dll utilizando LoadLibraryA y GetProcAddress, para cambiar los permisos de protección de la región de memoria de Program.inputData, permitiendo leer, escribir y ejecutar (PAGE_EXECUTE_READWRITE). Luego, CallWindowProcAejecuta código desde una posición específica dentro de Program.inputData (índice 392), utilizando también el contenido de Program.sectionContent como uno de los parámetros, lo que ejecutaría código almacenado o modificado en memoria.

Vamos a ver el otro ejecutable que tenemos, Yanto.exe, y comprobamos que es muy parecido.

Esta vez la clase se llama diferente pero hace más o menos lo mismo.

El cual, como vemos en la imagen anterior, realizaría las mismas acciones con VirtualProtect y CallWindowProcA que había mostrado con el otro malware.
El método InitRoute realiza una serie de operaciones relacionadas con la manipulación y ejecución de código en memoria. Primero, llama a Program.BeginInit para procesar el contenido de la sección (Program.sectionContent) utilizando una clave almacenada en Router._key. Luego, cambia los permisos de la región de memoria que contiene Program.inputData a PAGE_EXECUTE_READWRITE mediante Program.VirtualProtect, permitiendo su ejecución. Después, vuelve a inicializar los datos de entrada (Program.inputData) con una clave (Program.dataKey). Finalmente, ejecuta código desde la memoria, llamando a Program.CallWindowProcA con una referencia a una posición específica dentro de Program.inputData y utilizando Program.sectionContent como parámetro. Lo que vuelve a indicar que se está ejecutando código modificado o cargado dinámicamente en memoria.
Es muy parecido al de antes e incluso tiene las mismas variables (muy útil para lo que veremos al final):

Ponemos un breakpoint directamente en la siguiente línea y esperamos a que se cargue en memoria.

Y lo extraemos como en el caso anterior:

Si depuramos cualquiera de las muestras extraídas llegamos al punto de las obtención de API que serán empleadas durante la comunicación y son generadas en tiempo de ejecución, se usa API Hashing con el algoritmo MurmurHash2:

Con esto ocultan la finalidad real del binario, las funciones no se encuentran disponibles ni en las imports (en la IAT) ni como strings.
Buscamos la zona del código en donde se obtienen los dominios utilizados por el malware, esto lo iréis viendo a medida que vayáis avanzando en el malware.

Como queremos loguear los C2, editamos el breakpoint en ese punto, en donde nos devuelve el C2 en el registro ESI:

Y en la pestaña de Log aparecerán los C2 de Lumma, serían todos estos.

Esta herramienta es capaz de sacar los C2 de forma estática, pero no funciona con estas versiones, serán versiones recientes.

Siempre me gusta terminar con una Yara para detectar lo que hemos visto así que ahí va:
rule Lumma_payload {
meta:
author = "byRafa"
description = "Detects Lumma Stealer payload"
cape_type = "Lumma Payload"
strings:
$MZ = "MZx"
$s1 = ",5054585<5@5D5H5L5P5T5X5\\5`5d5h5l5p5t5x5|5"
$s2 = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F"
condition:
($MZ at 0 and all of ($s*))
}
rule Lumma_packer {
meta:
author = "byRafa"
description = "Detects Lumma Stealer packer"
cape_type = "Lumma Payload"
strings:
$s1 = "AD446C34F2704865A9E424BE5755BC8F9140414FD7E1456F1A4581F8C2D778A0"
$s2 = "CallWindowProcA"
$s3 = "_CorExeMain"
$s4 = "get_ExecutablePath"
$s5 = "inputData"
$s6 = "_key"
$s7 = "dataKey"
$s8 = "TargetFrameworkAttribute"
$s9 = "FromBase64String"
$s10 = "DebuggingModes"
condition:
(uint16(0) == 0x5A4D and all of ($s*))
}
Comprobamos que funciona:
$ yara Lumma.yar .
Lumma_packer ./Yanto.exe
Lumma_payload ./Yanto_dumped.exe
Lumma_packer ./Solara.exe
Lumma_payload ./Solara_dumped.exe
Espero que os haya gustado y nos vemos en el siguiente POST!!