Hay una cosa que define a los infostealers modernos y que, cuando la ves por primera vez en un desensamblador, resulta casi elegante: ya no esconden su servidor C2 (Comando y Control) dentro del binario. ¿Para qué, si los bloqueamos en cuanto lo extraemos? En lugar de eso, el malware lleva apuntado un perfil de una red social (Telegram, Steam, Mastodon) y, al arrancar, lee de ahí la dirección del C2 real. El operador cambia una línea en la descripción del canal y rota toda su infraestructura sin recompilar nada. Es lo que la industria llama un Dead Drop Resolver, y es la columna vertebral de la muestra que vamos a destripar hoy.
La pieza de malware llegó disfrazada de algo de lo más inofensivo: un pack de modelos .STL para impresión 3D. El tipo de archivo que un aficionado a la impresión descarga sin pensárselo dos veces.

Pero dentro del ZIP no había STLs que imprimir, sino dos ficheros que, juntos, esconden una cadena de infección de tres fases que acaba en Vidar 2.0, la reescritura en C del veterano stealer.

Un pack de STL que no tenía ningún STL
Lo primero que llama la atención al abrir el archivo es lo que no hay dentro. Un pack legítimo de impresión 3D contiene ficheros .stl y poco más. Este traía un ejecutable,
Ero-Pack 3D STL.exe, y una librería con un nombre que a cualquier analista le hace levantar la ceja: mpclient.dll. Ese nombre no es casual. Es el de un componente real de Microsoft Defender, y es la primera pista de que estamos ante un caso de DLL side-loading.
La confirmación llega enseguida. El supuesto «visor» Ero-Pack 3D STL.exe no es como tal el malware: es MpDlpService.exe, el servicio de prevención de fuga de datos de Microsoft Defender, con su firma Authenticode de Microsoft intacta y válida. Alguien se ha limitado a renombrarlo. Y como buen componente de Defender, cuando arranca busca y carga mpclient.dll desde su propio directorio. El atacante solo tiene que dejar ahí su DLL malicioso, con los mismos exports que el original (MpConfigInitialize, MpClientUtilExportFunctions y compañía), para que el binario firmado lo cargue y ejecute su código bajo la firma y la reputación de Microsoft. Para muchos controles de seguridad que confían en el firmante, eso es un salvoconducto.

Es una técnica que MITRE cataloga como T1574.002 y que hemos visto repetidamente en familias de primer nivel. Funciona porque explota algo que damos por sentado: que si un proceso firmado
por Microsoft carga una DLL, esa DLL es de fiar. No siempre lo es.

Primera fase: un cargador escrito en Go (y bien tapado)
Aquí es donde el caso se pone interesante. mpclient.dll no es el stealer, se trata de un intermediario. Un cargador de 3,6 MB escrito en Go y compilado con cgo, lo que ya de por sí es poco habitual y encaja con la tendencia de mover los loaders de malware a lenguajes que generan binarios grandes y ruidosos, más difíciles de analizar y de meter en sandboxes.
Y por si Go no fuera ya bastante incómodo de reversear, el autor lo ha pasado porgarble, el ofuscador de Go por excelencia. El resultado es que los nombres de las funciones propias del programa son galimatías aleatorios (main.zmkvcgzi, main.gzrlrlazymewxvo, main.qfihjnewysnnpbggunc) y que todas las cadenas de texto están cifradas. Abrir el binario en Ghidra y encontrarse este paisaje es, en sí mismo, una firma: estás ante un Go ofuscado con garble.

