Antecedentes
Una investigación sobre lo que a primera vista parecía una campaña “estándar” de infostealer basada en Python dio un giro interesante cuando se descubrió que culminaba en la implementación de un troyano de acceso remoto (RAT) completo y disponible comercialmente, conocido como PureRAT. Este artículo analiza la combinación que hace el actor de amenazas entre herramientas propias desarrolladas a medida y malware listo para usar.
Esta campaña muestra una progresión clara y deliberada, que comienza con un simple señuelo de phishing y escala a través de capas de cargadores en memoria, evasión de defensas y robo de credenciales. El payload final, PureRAT, representa la culminación de este esfuerzo: una puerta trasera modular y desarrollada de forma profesional que le da al atacante control total sobre un endpoint comprometido. Analizaremos toda la cadena de ataque, desde el DLL cargado mediante sideloading inicial hasta el canal de comando y control (C2) cifrado final, y te damos el contexto y los indicadores que necesitas para defender tus redes.
Nota: Desde que comenzamos este análisis, SentinelLABS y Beazley Security publicaron un excelente informe que cubre las etapas 1 y 2. Vale la pena leerlo para obtener contexto adicional, aunque el material de la etapa 3 (PureRAT) sigue siendo exclusivo de este artículo, así que quédate para eso.
Análisis detallado
Figura 1: Descripción general de la cadena de ataque
Esta intrusión es un gran ejemplo de ofuscación por capas y evolución táctica. El actor de amenazas encadenó diez payloads o etapas distintas, que aumentan progresivamente en complejidad para ocultar su objetivo final.
Etapa 1: El señuelo inicial y los cargadores en Python
El ataque comienza con un correo de phishing convencional que contiene un archivo ZIP disfrazado de aviso de infracción de derechos de autor. El archivo contiene un ejecutable legítimo y firmado de un lector de PDF, junto con un version.dll malicioso. Esta es una técnica clásica de sideloading de DLL, que obliga a un ejecutable confiable a cargar involuntariamente el DLL malicioso desde el mismo directorio.
Figura 2: Archivo malicioso enviado en el correo de phishing
El DLL malicioso usa una serie de binarios y archivos de Windows dentro de la carpeta oculta “_” para ejecutar el siguiente payload. Usa certutil.exe para decodificar un blob codificado en Base64 oculto dentro de un archivo llamado Document.pdf, lo que da como resultado un archivo ZIP. Luego usa una copia incluida y renombrada de WinRAR (images.png) para extraer el contenido.
Desde este segundo archivo, los archivos se extraen a C:\Users\public\windows\ e incluyen un intérprete de Python renombrado (svchost.exe) y un script de Python ofuscado (images.png), que luego se ejecutan.
Esta fase del ataque, tal como se describió anteriormente, queda registrada en el siguiente evento de Sysmon:
Type: Process Create
Image: C:\Windows\SysWOW64\cmd.exe
ParentImage: C:\Users\Malware\Desktop\sample\Detailed_report_document_on_actions_involving_copyrighted_material.exe
CommandLine: cmd /c cd _ && start Document.pdf && certutil -decode
Document.pdf Invoice.pdf && images.png x -ibck -y Invoice.pdf
C:\Users\Public && start C:\Users\Public\Windows\svchost.exe
C:\Users\Public\Windows\Lib\images.png ADN_UZJomrp3vPMujoH4bot
Payload 2
El script de Python images.png (no el binario images.png de WinRAR) es un cargador que contiene una cadena grande codificada en Base85. El payload se ejecuta completamente en memoria mediante exec() después de decodificarse y descomprimirse, lo que da inicio al payload 3.
Figura 3: Payload de archivos - un cargador de bytecode de Python
Payload 3
Al ejecutar el payload 3 a través de dis, un módulo integrado que convierte bytecode en una interpretación legible para humanos, se revela que se trata de otro cargador, en este caso uno criptográfico personalizado. Usa un esquema de cifrado híbrido que involucra RSA, AES, RC4 y XOR para descifrar el payload 4.
Figura 4: Resumen de la salida de Python dis
Payload 4
Reconstruir esta funcionalidad en nuestro propio script de Python nos permite ejecutar este payload a través de dis nuevamente.
Nota: De aquí en adelante, convertí la salida de dis a código fuente para explicar más fácilmente las siguientes secciones.
Para un ataque en memoria como este, el actor de amenazas debe asegurarse de que su malware pueda sobrevivir a un reinicio del sistema. El script del payload 4 usa la biblioteca integrada de Python winreg para modificar las claves del registro del sistema, agregando una clave de ejecución diseñada para parecer un componente legítimo de Windows: Windows Update Service.
Figura 5: Recreación de la verificación de infección y la creación de persistencia del payload 4
Los datos almacenados en este valor son un comando que vuelve a ejecutar la primera etapa del malware, lo que asegura que toda la cadena de infección se reinicie cada vez que el usuario comprometido inicia sesión.
cmd /c start C:\Users\Public\Windows\svchost.exe C:\Users\Public\Windows\Lib\images.png <sys.argv[1]>
El payload 4 luego continúa el patrón de cargador, esta vez usando descripciones de bots de Telegram y acortadores de URL (is[.]gd) para obtener y ejecutar dinámicamente el siguiente payload, lo que le da al actor de amenazas un mecanismo flexible para actualizar su cadena de ataque.
Figura 6: Recreación del cargador de la etapa 2
Observa el uso de sys.argv[1] aquí; en nuestro caso, este es el argumento ADN_UZJomrp3vPMujoH4bot de cuando la etapa 1 extrajo el payload 2 y ejecutó el primer script de Python.
Etapa 2: El primer payload armado: un infostealer en Python
Al descargar la siguiente etapa desde is[.]gd, llegamos al primer payload armado: un ladrón de información basado en Python. El análisis del bytecode descifrado revela funciones para recolectar una amplia variedad de datos confidenciales, incluyendo credenciales, cookies, tarjetas de crédito y datos de autocompletado de navegadores basados en Chrome y Firefox.
Figura 7: Recreación de la notificación de nueva víctima
Todos los datos robados se archivan en un archivo ZIP y se exfiltran mediante la API de Telegram Bot. Los metadatos del archivo ZIP contienen una pista sobre quién podría estar detrás de este ataque: un campo de contacto que apunta al usuario de Telegram @LoneNone. Este usuario ha sido asociado públicamente con la familia de malware PXA Stealer, lo que nos da un fuerte vínculo de atribución.
Figura 8: Recreación de la creación del archivo con la información recolectada, con una pista “@LoneNone”
Luego se usa la API de Telegram para enviar el ZIP resultante y el mensaje (arriba) a varios chats de Telegram, según la siguiente lógica:
Tabla 1: Lógica de mensajes de Telegram
Etapa 3: El cambio hacia .NET
Justo cuando el objetivo de la campaña parecía claro, el actor de amenazas da un giro. La etapa 3 marca un cambio importante: de scripts interpretados en Python a ejecutables .NET compilados.
Figura 9: Recreación del cargador de la etapa 3
La nueva etapa se obtiene desde 0x0[.]st, un "servicio de alojamiento de archivos y acortamiento de URL sin tonterías". Esta etapa es mucho más grande que el script anterior en Python (40 KB -> ~3 MB), ya que contiene dos payloads más incrustados.
El primer binario es un ensamblado .NET que se descifra usando base64 y una clave RC4 codificada directamente en el código. Luego, el actor de amenazas usa process hollowing al lanzar una utilidad legítima de .NET, RegAsm.exe, en estado suspendido. Desasigna el código ejecutable original de la memoria del proceso, asigna una nueva región de memoria y escribe en ella el payload malicioso de .NET (payload 7). Luego se actualiza el contexto del hilo principal para que apunte al nuevo punto de entrada, y se reanuda el hilo, ejecutando el código malicioso bajo la apariencia de un binario legítimo de Microsoft.
Figura 10: Recreación del script de Python usado para el process hollowing y la carga de un ensamblado .NET cifrado
El segundo es un cargador de shellcode, pero no profundizaré en este payload aquí, en parte porque este análisis ya es bastante denso, pero sobre todo porque tuve problemas al intentar emularlo.
Payload 7
Este es nuestro primer payload PE, y parece que el autor dejó cadenas de depuración, lo que confirma que realiza dos técnicas clave de evasión de defensas:
Figura 11: Salida de FLOSS del ensamblado .NET
- Parcheo de AMSI: Parchea la función AmsiScanBuffer en amsi.dll para evitar que el Antimalware Scan Interface inspeccione código cargado dinámicamente.
- Desenganche de ETW: Parchea EtwEventWrite en ntdll.dll para cegar Event Tracing for Windows, una fuente común de telemetría para productos EDR.
Este ensamblado contiene otro payload incrustado (payload 8), que decodifica usando una combinación simple de Base64 y XOR.
Una vez descifrado el payload, se pasa al método integrado de .NET Assembly.Load, que carga el ejecutable directamente en memoria. El flujo continúa a través de getEntryPoint, que obtiene el punto de entrada del ensamblado cargado, y finalmente, invokeCSharpMethod ejecuta el método mediante reflexión.
Figura 12: Desensamblado en dnSpy del cargador del siguiente payload
Extrayendo este payload usando CyberChef (Base64 → XOR con clave):
Figura 13: Receta de CyberChef para extraer el siguiente payload
Payload 8
Este payload usa AES-256 y descompresión GZip para desempaquetar la novena y última etapa: una DLL llamada Mhgljosy.dll. En lugar de depender de exportaciones tradicionales, el cargador usa reflexión de .NET (Assembly.Load(), GetType(), GetMethod()) para cargar la DLL completamente en memoria e invocar un método específico y ofuscado para iniciar su ejecución.
Figura 14: El cargador del payload 9, después del descifrado
Con un punto de interrupción en GetMethod() y un poco de depuración, descubrimos que este método es Mhgljosy.Formatting.TransferableFormatter.SelectFormatter()
Payload 9: La parte final: PureRAT
Después de ocho payloads/etapas de cargadores, ladrones de información y ofuscación, finalmente llegamos al último payload, Mhgljosy.dll. Pero la DLL está protegida con .NET Reactor, un ofuscador comercial usado para dificultar la ingeniería inversa.
Figura 15: DiE muestra que el ensamblado fue ofuscado por .NET Reactor
El análisis estático llega a un punto muerto, así que recurrimos a la desofuscación. Usando una herramienta de código abierto llamada NETReactorSlayer (gracias, Anna Pham, por la sugerencia), logramos eliminar gran parte de la redirección del flujo de control y el cifrado de cadenas para producir un ensamblado más legible.
Con un binario más limpio, podemos analizar el punto de entrada identificado en el payload anterior:
Siguiendo el control desofuscado, primero llegamos a ReceiveAttachedSubscriber. Justo encima de este método, vemos un blob en Base64.
Figura 16: Primer método de interés en PureRAT
La lógica de decodificación es:
- Decodificación Base64: Se decodifica la cadena inicial.
- Descompresión GZip: La salida decodificada en base64 revela un encabezado GZip.
- Deserialización Protobuf: Los datos descomprimidos se deserializan usando un esquema de Protocol Buffers (protobuf).
Esto revela la configuración del malware.
Figura 17: Decodificación de la configuración de PureRAT
La configuración final deserializada contiene la infraestructura de C2: una dirección IP (157.66.26[.]209), una lista de puertos (56001, 56002, 56003) y otro blob en base64 que se decodifica en un certificado X.509. El malware usa este certificado para TLS pinning, lo que garantiza que sus comunicaciones con el C2 estén cifradas y sean resistentes a la inspección por intermediarios (man-in-the-middle).
Figura 18: Configuración del socket con TLS pinning
Cabe destacar que este servidor de C2 está ubicado en Vietnam, lo que suma otra evidencia de que se trata de PXA y de que las personas detrás de esto probablemente sean vietnamitas.
Figura 19: Página de Validin para el servidor de C2 de los atacantes
Una vez conectado al C2, el RAT envía de vuelta al operador un paquete inicial de "hello". Esto se arma a partir de esta lógica en medio de la función, que es difícil de entender debido a la ofuscación de los nombres de los métodos.
Figura 20: Enumeración de sistema ofuscada
Una vez desofuscado, encontramos que esto consiste en un fingerprinting exhaustivo del equipo, que recopila una gran cantidad de información antes de enviarla de vuelta al servidor de C2.
Figura 21: Enumeración de sistema desofuscada
A continuación se detallan todas las funciones usadas en esta rutina de fingerprinting:
Figura 22: Productos antivirus: Consulta WMI (root\SecurityCenter) para obtener el displayName de todos los productos antivirus instalados.
Figura 23: La función PlaySubscriber() usada para crear un identificador único del equipo
ID único del equipo: Como se ve en la figura 23, se genera mediante un hash MD5 basado en el ID del procesador, el número de serie del disco duro, el número de serie de la memoria física y el nombre de dominio del usuario. Esto crea un identificador estable y único para el equipo de la víctima.
Figura 24: Presencia de webcam: Consulta WMI en busca de dispositivos PnP con la clase Image o Camera
Figura 25: Usuario y dominio: Recopila el nombre de usuario y el dominio actuales (username [DOMAIN])
Figura 26: Nivel de privilegios: Verifica la identidad de Windows del proceso actual frente a los roles integrados (Administrator, User, Guest, etc.) para determinar su nivel de privilegios
Figura 27: Sistema operativo: Recopila la versión y la arquitectura del sistema operativo (por ejemplo, "Windows 10 64Bit")
Figura 28: La función RemoveSelector() usada para encontrar y listar cualquier criptomonedera preconfigurada
Monederos de criptomoneda: Esta función busca docenas de monederos de criptomoneda basados en navegador y de escritorio, verificando los ID de extensión de Chrome, las rutas del sistema de archivos (%APPDATA%) y las claves de registro
Nota: esta función no recopila ningún dato, solo devuelve una cadena con lo que está presente en el sistema.
Figura 29: Tiempo de inactividad del sistema: Usa la API GetLastInputInfo para determinar cuánto tiempo ha estado inactivo el usuario, lo que permite al operador actuar cuando el usuario no está presente
Figura 30: Ruta del implante: Informa su propia ruta de archivo en el disco
Una vez que se completa la identificación inicial del equipo y se establece el enlace con el C2, el RAT pasa a su función principal: un bucle de tareas persistente diseñado para recibir y ejecutar comandos.
Figura 31: Bucle de tareas a la espera de más payloads
El bucle de tareas es bastante sencillo una vez desempaquetado:
- (Rojo) Lee los primeros 4 bytes para determinar la longitud del payload.
- (Azul) Lee esa cantidad de bytes en un búfer; este es el payload real.
- (Verde) Deserializa el búfer con la rutina de protobuf que vimos antes.
- (Verde) Crea un nuevo hilo y llama a DecideFlexibleController()sobre el mensaje para ejecutar la tarea.
Esta arquitectura convierte efectivamente a este RAT en un cargador dinámico. El implante permanece inactivo, esperando a que el operador envíe módulos bajo demanda, extendiendo dinámicamente sus capacidades mucho más allá del reconocimiento inicial. Estos complementos podrían agregar funcionalidades que van desde el acceso al micrófono o la cámara web hasta el registro de teclas en tiempo real y el acceso a escritorios ocultos.
Por suerte para la víctima, el Huntress SOC pudo aislar y remediar el endpoint infectado antes de que el actor de amenazas pudiera desplegar cualquiera de estos complementos armados adicionales, deteniendo el ataque antes de que pudiera lograr sus objetivos finales. Por desgracia para nosotros, eso significa que no tenemos más módulos que investigar.
Una última pista revela PureRAT
Los espacios de nombres de .NET nos dan otra pista con menciones de PureHVNC, una fuerte evidencia de que esta muestra está vinculada a Pure Hidden VNC, una pieza de malware comercial vendida anteriormente por alguien que usaba el alias “PureCoder”.
Figura 32: Módulos de PureHVNC en el ensamblado
Si bien PureHVNC es prácticamente legado en este punto, muchos de sus módulos perduran en las familias de malware más recientes de PureCoder, cada una diseñada para cumplir un propósito específico:
- PureCrypter – un crypter usado para inyectar malware en procesos legítimos, evadir la detección y frustrar el análisis con verificaciones anti-VM y anti-debug.
- BlueLoader – un cargador que despliega payloads adicionales en los sistemas infectados, dándoles a los atacantes una manera fácil de organizar y actualizar sus campañas de malware.
- PureMiner – un cryptojacker silencioso que secuestra los recursos de CPU y GPU de la víctima para minar criptomoneda para el atacante sin su consentimiento.
- PureLogs Stealer – un ladrón de información que exfiltra datos del navegador, credenciales guardadas y tokens de sesión, a menudo enviándolos directamente al Telegram del atacante.
- PureRAT – una puerta trasera modular que establece un canal C2 encriptado y permite a los operadores cargar módulos adicionales
- PureClipper – monitorea el portapapeles del sistema en busca de direcciones de criptomoneda y las reemplaza con direcciones controladas por el atacante durante las operaciones de copiar y pegar, redirigiendo transacciones de criptomonedas para robar fondos.
Esta arquitectura y conjunto de funciones que hemos observado aquí coinciden perfectamente con PureRAT, el desarrollador anunció abiertamente esta herramienta como una “herramienta de administración” remota codificada a medida en .NET, con un cliente ligero encriptado con TLS/SSL y una interfaz gráfica multilingüe, que ofrece amplias funciones de vigilancia y control, como acceso a escritorios ocultos (HVNC/HRDP), espionaje por cámara web y micrófono, registro de teclas en tiempo real y sin conexión, CMD remoto, y monitoreo de aplicaciones (por ejemplo, navegadores, Outlook, Telegram, Steam). Incluye herramientas de gestión como administradores de archivos, procesos, registro, red e inicio, además de capacidades para ataques DDoS, proxy inverso, inyección de código .NET, gestión de Bot de transmisión y ejecución de archivos en memoria o disco. Aunque notablemente “excluye la recuperación de contraseñas/cookies” (función de Stealer), ya que eso se vende por separado.
Figura 33: Interfaz C2 de PureRAT en la publicidad de PureCoder
Conclusión
La infraestructura recurrente de Telegram, los metadatos vinculados a @LoneNone, y los servidores C2 rastreados hasta Vietnam sugieren fuertemente que esto fue llevado a cabo por las personas detrás de PXA Stealer. Su progresión desde una ofuscación amateur de sus payloads en Python hasta el abuso de malware comercial como PureRAT no solo demuestra persistencia, sino también las características de un operador serio y en maduración. El actor de amenazas demostró dominio de múltiples lenguajes y técnicas, desde cargadores de bytecode de Python y enumeración por WMI hasta vaciado de procesos (process hollowing) en .NET y carga reflexiva de DLL.
Desde una perspectiva más amplia, el giro de un ladrón de información codificado a medida hacia un RAT comercial como PureRAT es significativo. Esto reduce la barrera de entrada para el atacante, dándole acceso a un kit de herramientas estable, rico en funciones y mantenido “profesionalmente” sin requerir un esfuerzo de desarrollo extenso. El impacto es una amenaza más resiliente, modular y peligrosa, capaz de un robo de datos extenso, vigilancia, ataques posteriores y persistencia a largo plazo.
Esta campaña subraya la importancia de la defensa en profundidad. El acceso inicial dependió de la ejecución por parte del usuario, los cargadores explotaron binarios confiables y del sistema, y la etapa final usó evasión de defensas para permanecer ocultos. Ningún control por sí solo podría haber detenido toda esta cadena. Al comprender el ciclo de vida completo del ataque y monitorear los comportamientos específicos descritos aquí, desde el abuso de certutil hasta las consultas WMI y el tráfico C2 encriptado, las organizaciones pueden construir una postura de seguridad más resiliente.
Mapeo de MITRE ATT&CK
|
Táctica |
Técnica |
Nombre |
Descripción del |
|
Acceso inicial |
T1566.001 |
Adjunto de spearphishing |
La campaña comienza con un correo de phishing que contiene un archivo ZIP malicioso. |
|
Ejecución |
T1204.002 |
Ejecución por el usuario: archivo malicioso |
Se engaña al usuario para que ejecute un archivo .exe disfrazado de documento. |
|
Ejecución |
T1059.006 |
Python |
Las etapas 1 y 2 se ejecutan mediante un intérprete de Python renombrado. |
|
Persistencia |
T1547.001 |
Claves de ejecución del registro / carpeta de inicio |
El payload 4 establece persistencia creando una clave Run llamada "Windows Update Service". |
|
Evasión de defensas |
T1574.001 |
Carga lateral de DLL |
Se usa un ejecutable legítimo de lector de PDF para cargar un version.dll malicioso. |
|
Evasión de defensas |
T1027 |
Archivos o información ofuscados |
Varias etapas usan Base85, Base64, RC4, AES y XOR para ocultar los payloads. |
|
Evasión de defensas |
T1055.012 |
Vaciado de procesos |
El cargador .NET del payload 7 se inyecta en un proceso RegAsm.exe suspendido. |
|
Evasión de defensas |
T1562.001 |
Deterioro de defensas: deshabilitar o modificar herramientas |
El cargador del payload 7 parchea AMSI para evitar el escaneo en tiempo de ejecución. |
|
Evasión de defensas |
T1562.006 |
Deterioro de defensas: bloqueo de indicadores |
El cargador del payload 7 desengancha ETW para bloquear la telemetría de EDR. |
|
Descubrimiento |
T1082 |
Descubrimiento de información del sistema |
PureRAT identifica la versión del sistema operativo, la arquitectura y los privilegios del usuario. |
|
Descubrimiento |
T1518.001 |
Descubrimiento de software de seguridad |
El malware usa WMI para enumerar los productos antivirus instalados. |
|
Recolección |
T1560.001 |
Archivado de datos recolectados: archivado mediante utilidad |
Los datos robados se comprimen en un archivo ZIP antes de la exfiltración. |
|
Comando y control |
T1071.001 |
Protocolos web |
El ladrón de la etapa 2 exfiltra datos mediante solicitudes HTTP POST a la API de Telegram. |
|
Comando y control |
T1573.002 |
Canal cifrado: criptografía asimétrica |
PureRAT usa TLS con un certificado X.509 fijado para las comunicaciones de C2. |
IOC
Artefactos de disco y memoria
|
Valor |
Descripción |
|
SHA256: e0e724c40dd350c67f9840d29fdb54282f1b24471c5d6abb1dca3584d8bacaa |
Payload 9 Payload (PureRAT) |
|
SHA256: 06fc70aa08756a752546198ceb9770068a2776c5b898e5ff24af9ed4a823fd9d |
Payload 8 Loader |
|
SHA256: f5e9e24886ec4c60f45690a0e34bae71d8a38d1c35eb04d02148cdb650dd2601 |
Payload 7 Loader |
|
File Path: C:\Users\Public\Windows\svchost.exe |
Intérprete de Python renombrado usado en las primeras etapas. |
|
File Path: C:\Users\Public\Windows\Lib\images.png SHA256: f6ed084aaa8ecf1b1e20dfa859e8f34c4c18b7ad7ac14dc189bc1fc4be1bd709 |
Script de Python ofuscado (payload 2). |
|
Registry Key: HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\Windows Update Service |
Clave de registro de persistencia creada en el payload 4. |
Red / Infraestructura
|
Tipo |
Valor |
Descripción |
|
Dirección IP |
157.66.26.209 |
Servidor C2 de PureRAT |
|
Puerto |
56001 |
Puerto C2 de PureRAT (predeterminado) |
|
Puerto |
56002 |
Puerto C2 de PureRAT |
|
Puerto |
56003 |
Puerto C2 de PureRAT |
|
URL |
https://0x0[.]st/8WBr.py |
URL de alojamiento del payload de la etapa 3. |
|
URL |
https://is[.]gd/s5xknuj2 https://paste[.]rs/fVmzS |
URL de alojamiento del payload de la etapa 2. |
|
Usuario de Telegram |
@LoneNone |
Usuario del actor de amenazas asociado con la etapa 2 (PXA Stealer). |
Agradecimientos
Me gustaría agradecer a Anna Pham por su ayuda para extraer y desofuscar la etapa final.