O Worm do NPM Voltou e Está Muito Pior (TanStack Hackeado)

BBetter Stack
컴퓨터/소프트웨어경영/리더십AI/미래기술

Transcript

00:00:00Shai Hulud está de volta para uma quarta sequência.
00:00:02Desta vez, está visando pacotes como o TanStack,
00:00:04literalmente horas após eu publicar este vídeo sobre Next.js,
00:00:07o que foi um timing brilhante da minha parte.
00:00:08Este é, na verdade, um ataque massivo à cadeia de suprimentos NPM
00:00:11que impacta mais do que apenas o TanStack.
00:00:13Também afetou pacotes como UiPath, Mistral,
00:00:15e outros 160 pacotes,
00:00:17incluindo até pacotes PyPy como o Guardrails.ai.
00:00:20O que torna este ainda mais divertido
00:00:22é que ele incluiu um interruptor de homem morto,
00:00:24então, se detectasse que você girou suas chaves roubadas,
00:00:26ele limparia todo o seu PC,
00:00:28e também trazia algumas políticas globais integradas.
00:00:30Então, vamos mergulhar nisso.
00:00:36Para esta sequência, O Verme tem o mesmo objetivo,
00:00:39roubar credenciais de máquinas de desenvolvedores e corredores CI/CD,
00:00:42depois usar essas credenciais para alcançar mais pacotes.
00:00:44Para o TanStack, isso significou publicar 84 versões maliciosas
00:00:47em 42 pacotes TanStack em apenas alguns minutos.
00:00:51Agora, vou mostrar como eles conseguiram
00:00:52infectar o TanStack em primeiro lugar,
00:00:54mas primeiro vamos ver o que o malware faz
00:00:56se você instalar um desses pacotes impactados.
00:00:58Dentro dos pacotes maliciosos,
00:00:59você encontraria um novo arquivo chamado routerinit.js,
00:01:02bem como uma dependência opcional injetada,
00:01:04que leva ao que parece ser
00:01:05um link legítimo do GitHub do TanStack router,
00:01:08mas na verdade é um commit órfão no fork do atacante.
00:01:10Essa é apenas a maneira como o GitHub lida com links de fork,
00:01:13então a URL pode realmente parecer
00:01:14que pertence ao projeto original,
00:01:16mesmo que o commit seja de um fork.
00:01:18Nesse fork, há um script de ciclo de vida,
00:01:20prepare, que executa bun run task runner JS,
00:01:22e tem um exit 1 no final.
00:01:24Essa é apenas uma maneira inteligente de fazer a dependência opcional falhar
00:01:27depois que o payload já tiver sido executado,
00:01:28para que a instalação continue normalmente,
00:01:30e deixe vestígios menos óbvios em seus logs de instalação.
00:01:33Além disso, você pode ter notado que isso não está executando
00:01:35aquele arquivo routerinit.js que eu disse que foi injetado
00:01:37nos pacotes no início,
00:01:38mas, por enquanto, apenas pense nesses dois arquivos
00:01:40como tendo exatamente a mesma função com nomes diferentes.
00:01:42O TLDR é: quando você instala isso,
00:01:44ele vai executar este script.
00:01:46A primeira coisa que esse script tenta fazer
00:01:47é se desacoplar do fluxo óbvio de instalação,
00:01:50então ele verificará se já está sendo executado
00:01:51em segundo plano, e se não estiver,
00:01:53ele bifurca uma cópia destacada de si mesmo
00:01:54e fecha o script pai de forma limpa.
00:01:57Dessa forma, seus logs de instalação npm
00:01:58não mostram nada da saída do script
00:02:00porque o malware agora se destacou
00:02:01desse processo e está rodando em segundo plano.
00:02:04Depois disso, ele faz algo muito inteligente.
00:02:06Ele escreve cópias de si mesmo
00:02:07em seu diretório de hooks do Claude Code,
00:02:08depois configura suas configurações do Claude
00:02:10para executar este hook sempre que você usar o Claude Code
00:02:12nesse projeto.
00:02:13Dessa forma, ele pode sobreviver após a instalação original
00:02:16e continuar sendo acionado toda vez
00:02:17que você abrir o Claude Code nesse projeto.
00:02:20Ele realmente faz o mesmo com o task runner do VS Code,
00:02:22duplicando-se lá,
00:02:23então se você usar os recursos de execução automática de workspace do VS Code,
00:02:26você tem exatamente o mesmo problema.
00:02:28Ele até configura um serviço de nível de SO
00:02:29chamado GitHub Token Monitor,
00:02:31mas voltaremos a esse,
00:02:32porque esse é absolutamente diabólico.
00:02:34Também é bastante diabólico
00:02:35que você ainda não se inscreveu.
00:02:37A próxima coisa que o payload faz
00:02:38é começar a roubar suas credenciais,
00:02:40e ele tenta de tudo.
00:02:41No GitHub Actions, ele procura credenciais
00:02:43e segredos no ambiente do corredor.
00:02:45Mais especificamente, vasculhando a memória do processo de trabalho
00:02:47do GitHub Actions
00:02:48por seus segredos de fluxo de trabalho
00:02:50que incluem segredos mascarados,
00:02:52e ele até insere um fluxo de trabalho do GitHub falso
00:02:55que serializa os segredos do seu repositório
00:02:57e os exfiltra mais tarde.
00:02:58Ele também procura segredos da AWS,
00:03:00primeiro atrás de suas variáveis de ambiente
00:03:02e arquivos de configuração local,
00:03:03mas então também vai atrás de serviços de metadados da AWS
00:03:06como IMDS v2 e metadados de tarefa ECS.
00:03:09Para Kubernetes, ele rouba tokens de conta de serviço
00:03:11e certificados que permitem acesso à API no cluster
00:03:14a quaisquer privilégios de controle de acesso
00:03:17que a conta de serviço daquele pod tivesse,
00:03:19o que em clusters mal configurados
00:03:21pode ser extremamente amplo,
00:03:22às vezes efetivamente administrador.
00:03:24E para piorar ainda mais,
00:03:25ele também vai atrás do HashiCorp Vault,
00:03:27coletando todas as suas variáveis de ambiente
00:03:29e tokens relacionados ao Vault,
00:03:30então usa qualquer acesso que tenha ao Kubernetes
00:03:32para recuperar todos os seus segredos gerenciados pelo Vault.
00:03:34E tudo isso é apenas o que ele faz
00:03:35às suas implantações de CI.
00:03:37Se estiver na sua estação de trabalho,
00:03:38ele vai atrás de todas as suas chaves SSH,
00:03:39suas credenciais NPM,
00:03:41suas credenciais Git,
00:03:42histórico do shell,
00:03:43credenciais de provedor de nuvem,
00:03:44chaves de criptografia,
00:03:45Signal,
00:03:45Slack,
00:03:45e arquivos do Discord.
00:03:46E além de tudo isso,
00:03:47ele extrai o histórico da sua sessão do Claude Code.
00:03:49Então, se você já forneceu credenciais ao Claude
00:03:51ou permitiu que ele lesse arquivos contendo credenciais,
00:03:53ele também tem acesso a essas.
00:03:55Então, sim, como eu disse,
00:03:56eles queriam absolutamente tudo
00:03:57que pudessem colocar as mãos,
00:03:58e então eles exfiltrariam esses dados
00:04:00através da rede de mensagens Session.
00:04:02E como backup,
00:04:02eles também deixavam esses dados roubados
00:04:04em repositórios do GitHub.
00:04:05E no tema de todos os seus ataques,
00:04:07esses branches são nomeados com referências a Duna.
00:04:09Então, eles têm suas credenciais.
00:04:11Não pode ficar pior, certo?
00:04:12Bem, sim.
00:04:13Sim, pode.
00:04:14Além de tudo isso,
00:04:15se você se lembra daquele serviço
00:04:16que eu disse que ele configura no seu computador,
00:04:18bem, esse monitora seus tokens do GitHub
00:04:19e continua re-exfiltrando-os.
00:04:21Mas também, a cada minuto,
00:04:22ele verifica se o token ainda é válido.
00:04:24E se não for,
00:04:25ele executa um RMRF no seu diretório de usuário,
00:04:27apagando tudo.
00:04:28Ele também tenta criar um token NPM
00:04:30com suas credenciais,
00:04:31com a descrição,
00:04:32se você revogar este token,
00:04:33nós apagaremos o computador do proprietário,
00:04:35dando a entender que ele faz a mesma coisa
00:04:36para tokens NPM também.
00:04:38Então, se você revogar esses tokens
00:04:39antes de isolar sua máquina
00:04:40e remover aquele processo em segundo plano,
00:04:42o payload pode autodestruir seu PC,
00:04:44o que é absolutamente diabólico.
00:04:46E como uma nota lateral aqui,
00:04:47a variante Python deste ataque
00:04:48faz aproximadamente a mesma coisa,
00:04:49mas também inclui uma verificação
00:04:51para ver se o idioma da sua máquina é russo.
00:04:53Se for,
00:04:53ele simplesmente para.
00:04:54E se sua máquina parece ser
00:04:55de Israel ou do Irã,
00:04:56ele gera um número aleatório
00:04:58entre 1 e 6.
00:04:59E se esse número for 2,
00:05:00ele executa um comando de limpeza destrutivo
00:05:01e tenta tocar em volume máximo
00:05:03um MP3.
00:05:04Infelizmente,
00:05:05eu não consegui descobrir
00:05:05o que é aquele MP3.
00:05:07Enfim,
00:05:07agora que ele fez tudo isso,
00:05:08o pior ainda está por vir
00:05:09porque isso foi apenas o estágio 1.
00:05:11O estágio 2 é a auto-propagação
00:05:13e essa é a parte mais perigosa
00:05:15deste ataque.
00:05:16Primeiro,
00:05:16ele procurará em sua máquina
00:05:17por quaisquer tokens NPM válidos
00:05:19onde ele possa publicar
00:05:19sem autenticação de dois fatores.
00:05:21E se encontrar um,
00:05:22ele digitalizará todos os pacotes
00:05:24aos quais essa conta tem acesso,
00:05:26então usará essas credenciais
00:05:26para se adicionar a esses pacotes
00:05:28e publicar novas versões infectadas.
00:05:30Agora, isso é obviamente muito ruim,
00:05:32mas você provavelmente também não deveria
00:05:33ter tokens publicados
00:05:33por aí
00:05:34que podem ignorar
00:05:35a autenticação de dois fatores.
00:05:36Então, a versão muito mais assustadora disto
00:05:38é o que acontece
00:05:39quando corre dentro do seu CI/CD.
00:05:41Porque no CI,
00:05:42o atacante não precisa
00:05:43de um token NPM de longa duração,
00:05:44porque boas configurações
00:05:45frequentemente dependem de OIDC,
00:05:47que pretende ser mais seguro.
00:05:48Essencialmente,
00:05:49em vez de armazenar
00:05:50um token NPM como um segredo,
00:05:51o GitHub Actions prova ao NPM,
00:05:53ei,
00:05:53eu sou este repositório
00:05:54a executar este fluxo de trabalho
00:05:55nesta ramificação,
00:05:56e o NPM então dá-lhe
00:05:57um token de publicação de curta duração.
00:05:59O problema com isto, no entanto,
00:06:00é que se o script tiver acesso
00:06:01a um ambiente de GitHub Actions confiável,
00:06:03ele pode colocar-se no mesmo lugar
00:06:04que um editor legítimo.
00:06:06Portanto, o malware pode usar
00:06:07o ambiente relacionado com OIDC
00:06:08que o GitHub expõe ao trabalho
00:06:10para solicitar um token JWT OIDC
00:06:12do endpoint de tokens do GitHub,
00:06:14então ele troca esse token JWT
00:06:16com o NPM
00:06:17por um token de publicação de curta duração
00:06:18através do sistema de publicação
00:06:19confiável do NPM,
00:06:20e agora ele pode publicar
00:06:22sem nunca roubar
00:06:22um token NPM permanente
00:06:24e parecer completamente legítimo.
00:06:26Neste caso,
00:06:26o malware inclui uma cópia
00:06:27desse ficheiro router init.js
00:06:29na tabela do pacote,
00:06:30então adiciona a dependência
00:06:31opcional maliciosa,
00:06:32então publica tudo
00:06:33como a etiqueta mais recente
00:06:34para esse pacote,
00:06:35então quando alguém
00:06:35ou algum pipeline CI/CD
00:06:37instala esses pacotes,
00:06:38o ciclo começa tudo de novo,
00:06:40espalhando-se o mais longe
00:06:40que for possível.
00:06:42Então, tudo isto
00:06:42é bastante insano, certo?
00:06:43Mas agora vamos focar-nos
00:06:44no paciente zero,
00:06:46TanStack.
00:06:46Como é que eles foram infetados
00:06:47em primeiro lugar?
00:06:48Bem,
00:06:49de acordo com a sua própria autópsia,
00:06:50o atacante abusou
00:06:51daquele pipeline do GitHub Actions.
00:06:53Eles começaram o dia
00:06:53antes de os pacotes maliciosos
00:06:54serem realmente publicados,
00:06:56onde criaram uma ramificação
00:06:57do TanStack router,
00:06:58mas na verdade renomearam
00:06:59isto para configuration
00:06:59para tentar dificultar
00:07:01a localização se estivesse a pesquisar
00:07:02através dos nomes de ramificações óbvios.
00:07:04Então adicionaram
00:07:04um compromisso malicioso
00:07:05a esta ramificação,
00:07:06que eles falsamente autoraram
00:07:07como Claude,
00:07:07e tinha uma mensagem de commit
00:07:08que era prefixada
00:07:09por skip CI,
00:07:10para que não executasse imediatamente
00:07:11o CI num evento de push.
00:07:13No dia seguinte,
00:07:13eles abriram então um PR
00:07:14contra o TanStack router
00:07:15chamado Work in Progress
00:07:16Simplify History Build.
00:07:18E é aqui que
00:07:18o ataque real acontece.
00:07:20O TLDR é que
00:07:21o TanStack tinha um fluxo de trabalho
00:07:22do GitHub Actions de tamanho de pacote
00:07:23que usava pull request target,
00:07:25e isso é notável
00:07:26porque pull request target
00:07:27na verdade executa
00:07:28no contexto de segurança
00:07:29do repositório base,
00:07:30não na ramificação.
00:07:31Isso significa que tem acesso
00:07:32ao âmbito de cache do repositório base
00:07:33e ao seu token do GitHub.
00:07:35Portanto, este fluxo de trabalho
00:07:35verificou o PR,
00:07:36instalou as suas dependências,
00:07:38e executou uma compilação de referência.
00:07:39O problema, no entanto,
00:07:40é que essa ramificação continha
00:07:40código malicioso.
00:07:41Neste caso,
00:07:42foi um script de configuração V
00:07:43que envenenou a
00:07:44loja de pacotes PMPM
00:07:45sob a chave de cache exata
00:07:47que a ação de lançamento
00:07:48usaria mais tarde.
00:07:49Eles realmente pré-calcularam
00:07:50isto a partir do ficheiro de bloqueio
00:07:51PMPM público
00:07:52usando a fórmula exata
00:07:54que o fluxo de trabalho também usa.
00:07:56Assim que esse cache envenenado
00:07:57foi guardado,
00:07:57eles realmente redefiniram
00:07:58essa ramificação de volta
00:07:59para corresponder à atual
00:07:59ramificação principal,
00:08:00então o PR visível
00:08:01parecia um zero ficheiro
00:08:02no-op,
00:08:03e depois fecharam esse PR
00:08:04e eliminaram
00:08:05a ramificação maliciosa.
00:08:06Portanto, de fora,
00:08:07parece que
00:08:07absolutamente nada
00:08:08aconteceu,
00:08:09mas eles envenenaram
00:08:10o cache do GitHub action.
00:08:11Isto significa que
00:08:12oito horas depois,
00:08:13quando um mantenedor normal
00:08:14fundiu um PR não relacionado
00:08:15na ramificação principal,
00:08:16isso desencadeou o fluxo de trabalho
00:08:17de lançamento do TanStack,
00:08:18que restaurou o
00:08:19cache envenenado PMPM,
00:08:20e agora código de controlo do atacante
00:08:22estava a ser executado dentro
00:08:23daquela ação de lançamento.
00:08:24Usou então a mesma lógica
00:08:25com OIDC
00:08:26para obter um token de publicação NPM,
00:08:28e conseguiu publicar
00:08:2984 versões de si mesmo
00:08:30através de 42 pacotes Tanstack,
00:08:32e nem sequer precisou
00:08:33de chegar ao passo de
00:08:34pacote publicado
00:08:35da ação.
00:08:36Curiosamente,
00:08:36a ação na verdade falhou
00:08:37porque alguns testes falharam,
00:08:39por isso nunca chegou a esse passo,
00:08:40mas o código malicioso foi executado
00:08:41e publicou todos eles
00:08:43independentemente.
00:08:43Portanto, o atacante conseguiu
00:08:44encadear três limites de confiança.
00:08:46Primeiro,
00:08:47o código PR da ramificação
00:08:47conseguiu envenenar
00:08:48o cache do repositório base,
00:08:49então esse cache do repositório base
00:08:51foi restaurado dentro
00:08:52do fluxo de trabalho de lançamento real,
00:08:53então o fluxo de trabalho de lançamento real
00:08:54tem permissões OIDC,
00:08:56que se transformam em
00:08:57acesso de publicação NPM,
00:08:58para que possam publicar
00:08:59o que parecem ser
00:08:59pacotes completamente legítimos.
00:09:01E é isso que eu acho
00:09:02que está a tornar-se realmente assustador
00:09:03sobre os ataques à cadeia de suprimentos.
00:09:05Estão a afastar-se
00:09:05de roubar
00:09:06o token de um mantenedor
00:09:07para abusar
00:09:08de todo o sistema CI/CD em si,
00:09:10e isso significa
00:09:11que todos os nossos sinais de confiança
00:09:12estão a começar a trabalhar
00:09:13para o atacante.
00:09:14Este era um pacote assinado
00:09:15com proveniência válida
00:09:16publicado por um fluxo de trabalho real.
00:09:18Então aqui vamos,
00:09:19isso é o ShaiHalud4,
00:09:20e se quiser verificar
00:09:21se foi comprometido
00:09:21por qualquer um desses pacotes,
00:09:23vou deixar links
00:09:23para blog posts abaixo,
00:09:25que cobrirão
00:09:25como pode descobrir
00:09:26e o que pode fazer
00:09:27se instalou
00:09:28um desses.
00:09:29Deixe-me saber nos comentários
00:09:30o que pensa
00:09:30sobre tudo isto
00:09:31e o ecossistema NPM,
00:09:33enquanto está aí em baixo,
00:09:33subscreva,
00:09:34e como sempre,
00:09:34vemo-nos na próxima.

