1 pontos por GN⁺ 4 시간 전 | Ainda não há comentários. | Compartilhar no WhatsApp
  • No LinkedIn, após oferecer uma vaga de engenheiro de software, foi enviado um repositório privado do GitHub disfarçado de tarefa legítima de React/Web3; ao ser executado, um malware em JavaScript escondido em tailwind.config.js roda no computador do desenvolvedor
  • O arquivo de configuração de 30.987 bytes escondia 27 KB de código ofuscado depois de milhares de espaços; ele baixava de um servidor remoto uma carga útil de segundo estágio criptografada com AES-256-CBC, salvava em %TEMP%\pack e então a executava com node pack
  • Em uma VM isolada com Windows 11 ARM, observada por cerca de 10 minutos, a carga útil ativou quatro componentes: backdoor de controle remoto, ladrão de navegador e carteiras, scanner recursivo de arquivos e monitor de área de transferência
  • Via Socket.IO, ela controlava terminal, SSH, tela, teclado e mouse, e coletava bancos de dados do Chromium, armazenamento de extensões de carteiras, chaves SSH, código-fonte, arquivos de configuração etc.; na porta de upload de arquivos, foram observadas 2.588 requisições
  • Repositórios de tarefas enviados por desconhecidos devem ser tratados como código não confiável e inspecionados em uma VM ou contêiner descartável sem perfis reais de navegador, chaves SSH, credenciais de nuvem ou carteiras; se houver infecção, após bloquear a rede e preservar evidências, é preciso trocar também as informações secretas

Repositório disfarçado de tarefa normal de recrutamento Web3

  • O usuário do LinkedIn Wayan Adrian ofereceu uma vaga de engenheiro de software na shrapnel.com e enviou como tarefa o repositório privado do GitHub tech-active-workplace-frontend-main, da conta yevhen-o
  • A plataforma de campanha de NFT chamada BLAIEXS parecia, por fora, um projeto React/Web3 comum
    • O frontend em React oferecia marca, painel administrativo, gerenciamento de campanhas, fluxo de criação de NFTs etc.
    • A API em Express tratava autenticação, dados de dashboard, verificação KYB, criação e resgate de NFTs, upload de arquivos e alguns endpoints stub
    • O script de seed criava contas de demonstração de superadmin, marca e consumidor, a campanha Demo NFT Drop e o NFT Demo Collectible, com 100 unidades disponíveis
  • O escopo real da tarefa era uma simples funcionalidade de exibição de rede da MetaMask
    • Implementar em src/utils/ethereum.js a função assíncrona getChainId() para chamar eth_chainId e retornar o valor hexadecimal parseado ou null
    • Implementar no mesmo arquivo getNetworkLabel(chainId) para encontrar, no objeto NETWORKS existente, um nome de rede legível
    • Modificar src/components/Wallet/ConnectWalletButton.js para chamar as duas funções após a conexão da carteira
  • Após concluir a implementação e executar o servidor de desenvolvimento, ele demorou muito para iniciar; percebendo algo estranho, o usuário desconectou o cabo de internet

Código executável escondido em tailwind.config.js

  • No ls -la, tailwind.config.js tinha 30.987 bytes, mas no editor apareciam apenas 97 linhas; o mesmo tamanho foi confirmado com wc -c
  • Por volta da linha 95, havia um grande blob de JavaScript difícil de ler escondido depois de milhares de espaços
  • O código usava técnicas comuns de ofuscação de JavaScript
    1. Armazenar strings importantes em um grande array
    2. Rotacionar o array até que o checksum batesse
    3. Esconder o acesso às strings atrás de uma função decodificadora
    4. Substituir nomes claros por índices numéricos e chamadas de wrappers
  • Um dos dois decodificadores recuperava strings em formato Base64, e o outro aplicava uma chave por string e uma cifra de fluxo semelhante a RC4; antes de os índices do decodificador baterem, o array de strings era rotacionado
  • Foi possível desofuscar sem executar o malware, na seguinte ordem
    1. Extrair o array de strings
    2. Reproduzir a rotação do array até alcançar o checksum esperado
    3. Reimplementar as funções decodificadoras
    4. Substituir chamadas como b(0x214) e c(0x2f1, "key") pelas strings reais
    5. Simplificar objetos wrapper e funções auxiliares para revelar a intenção de execução

