A Elastic Security Labs divulgou as regras iniciais de triagem e detecção para a vulnerabilidade na cadeia de suprimentos da Axios. Esta é uma análise detalhada do RAT e das cargas úteis.
Introdução
A Elastic Security Labs identificou uma vulnerabilidade na cadeia de suprimentos do pacote npm axios, um dos pacotes mais utilizados no ecossistema JavaScript, com aproximadamente 100 milhões de downloads semanais. O atacante comprometeu uma conta de mantenedor e publicou versões com backdoor que distribuíam um Trojan de Acesso Remoto multiplataforma para sistemas macOS, Windows e Linux por meio de um gancho malicioso de pós-instalação.
Principais conclusões
- Uma conta de mantenedor do npm comprometida (jasonsaayman) foi usada para publicar duas versões maliciosas do cliente HTTP Axios, amplamente utilizado — 1.14.1 (marcada como "latest") e 0.30.4 (marcada como "legacy") — o que significa que um comando padrão `npm install axios` resultava em um pacote com backdoor.
- O JavaScript malicioso implementa implantes de estágio 2 específicos para cada plataforma: macOS, Windows e Linux.
- Todas as três cargas úteis de estágio 2 são implementações da mesma RAT — protocolo C2 idêntico, conjunto de comandos, cadência de beacons e user-agent falsificado, escritas em PowerShell (Windows), C++ (macOS) e Python (Linux).
- O dropper realiza uma limpeza antiforense excluindo-se a si mesmo e substituindo seu arquivo package.json por uma cópia limpa, apagando assim os vestígios do gatilho pós-instalação.
node_modules
Preâmbulo
Em 30 de março de 2026, a Elastic Security Labs detectou uma violação da cadeia de suprimentos que tinha como alvo o pacote npm axios por meio de monitoramento automatizado da cadeia de suprimentos. O atacante obteve o controle da conta npm pertencente a jasonsaayman, um dos principais mantenedores do projeto, e publicou duas versões com backdoor em um intervalo de 39 minutos.
O pacote axios é uma das bibliotecas de clientes HTTP mais utilizadas no ecossistema JavaScript. No momento da descoberta, tanto as tags de distribuição mais recentes quanto as antigas apontavam para versões comprometidas, garantindo que a maioria das novas instalações obtivesse uma versão com backdoor.
As versões maliciosas introduziram uma única nova dependência: plain-crypto-js, um pacote criado especificamente para esse fim, cujo gancho de pós-instalação baixava e executava silenciosamente implantes RAT de estágio 2 específicos da plataforma a partir de sfrclak[.]com:8000.
O que torna esta campanha notável, além do seu impacto direto, é a ferramenta de segunda fase. O atacante implantou três implementações paralelas do mesmo RAT — uma para Windows, uma para macOS e uma para Linux — todas compartilhando um protocolo C2, estrutura de comando e comportamento de beacon idênticos. Não se trata de três ferramentas diferentes; é uma única estrutura de implante multiplataforma com implementações nativas da plataforma.
A Elastic Security Labs registrou um aviso de segurança no GitHub para o repositório axios em 31 de março, 2026 às 01:50 da manhã UTC para coordenar a divulgação e garantir que os mantenedores e o registro npm pudessem agir nas versões comprometidas.
Assim que a comunidade alertou sobre a vulnerabilidade nas redes sociais, o Elastic Security Labs compartilhou publicamente as primeiras descobertas para ajudar os profissionais de segurança a responderem em tempo real.
Este artigo aborda toda a cadeia de ataque: desde a violação da cadeia de suprimentos no nível do npm, passando pelo dropper ofuscado, até a arquitetura do RAT multiplataforma e as diferenças significativas entre suas três variantes.
Visão geral da campanha
O compromisso é evidente nos metadados do registro npm. O e-mail do mantenedor mudou de jasonsaayman@gmail[.]com — presente em todas as versões legítimas anteriores — para ifstap@proton[.]me nas versões maliciosas. O método de publicação também mudou:
| Versão | Publicado por | Method | Proveniência |
|---|---|---|---|
axios@1.14.0 (legítimo) | jasonsaayman@gmail[.]com | GitHub Actions OIDC | atestados de proveniência SLSA |
axios@1.14.1 (comprometido) | ifstap@proton[.]me | Publicação direta via CLI | Nenhuma |
axios@0.30.4 (comprometido) | ifstap@proton[.]me | Publicação direta via CLI | Nenhuma |
A mudança de um fluxo de publicação OIDC confiável com proveniência SLSA para uma publicação CLI direta com um e-mail alterado é um claro indicador de acesso não autorizado.
Linha do tempo
- 2026-02-18 17:19 UTC —
axios@0.30.3publicado legitimamente porjasonsaayman@gmail[.]com - 2026-03-27 19:01 UTC —
axios@1.14.0publicado legitimamente via GitHub Actions OIDC - 2026-03-30 05:57 UTC —
plain-crypto-js@4.2.0publicado pornrwise(nrwise@proton.me) — isca limpa para construir o histórico do registro - 2026-03-30 23:59 UTC —
plain-crypto-js@4.2.1publicado pornrwise— versão maliciosa com backdoorpostinstall - 2026-03-31 00:21 UTC —
axios@1.14.1publicado por conta comprometida — marcado comlatest - 2026-03-31 01:00 UTC —
axios@0.30.4publicado por conta comprometida — marcado comlegacy
Pacotes afetados
axios@1.14.1— Malicioso, etiquetado comolatestno momento da descobertaaxios@0.30.4— Malicioso, etiquetado comolegacyno momento da descobertaplain-crypto-js@4.2.0— Isca limpa, publicada para construir o histórico do registroplain-crypto-js@4.2.1— Veículo malicioso de entrega de carga (postinstallbackdoor)
Versões seguras: axios@1.14.0 (última versão legítima 1.x com procedência SLSA) e axios@0.30.3 (última versão legítima 0.30.x ).
O atacante marcou tanto os canais mais recentes quanto os legados, maximizando o alcance do ataque em projetos que utilizam a API axios atual ou a legada.
Análise de código
Etapa 1: O dropper plain-crypto-js
Toda a cadeia de distribuição depende do gancho de ciclo de vida postinstall do npm. A instalação de qualquer versão comprometida do axios puxa plain-crypto-js@^4.2.1 como dependência, que declara:
"scripts": {
"postinstall": "node setup.js"
}
Isso faz com que o arquivo setup.js seja executado automaticamente durante a instalação do npm — sem necessidade de interação do usuário.
O arquivo setup.js utiliza um esquema de codificação de duas camadas para ocultar seu comportamento:
- Camada 1: Inversão da string seguida de decodificação em Base64
- Camada 2: Cifra XOR usando a chave OrDeR_7077 com um índice dependente da posição (7 * i² % 10)
Todas as strings críticas, nomes de módulos, URLs e comandos do shell são armazenados em um array codificado stq[] e decodificados em tempo de execução. O conteúdo decodificado revela a infraestrutura operacional:
Entrega específica da plataforma
Após decodificar sua tabela de strings, o dropper verifica os.platform() e ramifica para uma das três rotinas de entrega. Cada um envia uma solicitação HTTP POST para http://sfrclak[.]com:8000/6202033 com um corpo específico da plataforma — packages.npm.org/product0 (macOS), packages.npm.org/product1 (Windows), packages.npm.org/product2 (Linux) — permitindo que o C2 forneça a carga útil correta a partir de um único ponto de extremidade. O packages.npm.org/ O prefixo é uma tentativa deliberada de fazer com que o tráfego de saída pareça uma comunicação benigna do registro npm nos logs de rede:
| Plataforma | Método de entrega | Localização da Etapa 2 | Disfarce |
|---|---|---|---|
| macOS | AppleScript via osascript baixa binário com curl | /Library/Caches/com.apple.act.mond | daemon do sistema Apple |
| Windows | Downloads de VBScript .ps1 via curl, executa via PowerShell renomeado (%PROGRAMDATA%\wt.exe) | %TEMP%\6202033.ps1 (transitório) | Terminal do Windows |
| Linux | Download direto via curl e execução em Python 3 | /tmp/ld.py | Nenhuma |
Antiforense
O conta-gotas realiza duas ações de limpeza:
- Autoexclusão: setup.js se remove através de fs.unlink(__filename)
- Substituição do manifesto do pacote: Um arquivo limpo chamado package.md (contendo uma configuração benigna da versão 4.2.0 sem nenhum gancho pós-instalação) é renomeado para package.json. sobrescrevendo a versão maliciosa
A inspeção do arquivo node_modules/plain-crypto-js/package.json após o incidente não revelou nenhum vestígio do gatilho postinstall. O arquivo setup.js malicioso foi removido. Somente o arquivo de bloqueio e os registros de auditoria do npm retêm evidências.
Etapa 2: RAT multiplataforma
As três cargas úteis do estágio 2: PowerShell para Windows, C++ compilado para macOS e Python para Linux não são três ferramentas diferentes. São três implementações da mesma especificação RAT, compartilhando um protocolo C2 idêntico, conjunto de comandos, formato de mensagem e comportamento operacional. A consistência indica fortemente um único desenvolvedor ou uma equipe bem coordenada trabalhando a partir de um documento de projeto compartilhado.
Arquitetura compartilhada
As seguintes propriedades são idênticas em todas as três variantes:
- Transporte C2: HTTP POST
- Codificação do corpo: JSON codificado em Base64
- Agente do usuário:
mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0) - Intervalo do sinalizador: 60 segundos
- UID da sessão: sequência alfanumérica aleatória de 16 caracteres, gerada a cada execução.
- Tipos de mensagens de saída:
FirstInfo,BaseInfo,CmdResult - Tipos de comandos de entrada:
kill,peinject,runscript,rundir - Tipos de comando de resposta:
rsp_kill,rsp_peinject,rsp_runscript,rsp_rundir
A string de agente de usuário falsificada do IE8/Windows XP é particularmente notável, sendo anacrônica em todas as três plataformas, e sua presença em um host macOS ou Linux é um forte indicador de detecção.
Inicialização e reconhecimento
Na inicialização, cada variante:
- Gera um UID de sessão — 16 caracteres alfanuméricos aleatórios, incluídos em todas as mensagens C2 subsequentes.
- Detecta o sistema operacional e a arquitetura — reporta identificadores específicos da plataforma (ex.: windows_x64, macOS, linux_x64)
- Enumera os diretórios iniciais de interesse (perfil do usuário, documentos, área de trabalho, diretórios de configuração).
- Envia um beacon FirstInfo contendo o UID, o identificador do sistema operacional e um instantâneo do diretório.
Após a inicialização, o implante entra no loop principal. O primeiro pulso do BaseInfo inclui um perfil completo do sistema. As mesmas categorias de dados são coletadas em todas as plataformas, embora as APIs subjacentes sejam diferentes:
| Dados coletados | Fonte do Windows | Fonte macOS | Fonte Linux |
|---|---|---|---|
| Hostname | %COMPUTERNAME% variável de ambiente | obternome_do_host() | /proc/sys/kernel/nome_do_host |
| Nome de usuário | %USERNAME% variável de ambiente | getuid() + getpwuid() | os.getlogin() |
| Versão do SO | WMI / registro | sysctlbyname("kern.osprodutoversão") | plataforma.sistema() + plataforma.release() |
| Fuso horário | Fuso horário do sistema | localtime_r() | data e hora. fuso horário |
| Tempo de inicialização | Tempo de atividade do sistema | sysctl("kern.boottime") | /proc/tempo de atividade |
| Data de instalação | Registro / WMI | stat("/") ou sysctl | ctime de /var/log/installer ou /var/log/dpkg.log |
| Modelo de hardware | WMI | sysctlbyname("hw.model") | /sys/class/dmi/id/nome_do_produto |
| tipo de CPU | WMI | sysctlbyname() | plataforma.máquina() |
| Process list | PID completo, sessão, nome, caminho | popen("ps") (até 1000) | Enumeração completa de /proc (PID, PPID, usuário, linha de comando) |
Os batimentos cardíacos subsequentes são leves, contendo apenas um registro de data e hora para confirmar que o implante está ativo.
despacho de comando
A resposta do C2 é analisada como JSON, e o campo "type" determina a ação. Todas as três variantes implementam os mesmos quatro comandos:
matar — Autoextermínio. Envia um reconhecimento rsp_kill e encerra a execução. O mecanismo de persistência da variante do Windows (chave de registro + arquivo em lote) sobrevive ao comando kill, a menos que seja explicitamente removido; as variantes do macOS e do Linux não possuem mecanismo de persistência próprio.
runscript — Execução de script/comando. O comando de interação principal do operador. Aceita um campo Script (código a ser executado) e um campo Param (argumentos). Quando o Script está vazio, o Param é executado diretamente como um comando. O mecanismo de execução é nativo da plataforma:
| Plataforma | Mecanismo de Execução |
|---|---|
| Windows | PowerShell com -NoProfile -ep Bypass |
| macOS | AppleScript via /usr/bin/osascript |
| Linux | Shell via subprocess.run(shell=True) ou Python via python3 -c |
peinject — Entrega de carga binária. Apesar da nomenclatura centrada no Windows ("PE inject"), todas as três plataformas implementam isso como uma forma de inserir e executar payloads binários:
| Plataforma | Implementation |
|---|---|
| Windows | Carregamento reflexivo de assemblies .NET via [System.Reflection.Assembly]::Load() |
| macOS | Decodifica e extrai um arquivo binário usando Base64, executando-o com parâmetros fornecidos pelo operador. |
| Linux | Decodifica um binário em Base64 para /tmp/. string de 6 caracteres> (arquivo oculto), executado via subprocess.Popen(). |
A implementação do Windows possui execução em memória sem descarte de arquivos, mas sem desabilitar o AMSI, o que certamente causará problemas no carregamento do assembly. As variantes para macOS e Linux adotam a abordagem mais simples de gravar um arquivo binário no disco e executá-lo diretamente.
rundir — Enumeração de diretórios. Aceita caminhos e retorna listagens detalhadas de arquivos (nome, tamanho, tipo, data e hora de criação/modificação, número de filhos para diretórios). Permite ao operador navegar interativamente pelo sistema de arquivos.
Resumo das capacidades
| Capacidade | Windows (PowerShell) | macOS (C++) | Linux (Python) |
|---|---|---|---|
| Persistência | Chave de execução do Registro + arquivo .bat oculto | Nenhuma | Nenhuma |
| Execução de script | PowerShell | AppleScript via osascript | Shell ou Python embutido |
| Injeção binária | Injeção de carga .NET reflexiva no cmd.exe | Binário drop + executar | Arquivo binário copiado para /tmp/ + executar |
| Antiforense | Janelas ocultas, limpeza de arquivos temporários | Arquivo temporário oculto .scpt | Arquivos ocultos em /tmp/.XXXXXX |
Atribuição
O binário Mach-O para macOS entregue pelo gancho de pós-instalação plain-crypto-js apresenta uma sobreposição significativa com o WAVESHAPER, um backdoor em C++ rastreado pela Mandiant e atribuído ao UNC1069, um cluster de ameaças ligado à Coreia do Norte.
Conclusão
Esta campanha demonstra a atratividade contínua do ecossistema npm como vetor de ataque à cadeia de suprimentos. Ao comprometer uma única conta de mantenedor em um dos pacotes mais importantes do ecossistema JavaScript, o atacante obteve um mecanismo de distribuição com alcance potencial em milhões de ambientes.
O indicador de detecção mais confiável do conjunto de ferramentas é também sua escolha de design mais curiosa: a string do agente do usuário do IE8/Windows XP codificada de forma idêntica em todas as três variantes da plataforma. Embora forneça uma impressão digital de protocolo consistente para roteamento do lado do servidor C2, é trivialmente detectável em qualquer rede moderna — e é uma anomalia imediata em hosts macOS e Linux.
A Elastic Security Labs continuará monitorando esse cluster de atividades e atualizará esta publicação com quaisquer descobertas adicionais.
MITRE ATT&CK
A Elastic usa a estrutura MITRE ATT&CK para documentar táticas, técnicas e procedimentos comuns que ameaças persistentes avançadas usam contra redes corporativas.
Táticas
As táticas representam o porquê de uma técnica ou subtécnica. É o objetivo tático do adversário: a razão para executar uma ação.
- Acesso inicial
- Execução
- Persistência
- Defense Evasion
- Descoberta
- Command and Control (Comando e controle)
Técnicas
Técnicas representam como um adversário atinge um objetivo tático executando uma ação.
- Compromisso na cadeia de suprimentos: dependências de software comprometidas
- Interpretador de Comando e Script: JavaScript
- Interpretador de comando e script: PowerShell
- Interpretador de comandos e scripts: AppleScript
- Command and Scripting Interpreter: Unix Shell
- Command and Scripting Interpreter: Python
- Execução automática na inicialização ou no logon: Chaves de execução do Registro
- Arquivos ou informações ofuscadas
- Mascarando
- Arquivos e diretórios ocultos
- Injeção de processo
- Indicator Removal: File Deletion
- Descoberta de informações do sistema
- Descoberta de Processos
- Descoberta de arquivos e diretórios
- Application Layer Protocol: Web Protocols
- Porta não padrão
- Codificação de dados: Codificação padrão
- Transferência de ferramenta de entrada
Observações
Os seguintes observáveis foram discutidos nesta pesquisa.
| Observável | Tipo | Nome | Referência |
|---|---|---|---|
617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101 | SHA-256 | 6202033.ps1 | Carga útil do Windows |
92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a | SHA-256 | com.apple.act.mond | carga útil do MacOS |
fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf | SHA-256 | ld.py | Carga útil Linux |
sfrclak[.]com | Domínio | C2 | |
142.11.206[.]73 | endereço-ipv4 | C2 |
Referências
Os seguintes itens foram referenciados ao longo da pesquisa acima:
