NWHStealer Disseminado Através do Tempo de Execução Bun JavaScript
Detection stack
- AIDR
- Alert
- ETL
- Query
Resumo
O artigo explica como atores de ameaça estão usando o runtime JavaScript Bun para entregar o infostealer NWHStealer baseado em Rust. Arquivos ZIP maliciosos contêm um instalador primário que lança um carregador JavaScript empacotado com Bun junto com um carregador secundário chamado dw.exe. O componente JavaScript executa verificações anti-máquina virtual, entra em contato com a infraestrutura de comando e controle, descriptografa uma carga adicional e abusa das APIs nativas do Windows para injetar o stealer na memória. Para reduzir a suspeita, a campanha esconde arquivos maliciosos atrás de plataformas de hospedagem legítimas como o GitHub, MediaFire e SourceForge.
Investigação
Pesquisadores descobriram que o Bun foi usado para empacotar JavaScript malicioso dentro da seção .bun do carregador. Dois scripts, sysreq.js and memload.js, cuidavam das verificações de ambiente e da comunicação com a infraestrutura do atacante. O carregador recuperou dados de configuração e cargas criptografadas de domínios como silent-harvester.cc, os descriptografou com AES-256-CBC e os injetou através de chamadas de API Win32. A carga final era o NWHStealer, que rouba credenciais, dados de navegador e informações de carteiras de criptomoeda, podendo também iniciar atividades adicionais de mineração.
Mitigação
Usuários devem evitar baixar executáveis de sites não confiáveis e verificar assinaturas de instaladores antes da execução. Equipes de segurança devem monitorar atividades incomuns do runtime Bun, consultas PowerShell CIM usadas para verificações de virtualização e chamadas de API suspeitas como VirtualAlloc and LoadLibraryA. As organizações também devem bloquear os domínios maliciosos conhecidos e aplicar políticas de execução com o menor privilégio para limitar abusos.
Resposta
Se esta atividade for detectada, isole o endpoint afetado, colete imagens de memória e disco, e procure por Installer.exe, dw.exe, e seções suspeitas .bun . Bloqueie os domínios e URLs de comando e controle identificados no perímetro da rede. Desdobre detecções de endpoint para os comandos PowerShell observados e padrões de API Win32. Gire credenciais expostas e monitore sistemas afetados para sinais de mineração de criptomoeda não autorizada.
graph TB %% Definições de classes classDef technique fill:#ffcc99 classDef action fill:#99ccff %% Nós node_initial_access[“<b>Acesso inicial</b><br/><b>T1036.008 Mascaramento: Tipo de ficheiro</b>: ZIP malicioso disfarçado como tipo de ficheiro benigno.<br/><b>T1204.002 Execução pelo utilizador: Ficheiro malicioso</b>: A vítima executa o ficheiro descarregado.”] class node_initial_access technique node_obfuscated_loader[“<b>Loader ofuscado</b><br/><b>T1027.016 Inserção de código lixo</b>: Insere JavaScript irrelevante para ocultar a lógica maliciosa.<br/><b>T1027.008 Remoção de partes do payload</b>: Remove código não essencial para reduzir tamanho e evitar análise.”] class node_obfuscated_loader technique node_discovery[“<b>Descoberta</b><br/><b>T1082 Descoberta de informações do sistema</b>: Recolhe sistema operativo, hardware e software.<br/><b>T1016 Descoberta de configuração de rede</b>: Enumera adaptadores, endereços IP e informação de routing.”] class node_discovery technique node_credential_access[“<b>Acesso a credenciais</b><br/><b>T1555.003 Credenciais de navegadores</b>: Extrai passwords guardadas e dados de autopreenchimento.<br/><b>T1550.004 Uso de material de autenticação alternativo</b>: Recolhe cookies de sessão web para acesso autenticado.”] class node_credential_access technique node_c2[“<b>Comando e controlo</b>: Obtém seed de desencriptação AES e payload encriptado de servidor remoto.”] class node_c2 action node_execution[“<b>Execução</b><br/><b>T1620 Carregamento de código refletivo</b>: Carrega payload encriptado diretamente em memória sem escrita em disco.<br/><b>T1055.009 Injeção de processo: memória</b>: Injeta código refletido num processo em execução.”] class node_execution technique node_persistence[“<b>Persistência</b><br/><b>T1053 Tarefa agendada</b>: Cria tarefa agendada para executar o payload malicioso de forma recorrente.”] class node_persistence technique %% Ligações node_initial_access –>|leva a| node_obfuscated_loader node_obfuscated_loader –>|leva a| node_discovery node_discovery –>|leva a| node_credential_access node_credential_access –>|leva a| node_c2 node_c2 –>|leva a| node_execution node_execution –>|leva a| node_persistence
Fluxo de Ataque
Detecções
Comando e Controle Suspeito por Solicitação de DNS de Domínio de Nível Superior (TLD) Incomum (via dns)
Ver
Verificações Possíveis de Evasão (via powershell)
Ver
Tentativa de Comunicação de Domínio de Pesquisa de IP Possível (via dns)
Ver
IOCs (HashSha256) para detectar: Atacantes adotam o runtime JavaScript Bun para espalhar o NWHStealer
Ver
Detectar Autoinjeção do Carregador JavaScript NWHStealer [Criação de Processo Windows]
Ver
Detecção de Comandos Anti-Virtualização PowerShell do NWHStealer [Windows Powershell]
Ver
Execução de Simulação
Pré-requisito: A Verificação Pré‑Voo Telemetria & Baseline deve ter sido aprovada.
Justificativa: Esta seção detalha a execução precisa da técnica do adversário (TTP) projetada para acionar a regra de detecção. Os comandos e a narrativa DEVEM refletir diretamente os TTPs identificados e visam gerar a telemetria exata esperada pela lógica de detecção. Exemplos abstratos ou não relacionados levarão a um diagnóstico incorreto.
-
Narrativa & Comandos do Ataque:
- Acesso Inicial: O atacante entrega um arquivo JavaScript malicioso (
loader.js) no sistema da vítima e o executa usando o bun runtime (bun loader.js). - Rotina de Autoinjeção: O código JavaScript chama APIs Win32 nativas via um auxiliar PowerShell que usa Add‑Type para definir assinaturas P/Invoke para
VirtualAlloc,VirtualProtect, eLoadLibraryA. - Alocação de Memória:
VirtualAllocreserva uma região RWX dimensionada para o shellcode embutido. - Injeção de Shellcode: O script PowerShell copia o shellcode decodificado em base64 para a memória alocada usando
Marshal.Copy. - Mudança de Permissão:
VirtualProtectaltera a proteção da página para PAGE_EXECUTE_READ. - Execução de Carga:
LoadLibraryAé invocada em uma DLL maliciosa que reside apenas em memória (o cabeçalho da DLL é escrito na região alocada, então o endereço é passado paraLoadLibraryA). - Sem Nova Thread: O atacante evita deliberadamente chamar
CreateThread; o DllMain da DLL é executado no contexto do processo atual, satisfazendo a cláusula de exclusão da regra.
- Acesso Inicial: O atacante entrega um arquivo JavaScript malicioso (
-
Script de Teste de Regressão:
# ------------------------------------------------- # NWHStealer JavaScript Loader – Demo de Autoinjeção # ------------------------------------------------- # Este script imita o comportamento do carregador real NWHStealer. # Ele chama deliberadamente VirtualAlloc, VirtualProtect, e LoadLibraryA # sem invocar CreateThread. # 1. Defina assinaturas de API 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. Alocar memória executável (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. Shellcode de exemplo (MessageBox) – codificado em base64 para legibilidade $b64 = "AQAAANAAAABAAEAAAABAAAAAgAAAAEAAABWAAAAAQAAAAIAAAD/////AQAAAAAAAAA=" $shellcode = [Convert]::FromBase64String($b64) # 4. Copiar shellcode na região alocada [System.Runtime.InteropServices.Marshal]::Copy($shellcode, 0, $mem, $shellcode.Length) # 5. Alterar proteção para 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. Carregar a "DLL" na memória (aqui simplesmente chamamos LoadLibraryA em kernel32 como um espaço reservado) # No carregador real, esta seria uma DLL personalizada escrita em $mem. $hLib = [Win32]::LoadLibraryA("kernel32.dll") if ($hLib -eq [IntPtr]::Zero) { throw "LoadLibraryA failed" } Write-Host "Passos de autoinjeção concluídos – o processo agora deve ser sinalizado pela regra de detecção." # ------------------------------------------------- -
Comandos de Limpeza:
# Terminar a instância do PowerShell que realizou a injeção Stop-Process -Id $PID -Force # (Opcional) Se uma DLL personalizada foi escrita no disco para teste, remova-a Remove-Item -Path "$env:TEMPmalicious.dll" -ErrorAction SilentlyContinue
Validação Pós‑Execução
-
Confirme a Geração de Alerta: Execute a seguinte consulta KQL para verificar se a regra foi acionada:
// Regra de Detecção: VirtualAlloc/VirtualProtect/LoadLibraryA sem CreateThread Sysmon | onde EventID == 1 | onde CallTrace contém "VirtualAlloc" ou CallTrace contém "VirtualProtect" ou CallTrace contém "LoadLibraryA" | onde não(CallTrace contém "CreateThread") | projeto TimeGenerated, Process, CallTrace, EventID -
Verifique se Não há Falso Positivo: Re‑execute o comando benigno do Notepad e assegure-se que a consulta retorne zero resultados para essa execução.
Fim do Relatório