Funcionamento do dropper de primeiro estágio

  • O código desofuscado carregava child_process, os, fs, path e crypto, e instalava axios e socket.io-client no diretório temporário
  • Handlers de uncaughtException e unhandledRejection em nível de processo eram configurados para ignorar erros
  • O fluxo de execução da carga útil remota era o seguinte
    • O UID era 59e605dd78fb2aafccd1b622f06a00ca
    • Buscava dados em http://45.146.252.17/api/service/59e605dd78fb2aafccd1b622f06a00ca
    • Passava o UID e a string salt para crypto.scryptSync para derivar uma chave de 32 bytes
    • Separava a resposta no formato base64_iv:base64_ciphertext e descriptografava com aes-256-cbc
    • Gravava o texto claro no arquivo pack do diretório temporário
    • Executava com child_process.execSync("node pack", { windowsHide: true, cwd: os.tmpdir() })
  • Em vez de executar funcionalidades próprias, tratava-se de um dropper de malware que baixava e executava outro software malicioso
  • O código baixado não tinha verificação de assinatura, lista de hashes permitidos, fixação de origem, restrição de caminho nem guardas contra execução, permitindo que o endpoint remoto executasse código com as permissões da conta do sistema operacional que carregou a configuração do Tailwind

Análise dinâmica em VM isolada

  • Para não expor o sistema host, foi configurada no UTM uma VM descartável com Windows 11 ARM
    • Memória 4096 MiB
    • Disco 64 GiB
    • Rede shared/NAT
    • Pastas compartilhadas desativadas
  • Foram instaladas ferramentas para coletar o comportamento do malware de vários pontos de vista
    • Wireshark: coleta de pacotes e tráfego de C2/exfiltração
    • Sysinternals Sysmon: telemetria persistente de eventos do Windows
    • Procmon: coleta de processos em execução e atividades de registro e sistema de arquivos
  • Para verificar os alvos de coleta do malware, foram inseridos dados-isca
    • Par de chaves SSH
    • Repositório privado do GitHub
    • Carteira de criptomoedas
    • Dados de navegador
    • Outros arquivos que um infostealer poderia mirar
  • Na VM, yarn start foi executado e, após cerca de 10 minutos de observação, foram obtidos run1-full.pcapng, run1-sysmon.evtx e stage2-pack.bin

Fluxo de infecção identificado na rede

  • As requisições HTTP para 45.146.252.17 tinham papéis separados por porta
    • Porta 80: obtenção da carga útil de primeiro estágio, registro do host e envio de logs
    • Porta 7641: backdoor de comando e controle via Socket.IO
    • Porta 7646: 2.588 uploads de arquivos
    • Porta 7649: 3 uploads maiores, porém em menor quantidade, de dados de navegador
  • A primeira requisição foi GET /api/service/59e605dd78fb2aafccd1b622f06a00ca, e a resposta estava no formato base64_iv:base64_ciphertext, com Content-Length: 150897
  • tailwind.config.js descriptografava a resposta com AES-256-CBC, escrevia o texto claro em %TEMP%\pack e o executava com node pack
  • As características da carga útil de segundo estágio obtida eram as seguintes
    • SHA-256: 68a64d8c015c06fd70bcb8c5878c1e430da827dd00b62f8e6ef69e76bb94de5b
    • Tamanho: 113136 bytes
    • Formato: JavaScript ASCII composto por uma única linha
  • O pack descriptografado também estava ofuscado novamente, mas usava as mesmas técnicas do primeiro estágio e pôde ser desofuscado pelo mesmo procedimento