El primer muro, por tanto, son las cadenas. Sin ellas no hay rutas, ni claves, ni indicadores. Solo código que manipula bytes que no significan nada hasta que se descifran en tiempo de ejecución. La
buena noticia es que garble no inventa criptografía irrompible: usa un descifrador por literal, y aquí ese descifrador es la función main.zmkvcgzi, en 0x1e5d8d900. Reconstruir su lógica (cinco pasadas sobre el buffer, todas gobernadas por una semilla de 32 bits distinta para cada cadena) nos llevó un rato de paciencia con el decompilador, pero una vez entendida, se reimplementa en unas pocas líneas de Python y nos abre todo el binario:
def decrypt(data: bytes, seed: int) -> bytes:
b = bytearray(data); n = len(b)
for i in range(n):
if i & 1 == 0: b[i] = (b[i] - (seed % 53) - 17*i) & 0xff
else: b[i] = ((31*i) ^ (seed % 97) ^ b[i]) & 0xff
b.reverse()
i = 0
while i + 1 < n: b[i], b[i+1] = b[i+1], b[i]; i += 2
d = (seed >> 8) & 0xff
for i in range(n): b[i] = (b[i] - d) & 0xff
s = seed & 0xff
for i in range(n): b[i] ^= s ^ (i & 0xff)
return bytes(b)
La prueba de que la rutina es correcta llega cuando las dos primeras cadenas que descifra el binario en su init resultan ser, limpias y legibles, kernel32.dll y GetProcAddress. No es casualidad: significa que el loader resuelve sus APIs de Windows en tiempo de ejecución en lugar de declararlas en la tabla de imports, precisamente para no enseñar sus intenciones a quien mire el IAT.

Lo que de verdad hace el loader: cargar un PE en memoria
Con las cadenas descifradas y las APIs identificadas, el comportamiento del cargador se desvela como un loader reflexivo de PE de libro. Cuando MpDlpService.exe invoca el export MpConfigInitialize (algo que hace de forma natural al inicializarse), se dispara una rutina que, una vez apartado todo el ruido, hace exactamente esto: copia un blob cifrado de aproximadamente un megabyte que vive en la sección .rdata, lo descifra en memoria con la misma familia de rutinas garble, y descubre debajo un ejecutable PE de 64 bits completo. Acto seguido reserva una región de memoria con permisos de lectura, escritura y ejecución (VirtualAlloc con PAGE_EXECUTE_READWRITE), copia ahí cada sección del PE, le aplica las relocalizaciones de base y, finalmente, salta a su punto de entrada. El segundo stage nunca toca el disco: nace y se ejecuta en memoria RAM.
Lo que rodea a estos siete pasos merece una mención aparte, porque es donde el autor se ha divertido. Toda la maquinaria está enterrada bajo cientos de llamadas de impresión de un
decoy (un absurdo «simulador térmico de centro de datos» escrito en ruso, con zonas bautizadas Альфа, Бета, Гамма y un «registro de puntos calientes») y rodeada de bucles matemáticos de coma flotante que no sirven para nada salvo para agotar la paciencia del que analiza. Son predicados opacos: ruido deliberado para que el código real (la aguja) se pierda entre la paja.

Extraído ese megabyte y volcado a disco para estudiarlo con calma, lo que tenemos delante es un PE32+ de 64 bits, con su cabecera MZ, su «This program cannot be run in DOS mode» y su
firma PE impecables. Aquí empieza, de verdad, la segunda mitad de la investigación.

Segunda fase: Vidar, ahora en C y mejor blindado
El payload extraído es un PE de 64 bits compilado con Visual Studio 2019 en abril de 2026, sin tabla de imports y con todas las cadenas cifradas. Donde el loader usaba garble, este usa otra cosa: un ofuscador a medida de estilo MSVC, con aplanamiento del flujo de control, saltos indirectos que rompen el seguimiento de llamadas y aritmética mixta booleana-entera (MBA) que se va plegando en un acumulador global y se usa para construir predicados opacos. Es un grado de protección notablemente superior al de un stealer corriente, y es el primer indicio de que estamos ante algo serio.

El mismo problema de antes, multiplicado: sin cadenas no hay análisis, y aquí las cadenas están aún mejor escondidas. El binario las descifra con un transformador sembrado por una semilla
global, 0x5b658b19, que a su vez genera una función con una trampa elegante: solo devuelve la semilla buena si detecta que está en un proceso vivo (consultando campos del PEB); si la
ejecutas en frío, en un emulador ingenuo, devuelve 0xdeadbeef y todo el descifrado se va al traste. Es anti-análisis puro. Una parte de las cadenas pasa además por un stream cipher tipo
FNV-1a con sus propias constantes.
La forma de saltarse todo esto fue dejar de pelear contra el código y hacer que el propio binario trabajara para nosotros: con el EmulatorHelper de Ghidra emulamos las rutinas de descifrado (inyectando el estado correcto para que la trampa del PEB no saltara) y, una a una, recuperamos 789 cadenas en claro. Ese fue el momento en que el malware dejó de ser una caja negra. Entre esas cadenas estaba todo: las rutas de los navegadores, los nombres de las carteras, los formatos de las peticiones HTTP y, lo más importante, las pistas de su arquitectura de C2.

