SOC Prime Bias: Médio

08 May 2026 15:33 UTC

NWHStealer Disseminado Através do Tempo de Execução Bun JavaScript

Author Photo
SOC Prime Team linkedin icon Seguir
NWHStealer Disseminado Através do Tempo de Execução Bun JavaScript
shield icon

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.

Fluxo de Ataque

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:

    1. 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).
    2. 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, e LoadLibraryA.
    3. Alocação de Memória: VirtualAlloc reserva uma região RWX dimensionada para o shellcode embutido.
    4. Injeção de Shellcode: O script PowerShell copia o shellcode decodificado em base64 para a memória alocada usando Marshal.Copy.
    5. Mudança de Permissão: VirtualProtect altera a proteção da página para PAGE_EXECUTE_READ.
    6. 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 para LoadLibraryA).
    7. 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.
  • 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

  1. 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
  2. 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