Payload de segundo estágio composto por quatro programas

  • pack não era um script único, mas uma pequena árvore de processos que executava os quatro programas a seguir
    1. Gravava e executava o backdoor de comando e controle scdata em um diretório temporário
    2. Gravava e executava o ladrão de navegador e carteiras ldata em um diretório temporário
    3. Executava um scanner recursivo de arquivos diretamente na memória com node -e
    4. Executava um monitor de área de transferência diretamente na memória com node -e
  • As principais configurações eram o UID 59e605dd78fb2aafccd1b622f06a00ca, a chave de usuário 308, o host 45.146.252.17, a porta Socket.IO 7641, a porta de chave 7648, a porta de upload de navegador 7649 e a porta de upload de arquivos 7646

scdata: backdoor interativo de controle remoto

  • scdata é gravado como arquivo em %TEMP% e então executado com npm i axios socket.io-client ... && node scdata, permanecendo como um processo filho de longa duração
  • Após a execução, configura a si mesmo para parecer um processo normal
  • Também instala pacotes adicionais necessários para as funções de controle remoto
    • socket.io-client, ssh2, node-pty: funções semelhantes a terminal e SSH
    • sharp, screenshot-desktop, clipboardy, @nut-tree-fork/nut-js: capturas de tela, área de transferência, movimentação/clique/rolagem do mouse e entrada de teclado
  • Os eventos Socket.IO mostram diretamente o escopo do controle remoto
    • Terminal: start-terminal, terminal-input, terminal-resize, stop-terminal, command
    • Verificação e captura do host: whour, capture
    • Controle de entrada: mouseMove, mouseClick, mouseScroll, keyTap, keyCombo
    • Área de transferência: copyText, pasteText
    • SSH e encerramento: start_ssh, ssh_input, kill
  • No PCAP, foram confirmados o polling e o handshake WebSocket na porta 7641, além do primeiro evento do servidor, whour; no Sysmon, foram capturados em sequência node.exe scdata, uma consulta de informações do sistema via PowerShell e a instalação de dois grupos de pacotes npm
  • Vai além do simples roubo de informações e também oferece ao atacante funcionalidades de shell e controle do desktop

ldata: ladrão de dados de navegadores e carteiras

  • ldata é gravado em %TEMP% e executado com npm i axios && node ldata; o título do processo é npm-cache
  • Coleta perfis de navegador e armazenamentos de extensões de carteira e os envia para http://45.146.252.17:7649/upload; o status do LevelDB é verificado em /cldbs
  • Os navegadores-alvo são definidos de forma ampla por sistema operacional
    • Windows: Chrome, Edge, Brave, LT Browser
    • macOS: Chrome, Brave, Opera, LT Browser, Edge e o chaveiro local de login
    • Linux: pastas de perfil correspondentes da família Chromium
  • Nos diretórios Default ou Profile*, faz upload dos seguintes bancos de dados do Chromium
    • Login Data
    • Login Data For Account
    • Web Data
  • Em seguida, percorre Local Extension Settings/<extension-id>; entre os IDs de extensões de carteira hardcoded está também o da MetaMask, nkbihfbeogaeaoehlefnkodbefgpgknn
  • Para os caminhos das primeiras 8 extensões de carteira, copia o diretório LevelDB para uma pasta temporária e faz upload dos arquivos individualmente; com base na resposta cldbs do servidor, decide se concluiu ou se deve tentar novamente
  • Os três uploads confirmados na porta 7649 eram os seguintes bancos de dados
    • Login_Data.sqlite: 51.200 bytes
    • Login_Data_For_Account.sqlite: 51.200 bytes
    • Web_Data.sqlite: 262.144 bytes
  • Os dados do experimento não continham senhas salvas nem linhas de cartão, mas incluíam 6 valores de preenchimento automático e metadados do navegador
  • Navegadores baseados em Chrome criptografam localmente alguns campos, portanto nem sempre é possível recuperar segredos em texto claro apenas com os bancos de dados
    • Ainda assim, quando combinados com segredos do sistema operacional, cookies, armazenamentos de extensões e um navegador desbloqueado, eles se tornam parte de um pipeline de roubo de credenciais
  • Depois de fazer upload dos dados de navegador e dos LevelDB necessários, ou quando o servidor os marca como concluídos, o processo termina sem aguardar comandos adicionais do operador