El servidor de control que no estaba en el servidor
Y aquí llegamos al motivo del título. Buscamos por todas partes una URL, una IP, un dominio hardcodeado… y no aparece. En su lugar, las cadenas hablan de «dead drop», de un separador
llamado sepword, de un modo direct y otro deaddrop. La configuración real del stealer no está en claro: viaja como un overlay al final del PE (1474 caracteres compuestos solo de letras, que resultan ser una codificación en base-52 sobre algo más de mil bytes cifrados con una clave que el binario calcula en ejecución).
La clave nace en runtime, después de toda la inicialización ofuscada, y no hubo combinación de cifrados ni de cribas que lo abriera en frío. Es un final honesto que conviene contar: no todo cede al análisis estático.
Pero el diseño nos decía exactamente lo que estaba pasando. El stealer no lleva su C2 escrito. Lleva apuntado un perfil de Telegram y, al arrancar, descarga esa página y extrae de su descripción la dirección del C2 real, separándola con el sepword. Es el patrón Dead Drop Resolver, y es la firma inconfundible de Vidar: el operador edita el canal y rota su infraestructura sin tocar el binario(Trend Micro,Darktrace).

En la capa de cadenas hardcodeadas del binario aparecía un dead drop concreto: t[.]me/turb00m. Pero el análisis dinámico nos demostró que ese no era el operativo. El que el malware usó de verdad fue t[.]me/t0mdr. Esto no quiere decir que se trata de un error al descifrar, ya que las dos cadenas tienen longitudes distintas, así que no son el mismo dato mal decodificado. En un stealer dirigido por configuración, las cadenas hardcodeadas son valores por defecto o plantillas. Los indicadores vivos están en la configuración cifrada o en el tráfico. El turb00m era el (por defecto) de fábrica (probablemente un canal de telegram ya eliminado o tumbado por Telegram), y el desarrollador del malware lo había sustituido por t0mdr en la config.
La detonación lo confirma todo
El sandbox cerró el círculo. Detonada la muestra en un entorno aislado, el tráfico reprodujo, paso por paso, el guion que habíamos reconstruido leyendo el código: una primera petición a https://telegram[.]me/t0mdr, el dead drop, e inmediatamente después, una ráfaga de peticiones POST contra https://k1h[.]fileboro[.]com/, el C2 real resuelto desde Telegram, alojado tras Cloudflare en 104.21.85[.]121 y 172.67.205[.]153. Los datos robados se exfiltran en cuerpos multipart/form-data con los campos token, build_id, hwid y file_data, y el veredicto del sandbox fue, sin ambigüedad, Vidar. Estático y dinámico, encajando como dos mitades de la misma foto. No siempre se tiene esa satisfacción.



Qué se lleva de la máquina
Una vez descifrado el tráfico hacia el C2, ya no hay que inferir nada: vemos al stealer recibir sus órdenes y empezar a vaciar la máquina en directo. Lo primero que devuelve el servidor, nada más recibir el identificador de la víctima, es un pequeño bloque de configuración en JSON que enciende o apaga cada módulo (Cookies, History, cryptocurrency, steal_discord, telegram, screenshot, steam, azure…) junto con parámetros como el tamaño máximo de los ficheros a robar (grabber_size_max) o el identificador del cliente (token). Es el panel de mandos del robo, y en esta muestra venía con prácticamente todo activado.