Key Takeaway

O ataque Shai Hulud 4 demonstra que a segurança da cadeia de suprimentos moderna está em risco crítico, pois o malware agora abusa de caches e permissões OIDC do CI/CD para publicar pacotes maliciosos que parecem legítimos e assinados.

Highlights

  • O ataque de cadeia de suprimentos Shai Hulud 4 comprometeu 42 pacotes do TanStack, resultando na publicação de 84 versões maliciosas em poucos minutos.

  • O malware utiliza arquivos injetados, como 'routerinit.js', e dependências opcionais manipuladas para executar payloads em segundo plano sem deixar vestígios óbvios nos logs de instalação.

  • O script malicioso rouba uma vasta gama de credenciais, incluindo segredos do GitHub Actions, AWS, Kubernetes, HashiCorp Vault, chaves SSH e histórico de sessões do Claude Code.

  • Um serviço de monitoramento de nível de SO (GitHub Token Monitor) é instalado para re-exfiltrar tokens e destruir o diretório do usuário caso os tokens sejam revogados.

  • O ataque envenena caches de fluxo de trabalho do GitHub Actions (via PMPM) para que código malicioso seja executado automaticamente durante compilações legítimas de lançamento.

  • O malware usa OIDC (OpenID Connect) para trocar tokens JWT por tokens de publicação de curta duração do NPM, permitindo que pacotes infectados pareçam assinados e legítimos.

Timeline

Escopo e Método de Infecção

  • O ataque impacta mais de 160 pacotes, incluindo TanStack, UiPath e Mistral.
  • Arquivos maliciosos são injetados via dependências opcionais apontando para commits órfãos em forks do GitHub.
  • O script malicioso bifurca-se para rodar em segundo plano, evitando a detecção nos logs do NPM.

O ataque visa roubar credenciais de desenvolvedores e corredores CI/CD. A técnica envolve links que parecem pertencer ao repositório original, mas apontam para commits em forks do atacante, garantindo que a instalação continue após a execução do payload.

Exfiltração de Segredos e Persistência

  • O malware estabelece persistência injetando hooks no Claude Code e no VS Code.
  • Segredos são extraídos de ambientes CI/CD, AWS, Kubernetes e do HashiCorp Vault.
  • Dados roubados são exfiltrados via rede Session ou branches do GitHub referenciando Duna.

A capacidade de coleta de dados é ampla, atingindo desde arquivos locais (SSH, Slack, Discord) até infraestrutura em nuvem. O componente mais destrutivo é o 'GitHub Token Monitor', que monitora a validade de tokens e apaga o diretório do usuário em caso de revogação.

Auto-propagação e Abuso de OIDC

  • O estágio 2 foca na auto-propagação, infectando pacotes aos quais a conta comprometida tem acesso.
  • O malware utiliza OIDC para obter tokens de publicação de curta duração do NPM.
  • O acesso via OIDC permite que o atacante pareça um autor legítimo durante o processo de publicação.

Ao abusar de configurações de OIDC em pipelines de CI/CD, o malware elimina a necessidade de tokens NPM permanentes. Isso torna a detecção difícil, pois os pacotes publicados possuem proveniência válida segundo o sistema do NPM.

Vetor de Entrada: Envenenamento de Cache

  • O TanStack foi comprometido através do envenenamento de um cache do GitHub Actions usando pull_request_target.
  • O atacante envenenou o cache com um PR malicioso e fechou o PR para eliminar vestígios.
  • O fluxo de trabalho de lançamento legítimo restaurou o cache envenenado oito horas depois, desencadeando o ataque.

O ataque ao TanStack explorou a confiança em caches persistentes de dependências como PMPM. A automação legítima do repositório base foi usada para executar o código malicioso, provando que sistemas CI/CD bem configurados podem ser transformados em ferramentas de ataque.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video