Scanner recursivo de arquivos e monitor de área de transferência

  • O scanner recursivo de arquivos é executado com node -e, sem criar um arquivo separado, e começa a varredura pelo diretório home do usuário
    • No Windows, enumera as letras de unidade com Get-CimInstance Win32_LogicalDisk e também verifica a raiz de cada unidade
    • Os padrões de arquivos coletados incluem *.env*, *.md, *.pem, *.ini, *.secret, *.json, *.js, *.ts, *.csv, *.txt, *.doc, *.docx, *.pdf, *.xlsx, .zsh_history, .bash_history
    • ~/.ssh, ~/.aws, ~/.azure, ~/.config, ~/.foundry são automaticamente tratados como pastas de interesse
    • Também procura nomes como metamask, bitcoin, btc, solana, secret phrase, private key
    • Os resultados são enviados para http://45.146.252.17:7646/upload
  • No ambiente-isca, arquivos como id_ed25519, id_ed25519.pub, History.txt, seed.js, password.js, tokens.js, ConnectWalletButton.js, ExportWallet.js, RegisterWallet.js, tailwind.config.js, aptos-cli.json foram de fato enviados
  • Se ldata se encarrega de navegadores e armazenamentos de carteiras, o scanner de arquivos coleta amplamente chaves SSH, configurações, código-fonte, segredos locais, históricos de shell e arquivos de projeto
  • O monitor de área de transferência também é executado com node -e; o título do processo é npm-compiler.log
    • Após aguardar alguns segundos, lê a área de transferência repetidamente
    • No macOS usa pbpaste; no Windows usa powershell -NoProfile -NonInteractive Get-Clipboard
    • Valores alterados são enviados para http://45.146.252.17/api/service/makelog
  • Mesmo sem interpretar o formato, ele pode capturar diretamente senhas, frases de recuperação, chaves privadas, tokens de API, códigos de uso único, URLs do GitHub, endereços de carteira e segredos de implantação que o usuário copiar

Princípios a seguir antes de executar uma tarefa de recrutamento

  • Um repositório de tarefa enviado por uma pessoa desconhecida deve ser tratado como código executável não confiável até que sua segurança seja confirmada
  • Antes de yarn install, npm install, yarn build ou yarn start, é preciso revisar os seguintes itens
    • package.json
    • scripts de ciclo de vida
    • arquivos de configuração
    • hooks de dependência evidentes
  • Neste caso, o malware estava escondido em tailwind.config.js, um arquivo que as pessoas tendem a deixar passar; arquivos de configuração, dependências e ferramentas de build também podem ser executados como código
  • Projetos de entrevista devem ser executados em uma VM ou contêiner descartável sem segredos reais montados
    • perfil pessoal do navegador
    • gerenciador de senhas
    • chaves SSH
    • carteiras de criptomoedas
    • tokens do GitHub
    • credenciais de nuvem
    • sessões bancárias
    • conta principal de e-mail
  • Para tarefas que exigem uma conta ou carteira, use uma nova identidade de teste sem fundos e que não seja reutilizada em outros serviços
  • Se for uma tarefa Web3, use apenas testnet e, mesmo que pareça inofensivo, não conecte sua carteira real a um projeto desconhecido