A partir de ahí, Vidar pide al C2 sus listas de objetivos y se pone a trabajar por fases. Va a por las credenciales, cookies e historiales de los navegadores (y no de dos o tres: la lista incluye Chrome, Edge, Brave, Vivaldi, Opera y Opera GX, Firefox, Thunderbird, CocCoc, el navegador de Avast, e incluso navegadores de nicho como Pale Moon o el de Roblox), con técnicas nuevas para sortear el cifrado moderno de Chrome. También va a por las carteras de criptomonedas. Por un lado, alrededor de cuarenta wallets de escritorio (Exodus, Electrum, Ledger Live, Monero, Binance, Coinomi, Wasabi, Trezor, Guarda, Atomic…), por otro, más de un centenar de extensiones de navegador (MetaMask, Phantom, TronLink, Coinbase, Rabby, Keplr, OKX, Trust Wallet y una lista interminable), a las que se suman decenas de gestores de contraseñas y autenticadores 2FA (Bitwarden, 1Password, LastPass, Dashlane, NordPass, KeePass, Authenticator, Proton Pass…). Y va, cómo no, a por las sesiones de Telegram (tanto los tdata locales como web.telegram.org), los tokens de Discord y de Steam, y las credenciales de servicios cloud como Azure (accessTokens.json, msal_token_cache.json).


