Propagación de NWHStealer a través del entorno de ejecución Bun JavaScript
Detection stack
- AIDR
- Alert
- ETL
- Query
Resumen
El artículo explica cómo los actores de amenazas están utilizando el entorno de ejecución de Bun JavaScript para entregar el infostealer NWHStealer basado en Rust. Los archivos ZIP maliciosos contienen un instalador primario que lanza un cargador de JavaScript empaquetado con Bun junto con un cargador secundario llamado dw.exe. El componente de JavaScript realiza comprobaciones contra máquinas virtuales, se comunica con la infraestructura de comando y control, desencripta una carga útil de seguimiento y abusa de las API nativas de Windows para inyectar el stealer en la memoria. Para reducir sospechas, la campaña oculta archivos maliciosos detrás de plataformas de alojamiento legítimas como GitHub, MediaFire y SourceForge.
Investigación
Los investigadores encontraron que Bun se utilizó para empaquetar JavaScript malicioso dentro de la sección .bun del cargador. Dos scripts, sysreq.js and memload.js, manejaban las comprobaciones del entorno y la comunicación con la infraestructura del atacante. El cargador recuperaba datos de configuración y cargas útiles encriptadas de dominios como silent-harvester.cc, los desencriptaba con AES-256-CBC, y los inyectaba a través de llamadas a la API de Win32. La carga útil final era NWHStealer, que roba credenciales, datos de navegador e información de billeteras de criptomonedas, y también puede iniciar actividad adicional de minería.
Mitigación
Los usuarios deben evitar descargar ejecutables de sitios web no confiables y verificar las firmas de los instaladores antes de ejecutarlos. Los equipos de seguridad deben monitorear actividad inusual del tiempo de ejecución de Bun, consultas PowerShell CIM utilizadas para comprobaciones de virtualización, y llamadas sospechosas a APIs como VirtualAlloc and LoadLibraryA. Las organizaciones también deberían bloquear los dominios maliciosos conocidos y aplicar políticas de ejecución de privilegios mínimos para limitar abusos.
Respuesta
Si se detecta esta actividad, aísle el punto final afectado, recopile imágenes de memoria y disco, y busque Installer.exe, dw.exe, y secciones sospechosas .bun . Bloquee los dominios y URLs de comando y control identificados en el perímetro de la red. Despliegue detecciones de puntos finales para los comandos PowerShell observados y patrones de API de Win32. Rote las credenciales expuestas y monitoree los sistemas afectados por signos de minería de criptomonedas no autorizada.
graph TB %% Definiciones de clases classDef technique fill:#ffcc99 classDef action fill:#99ccff %% Nodos node_initial_access[«<b>Acceso inicial</b><br/><b>T1036.008 Mascaramiento: Tipo de archivo</b>: ZIP malicioso disfrazado como tipo de archivo benigno.<br/><b>T1204.002 Ejecución por usuario: Archivo malicioso</b>: La víctima ejecuta el archivo descargado.»] class node_initial_access technique node_obfuscated_loader[«<b>Cargador ofuscado</b><br/><b>T1027.016 Inserción de código basura</b>: Inserta JavaScript irrelevante para ocultar la lógica maliciosa.<br/><b>T1027.008 Eliminación de partes del payload</b>: Elimina código no esencial para reducir tamaño y evadir análisis.»] class node_obfuscated_loader technique node_discovery[«<b>Descubrimiento</b><br/><b>T1082 Descubrimiento de información del sistema</b>: Recopila sistema operativo, hardware y software.<br/><b>T1016 Descubrimiento de configuración de red</b>: Enumera adaptadores, direcciones IP e información de rutas.»] class node_discovery technique node_credential_access[«<b>Acceso a credenciales</b><br/><b>T1555.003 Credenciales de navegadores web</b>: Extrae contraseñas almacenadas y datos de autocompletar.<br/><b>T1550.004 Uso de material de autenticación alternativo</b>: Roba cookies de sesión web para acceso autenticado.»] class node_credential_access technique node_c2[«<b>Mando y control</b>: Recupera semilla de descifrado AES y payload cifrado desde servidor remoto.»] class node_c2 action node_execution[«<b>Ejecución</b><br/><b>T1620 Carga de código reflectivo</b>: Carga el payload cifrado directamente en memoria sin escribir en disco.<br/><b>T1055.009 Inyección de proceso: memoria de proceso</b>: Inyecta el código reflejado en un proceso en ejecución.»] class node_execution technique node_persistence[«<b>Persistencia</b><br/><b>T1053 Tarea programada</b>: Crea una tarea programada para ejecutar el payload malicioso de forma recurrente.»] class node_persistence technique %% Conexiones node_initial_access –>|lleva a| node_obfuscated_loader node_obfuscated_loader –>|lleva a| node_discovery node_discovery –>|lleva a| node_credential_access node_credential_access –>|lleva a| node_c2 node_c2 –>|lleva a| node_execution node_execution –>|lleva a| node_persistence
Flujo de ataque
Detecciones
Comando y Control Sospechoso por Solicitud DNS con Dominio de Nivel Superior (TLD) Inusual (via dns)
Ver
Posibles Comprobaciones de Evasión (a través de PowerShell)
Ver
Comunicaciones de Búsqueda de Dominio IP Posibles (a través de dns)
Ver
IOCs (HashSha256) para detectar: Los atacantes adoptan el entorno de ejecución de JavaScript Bun para propagar NWHStealer
Ver
Detectar Cargador NWHStealer por Autoinyección en JavaScript [Creación de Procesos en Windows]
Ver
Detección de Comandos Anti-Virtualización de PowerShell de NWHStealer [Windows Powershell]
Ver
Ejecución de Simulación
Prerrequisito: La Verificación Previa de Telemetría y Línea de Base debe haber pasado.
Racional: Esta sección detalla la ejecución precisa de la técnica del adversario (TTP) diseñada para activar la regla de detección. Los comandos y la narrativa DEBEN reflejar directamente los TTP identificados y apuntar a generar la telemetría exacta esperada por la lógica de detección. Ejemplos abstractos o no relacionados llevarán a un diagnóstico erróneo.
-
Narrativa de Ataque y Comandos:
- Acceso Inicial: El atacante entrega un archivo JavaScript malicioso (
loader.js) en el sistema de la víctima y lo ejecuta usando el bun entorno de ejecución (bun loader.js). - Rutina de Autoinyección: El código JavaScript llama a las APIs nativas de Win32 a través de un asistente de PowerShell que usa Add‑Type para definir firmas P/Invoke para
VirtualAlloc,VirtualProtect, yLoadLibraryA. - Asignación de Memoria:
VirtualAllocreserva una región RWX del tamaño del shellcode embebido. - Inyección de Shellcode: El script de PowerShell copia el shellcode decodificado en base64 en la memoria asignada utilizando
Marshal.Copy. - Cambio de Permisos:
VirtualProtectcambia la protección de la página a PAGE_EXECUTE_READ. - Ejecución de la Carga Útil:
LoadLibraryAse invoca en un DLL malicioso que reside solo en memoria (el encabezado del DLL se escribe en la región asignada, luego se pasa la dirección aLoadLibraryA). - Sin Nuevo Hilo: El atacante evita deliberadamente llamar a
CreateThread; el DllMain del DLL se ejecuta en el contexto del proceso actual, satisfaciendo la cláusula de exclusión de la regla.
- Acceso Inicial: El atacante entrega un archivo JavaScript malicioso (
-
Script de Prueba de Regresión:
# ------------------------------------------------- # NWHStealer JavaScript Loader – Demo de Autoinyección # ------------------------------------------------- # Este script simula el comportamiento del cargador real NWHStealer. # Llama deliberadamente a VirtualAlloc, VirtualProtect y LoadLibraryA # sin invocar CreateThread. # 1. Definir firmas de API de Win32 $sig = @" using System; using System.Runtime.InteropServices; public class Win32 { [DllImport("kernel32.dll", SetLastError=true)] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect); [DllImport("kernel32.dll", CharSet=CharSet.Ansi, SetLastError=true)] public static extern IntPtr LoadLibraryA(string lpFileName); } "@ Add-Type $sig # 2. Asignar memoria ejecutable (RWX) $size = 0x1000 $MEM_COMMIT = 0x1000 $PAGE_EXECUTE_READWRITE = 0x40 $mem = [Win32]::VirtualAlloc([IntPtr]::Zero, $size, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) if ($mem -eq [IntPtr]::Zero) { throw "VirtualAlloc failed" } # 3. Ejemplo de shellcode (MessageBox) – codificado en base64 para legibilidad $b64 = "AQAAANAAAABAAEAAAABAAAAAgAAAAEAAABWAAAAAQAAAAIAAAD/////AQAAAAAAAAA=" $shellcode = [Convert]::FromBase64String($b64) # 4. Copiar shellcode en la región asignada [System.Runtime.InteropServices.Marshal]::Copy($shellcode, 0, $mem, $shellcode.Length) # 5. Cambiar protección a EXECUTE_READ $oldProtect = 0 $PAGE_EXECUTE_READ = 0x20 $ok = [Win32]::VirtualProtect($mem, $size, $PAGE_EXECUTE_READ, [ref]$oldProtect) if (-not $ok) { throw "VirtualProtect failed" } # 6. Cargar el "DLL" en memoria (aquí simplemente llamamos a LoadLibraryA en kernel32 como marcador de posición) # En el cargador real, esto sería un DLL personalizado escrito en $mem. $hLib = [Win32]::LoadLibraryA("kernel32.dll") if ($hLib -eq [IntPtr]::Zero) { throw "LoadLibraryA failed" } Write-Host "Pasos de autoinyección completados – el proceso ahora debería ser señalado por la regla de detección." # ------------------------------------------------- -
Comandos de Limpieza:
# Terminar la instancia de PowerShell que realizó la inyección Stop-Process -Id $PID -Force # (Opcional) Si un DLL personalizado fue escrito en disco para pruebas, elimínelo Remove-Item -Path "$env:TEMPmalicious.dll" -ErrorAction SilentlyContinue
Validación Post-Ejecución
-
Confirmar Generación de Alerta: Ejecute la siguiente consulta KQL para verificar que la regla se activó:
// Regla de detección: VirtualAlloc/VirtualProtect/LoadLibraryA sin CreateThread Sysmon | where EventID == 1 | where CallTrace contains "VirtualAlloc" or CallTrace contains "VirtualProtect" or CallTrace contains "LoadLibraryA" | where not(CallTrace contains "CreateThread") | project TimeGenerated, Process, CallTrace, EventID -
Verificar Ausencia de Falsos Positivos: Ejecute nuevamente el comando benigno de Notepad y asegúrese de que la consulta devuelva cero resultados para esa ejecución.
Fin del Informe