Indicadores para verificar se houve infecção

  • No macOS e no Linux, verifique primeiro os seguintes itens
    • Processos em execução relacionados a node, pack, scdata, ldata, npm-compiler, vhost.ctl
    • Conexões com 45.146.252.17 ou com as portas 7641, 7646, 7649
    • pack, scdata, ldata, vhost.ctl em diretórios temporários, Downloads, Desktop, Documents e Library
    • Arquivo marcador */.npm/vhost.ctl
    • Strings como IP, UID, /api/service/makelog, node scdata, node ldata, node pack dentro do projeto baixado
  • No Windows, verifique os seguintes itens
    • Entre os processos node, npm, cmd e powershell, aqueles cuja linha de comando contém pack, scdata, ldata, node -e, endereço IP ou Get-Clipboard
    • Conexões TCP abertas com 45.146.252.17 ou com as portas remotas 7641, 7646, 7649
    • pack, scdata, ldata, vhost.ctl, .npm\vhost.ctl dentro de %TEMP%
    • Strings C2 conhecidas dentro do diretório onde o repositório da entrevista foi clonado
  • Se for encontrado qualquer um destes itens — processos Node ativos, conexões com esse IP ou artefatos pack, scdata ou ldata — o sistema deve ser considerado exposto
  • Esses indicadores são verificações iniciais específicas das amostras analisadas e não constituem um procedimento forense completo

Limpeza do sistema infectado e rotação de segredos

  • Antes de tudo, desconecte o computador da rede e não continue investigando, depurando nem copiando novos segredos no ambiente infectado
  • Se forem necessárias evidências, preserve os seguintes materiais antes da remoção
    • Lista de processos
    • Conexões de rede
    • Arquivos suspeitos
    • Histórico do navegador
    • Repositório malicioso
  • Depois, encerre processos relacionados a node pack, node scdata, node ldata, node -e, npm-compiler, vhost.ctl e remova pack, scdata, ldata, .npm/vhost.ctl dos diretórios temporários
  • Se for uma VM descartável e não houver necessidade de preservar trabalhos legítimos em Node, é possível usar pkill node no macOS/Linux ou forçar o encerramento de todos os processos node no Windows
  • Exclua o repositório malicioso e node_modules, mas, se for necessária análise adicional, preserve uma cópia ZIP offline
  • Apenas excluir os arquivos não é suficiente; é preciso rotacionar ou revogar as seguintes informações secretas
    • Chaves SSH
    • Tokens do GitHub e do npm
    • Chaves de nuvem e chaves de API
    • Segredos de deploy
    • Senhas salvas no navegador
    • Sessões de login ativas
  • Se houver possibilidade de que uma seed de carteira ou chave privada tenha passado pelo sistema infectado, crie uma nova carteira em um dispositivo limpo e transfira os fundos

Ataque que explora as fronteiras de confiança das ferramentas de desenvolvimento

  • Produtos antivírus tradicionais não detectaram esse repositório, e agentes populares de codificação por IA usados para resolver a tarefa também não identificaram o código malicioso escondido no projeto
  • Como o Tailwind avalia arquivos de configuração JavaScript como módulos Node, a IIFE da linha 95 é executada no momento em que ferramentas de desenvolvimento, scripts de build, integrações de editores, a CLI do Tailwind, bundlers ou tarefas de CI carregam a configuração
  • A configuração legítima do Tailwind ia até a linha 94; depois dela havia cerca de 27 KB de código ofuscado adicionados
  • O payload baixado é executado com os mesmos privilégios do sistema operacional do usuário que carregou a configuração
    • Pode acessar arquivos locais, perfis de navegador, credenciais salvas, dados de extensões de carteira, chaves SSH, variáveis de ambiente, tokens de pacotes, credenciais de nuvem, código-fonte e área de transferência
    • Se for executado em CI, segredos de deploy, artefatos de build, credenciais de registro e tokens de acesso à produção também podem ser expostos
  • A correção necessária é remover completamente o blob JavaScript ofuscado de tailwind.config.js

Ainda não há comentários.

Ainda não há comentários.