No se limita a las aplicaciones: monta también un grabber de ficheros dirigido por reglas que el propio C2 le envía. En esta ejecución le ordenó peinar el Escritorio, las unidades extraíbles y Documentos buscando, hasta dos o tres niveles de profundidad, cualquier cosa que oliera a dinero o a secretos (máscaras como *wallet*, *seed*, *2fa*, *private*, *recovery*, *.txt), excluyendo de paso las carpetas del sistema para no hacer ruido. Todo lo recolectado lo empaqueta en ZIP y lo sube al servidor. En la captura de red se ve salir, una tras otra, las contraseñas de Firefox (logins.json), la base de contraseñas de Edge (passwords.db.zip), los certificados de Firefox y hasta una captura del escritorio de la víctima (releasesround.jpg). El primer fichero que manda, el information.txt, es un retrato completo de la máquina (y, de paso, una pequeña confesión del propio malware: junto al modelo de CPU, la RAM y el «Antivirus: None» aparece la cadena Version: 2.2 y, mejor aún, un revelador Work Dir: In memory que confirma, escrito por el propio bicho, la ejecución fileless que habíamos reconstruido a mano. Y por si todo esto fuera poco, la pieza hace también de loader (puede descargar y ejecutar más malware con powershell -ExecutionPolicy Bypass), se inyecta en otros procesos, persiste en la clave Run del usuario y comprueba si está siendo observada buscando procesos como MsMpEng.exe. Es, en definitiva, una navaja suiza del robo de datos.
Por qué decimos que es Vidar 2.0
Si en el plano estático la atribución ya descansaba en la concurrencia de varios indicios, el tráfico de red descifrado la convierte casi en una certeza: la propia muestra se identifica como tal. En el primer fichero que exfiltra al C2, ese information.txt con el retrato de la máquina, aparece estampada la cadena Version: 2.2 (es el malware diciéndonos, con sus palabras, qué es). Y no es el único marcador que pudimos ver en la captura en lugar de inferir: observamos en vivo el Dead Drop Resolver de Telegram resolviendo el C2 (t[.]me/t0mdr → k1h[.]fileboro[.]com), que es la marca de la casa de Vidar; y el protocolo de exfiltración multipart/form-data con sus campos inconfundibles (token, build_id, hwid) y su baile de modes pidiendo al servidor, fase a fase, las listas de navegadores, wallets y extensiones a saquear.
El resto de piezas encaja sobre esa base. El lenguaje: el binario está compilado en C con MSVC, y precisamente la versión Vidar 2.0, anunciada el 6 de octubre de 2025 por un desarrollador que firma como «Loadbaks», fue una reescritura de C++ a C pensada para builds polimórficos y evasión estática (Trend Micro, Infosecurity Magazine). Y el contexto: tras el desmantelamiento de Lumma en mayo de 2025 y la caída de Rhadamanthys, Vidar se movió rápido para ocupar el vacío, y a comienzos de 2026 es una de las cuatro familias que se reparten el mercado activo de infostealers (Intrinsec, Motasem Notes). El uso de un loader en Go con dead drop en su órbita tampoco es nuevo (Derp[.]ca). Con la versión escrita por el propio binario y su tráfico reproduciendo el manual de Vidar al pie de la letra, la atribución pasa de alta a prácticamente confirmada.
Para defenderse
Más allá de los IOCs concretos (que conviene monitorizar, pero que un distribuidor de malware puede rotar en minutos editando un canal de Telegram), hay comportamientos que envejecen mucho mejor como detección. El primero es el side-loading: cualquier MpDlpService.exe o MpCmdRun.exe ejecutándose desde una carpeta de usuario, fuera de las rutas oficiales de Defender, o con un mpclient.dll no firmado por Microsoft a su lado, es sospechoso por definición. El segundo es la carga reflexiva: procesos que reservan memoria con permisos de ejecución y escritura simultáneos y saltan a ella. Y el tercero, a nivel de red, es la propia mecánica del dead drop: una petición a telegram.me seguida, casi de inmediato, de tráfico hacia un host recién resuelto. Esos tres patrones cuestan mucho más de cambiar que un dominio.
A nivel de fichero, las constantes criptográficas que recuperamos sirven de ancla estable para reglas YARA, porque no dependen del empaquetado:
rule Vidar2_Stage2_CryptoConstants {
meta:
description = "Vidar 2.0 - constantes del descifrado de cadenas"
strings:
$seed = { 19 8B 65 5B } // semilla global 0x5b658b19
$fnv_init = { 41 CD B5 DD } // estado FNV 0xddb5cd41
$fnv_pr = { 93 01 00 01 } // primo FNV 0x01000193
$fnv_xor = { A8 DB 22 45 } // 0x4522dba8
condition:
uint16(0) == 0x5A4D and $seed and 2 of ($fnv_*)
}
Reflexión final
Esta muestra resume bastante bien dónde está el «commodity stealer» en 2026. Entrega a través
de un binario de confianza para esquivar la reputación del firmante; ejecución fileless gracias
a un cargador intermedio que mantiene el payload fuera del disco y un C2 que el malware ni siquiera
lleva encima, sino que recoge de Telegram cada vez, para sobrevivir a los takedowns. La doble
ofuscación (garble en la capa de Go, MBA y aplanamiento en la de C) encarece el análisis y
busca desanimar al que mira. Pero la combinación de reversing estático con emulación selectiva y una
detonación dinámica bien acotada permite, con paciencia, reconstruir la historia completa y sacar
indicadores accionables. Que es, al fin y al cabo, de lo que va esto.
Apéndice — Indicadores de compromiso (IOCs)
| Tipo | Valor |
|---|---|
| C2 host (vivo) | k1h[.]fileboro[.]com |
| C2 IPs | 104.21.85[.]121, 172.67.205[.]153 |
| Dead drop (vivo) | hXXps://telegram[.]me/t0mdr |
SHA-256 — ZIP Ero-Pack 3D STL.zip |
B1414F0F456630ACCF1B84D8E846CCCE02B58EA5F25A82A7BE1E309FC7462E34 |
SHA-256 — loader mpclient.dll |
20B50792CF0ACDA820F3B2A05EA738D9608C64950F7D3D30191F6C0D5BB25606 |
| SHA-256 — payload Vidar | EAE999E66861EF66AE42E357C8D6FD4D2BC61AB7F343418887695101192BEA93 |
MITRE ATT&CK: T1574.002, T1036, T1027, T1140, T1620, T1106, T1102 (Telegram DDR),
T1555/T1539, T1217, T1005/T1560, T1055, T1547.001, T1497.
Fuentes
- Trend Micro — How Vidar Stealer 2.0 Upgrades Infostealer Capabilities: enlace
- Intrinsec — «Chaos is a ladder»: Vidar’s recent rise (abr. 2026): enlace
- Darktrace — Vidar Network: Analyzing a Prolific Info Stealer: enlace
- Zscaler — Vidar distributed through backdoored Windows 11 downloads: enlace
- Derp.ca — Vidar v1.5 in Go: same family, new language, dead drop: enlace
- Infosecurity Magazine — Vidar Stealer 2.0 via fake game cheats: enlace
