Relatório de incidente: CVE-2024-YIKES
(nesbitt.io)- CVE-2024-YIKES é um incidente em que o comprometimento de dependências JavaScript se espalhou para as cadeias de suprimento de Rust e Python
- O phishing de
left-justifyvazou credenciais de.npmrc,.pypirc, Cargo e Gem - O
build.rsmalicioso devulpine-lz4baixou e executou um script de shell em hosts de CI - O malware do
snekpack3.7.0 se espalhou para cerca de 4,2 milhões de máquinas e adicionou chaves SSH e um shell reverso - O worm cryptobro-9000 acidentalmente atualizou para
snekpack3.7.1, removendo o malware
Visão geral do incidente
- CVE-2024-YIKES é um incidente de segurança em que uma dependência comprometida do ecossistema JavaScript levou ao roubo de credenciais, se espalhando depois para um ataque à cadeia de suprimento de uma biblioteca de compressão em Rust e para a distribuição de malware em uma ferramenta de build Python
- O incidente foi registrado às 03:47 UTC, e o status mudou para “resolvido por acaso”, enquanto a severidade passou de “Critical → Catastrophic → Somehow Fine”
- A duração foi de 73 horas, e os sistemas afetados continuaram marcados como “Yes”
- A cadeia de pacotes e ferramentas comprometidos passou por
left-justify,vulpine-lz4esnekpack, distribuindo malware para cerca de 4 milhões de desenvolvedores - No fim, um worm separado de mineração de criptomoeda,
cryptobro-9000, executou uma atualização nas máquinas infectadas, elevandosnekpackpara uma versão legítima e removendo o malware por acidente
Evolução do incidente
-
Dia 1: roubo de credenciais em pacote JavaScript
- Às 03:14 UTC, o mantenedor de
left-justify, Marcus Chen, publicou no Twitter que haviam roubado seu cartão de transporte, um notebook antigo e “algo que parecia importante e que o Kubernetes vomitou”, mas isso não foi imediatamente associado a um problema de segurança no pacote - Às 09:22 UTC, Chen tentou fazer login no registro nmp e percebeu que não estava com sua chave de 2FA por hardware; o AI Overview no topo dos resultados do Google o direcionou para o site de phishing
yubikey-official-store.net, registrado 6 horas antes - Às 09:31 UTC, Chen inseriu suas credenciais do nmp no site de phishing, que agradeceu pela compra e prometeu envio em 3 a 5 dias úteis
- Às 11:00 UTC,
[email protected]foi publicado com o changelog “performance improvements” - O pacote incluía um script executado após a instalação, que exfiltrava
.npmrc,.pypirc,~/.cargo/credentialse~/.gem/credentialspara um servidor escolhido pelo atacante - Às 13:15 UTC, foi aberto um ticket de suporte em
left-justifycom a mensagem “why is your SDK exfiltrating my .npmrc”, mas ele foi marcado como “low priority - user environment issue” e encerrado automaticamente após 14 dias sem atividade
- Às 03:14 UTC, o mantenedor de
-
Dia 1: ataque à cadeia de suprimento se espalha para biblioteca Rust
- Entre as credenciais vazadas estavam as do mantenedor da biblioteca Rust
vulpine-lz4 vulpine-lz4é uma biblioteca para “blazingly fast Firefox-themed LZ4 decompression”, tem 12 estrelas no GitHub, mas é uma dependência transitiva do própriocargo- Às 22:00 UTC,
vulpine-lz40.4.1 foi publicado com a mensagem de commit “fix: resolve edge case in streaming decompression” - A mudança real foi a adição de um script
build.rsque baixava e executava um script de shell se o hostname contivesse “build”, “ci”, “action”, “jenkins”, “travis” ou “karen”
- Entre as credenciais vazadas estavam as do mantenedor da biblioteca Rust
-
Dia 2: falha na detecção e na resposta
- Às 08:15 UTC, a pesquisadora de segurança Karen Oyelaran encontrou o commit malicioso depois que o payload foi executado em seu notebook pessoal
- Karen Oyelaran abriu uma issue dizendo “your build script downloads and runs a shell script from the internet?”, mas não recebeu resposta
- O mantenedor legítimo havia ganhado €2.3 million na EuroMillions e estava em Portugal pesquisando fazendas de cabras
- Às 10:00 UTC, o VP de Engenharia de uma empresa da Fortune 500 cliente do
snekpacksoube do incidente por um post no LinkedIn intitulado “Is YOUR Company Affected by left-justify?” e quis saber por que ninguém o havia incluído antes, embora ele já tivesse sido incluído antes - Às 10:47 UTC, o canal
#incident-responseno Slack desviou brevemente para uma thread de 45 mensagens discutindo se “compromised” deveria ser escrito com “z” no inglês americano
-
Dia 2: infecção da ferramenta de build Python
snekpack- Às 12:33 UTC, o script de shell mirou especificamente o pipeline de CI do
snekpack snekpacké uma ferramenta de build Python usada por 60% dos pacotes do PyPI com “data” no nomesnekpackembutiavulpine-lz4porque “Rust is memory safe”- Às 18:00 UTC,
snekpack3.7.0 foi lançado, e o malware começou a ser instalado em máquinas de desenvolvedores no mundo todo - O malware adicionava uma chave SSH em
~/.ssh/authorized_keys, instalava um shell reverso que só era ativado às terças-feiras e alterava o shell padrão do usuário parafish - A mudança do shell padrão para
fishfoi tratada como bug - Às 19:45 UTC, outro pesquisador de segurança publicou um post de blog de 14.000 palavras intitulado “I found a supply chain attack and reported it to all the wrong people”, contendo a expressão “in this economy?” 7 vezes
- Às 12:33 UTC, o script de shell mirou especificamente o pipeline de CI do
-
Dia 3: correção acidental e encerramento do incidente
- Às 01:17 UTC, um desenvolvedor júnior em Auckland descobriu o malware enquanto depurava um problema não relacionado e abriu um PR revertendo a versão vendorizada de
vulpine-lz4emsnekpack - Esse PR exigia 2 aprovações, mas os dois aprovadores estavam dormindo
- Às 02:00 UTC, o mantenedor de
left-justifyrecebeu um YubiKey deyubikey-official-store.net; era um pen drive de 4 dólares com um README escrito “lol” - Às 06:12 UTC, um worm separado de mineração de criptomoeda,
cryptobro-9000, começou a se espalhar por meio de uma vulnerabilidade emjsonify-extreme jsonify-extremeé descrito como um pacote que “makes JSON even more JSON, now with nested comment support”- O payload de
cryptobro-9000em si não tinha nada de especial, mas seu mecanismo de propagação incluía executarnpm updateepip install --upgradeem máquinas infectadas para ampliar a superfície de ataque futura - Às 06:14 UTC,
cryptobro-9000atualizou acidentalmentesnekpackpara 3.7.1 snekpack3.7.1 era um release legítimo publicado por um co-mantenedor confuso e revertia a versão vendorizada devulpine-lz4- Às 06:15 UTC, o shell reverso de terça-feira foi ativado, mas o servidor de comando e controle havia sido comprometido por
cryptobro-9000e não conseguia responder - Às 09:00 UTC, os mantenedores de
snekpackemitiram um aviso de segurança de 4 frases contendo as expressões “out of an abundance of caution” e “no evidence of active exploitation” - “no evidence of active exploitation” foi considerado tecnicamente verdadeiro porque ninguém havia procurado evidências
- Às 11:30 UTC, um desenvolvedor tuitou “I updated all my dependencies and now my terminal is in fish???” e recebeu 47.000 curtidas
- Às 14:00 UTC, as credenciais comprometidas de
vulpine-lz4foram trocadas - O mantenedor legítimo recebeu um e-mail em sua nova fazenda de cabras e respondeu “I haven’t touched that repository in two years” e “I thought Cargo 2FA was optional”
- Às 15:22 UTC, o incidente foi declarado resolvido, e a retrospectiva foi agendada e depois remarcada três vezes
- Às 01:17 UTC, um desenvolvedor júnior em Auckland descobriu o malware enquanto depurava um problema não relacionado e abriu um PR revertendo a versão vendorizada de
Designação do CVE e escala do dano
- Na 6ª semana, CVE-2024-YIKES foi oficialmente designado
- O aviso ficou sob embargo enquanto MITRE e GitHub Security Advisories discutiam a classificação CWE
- Quando o CVE foi publicado, 3 artigos no Medium e uma apresentação na DEF CON já haviam detalhado o incidente
- O dano total permaneceu desconhecido
- O número de máquinas comprometidas foi estimado em 4,2 milhões
- O número de máquinas salvas pelo worm de criptomoeda também foi estimado em 4,2 milhões
- A mudança líquida na postura de segurança permaneceu como “desconforto”
Causa raiz e fatores contribuintes
-
Causa raiz
- Foi tratado como causa raiz o fato de um cachorro chamado Kubernetes ter comido o YubiKey
-
Fatores contribuintes
- O registro nmp ainda permite autenticação apenas por senha para pacotes com menos de 10 milhões de downloads semanais
- O Google AI Overviews apontou com confiança para uma URL que jamais deveria existir
- A filosofia de “small crates” do ecossistema Rust foi copiada no ecossistema npm, permitindo que pacotes como
is-even-number-rs, com 3 estrelas no GitHub, acabem como dependência transitiva a quatro níveis de infraestrutura crítica - Ferramentas de build Python vendorizam bibliotecas Rust por “performance” e depois não as atualizam
- O Dependabot fez merge automático de PRs após o CI passar, e o CI passou porque o malware instalou
volkswagen - O worm de criptomoeda tem melhores práticas de CI/CD do que a maioria das startups
- Não houve um único responsável, mas o PR do Dependabot foi aprovado por um contratado cuja sexta-feira era o último dia de trabalho
- O incidente aconteceu em uma terça-feira
Ações de melhoria e opções restantes
- A implementação de assinatura de artefatos era um item de ação do incidente do Q3 de 2022, mas continua no backlog
- A implementação obrigatória de 2FA já havia sido exigida, mas não ajudou
- A auditoria de dependências transitivas foi riscada porque havia 847 itens no escopo
- Fixar todas as versões de dependências impede o recebimento de patches de segurança
- Não fixar versões de dependências abre espaço para ataques à cadeia de suprimento
- A opção de reescrever em Rust foi riscada e apontava para
vulpine-lz4 - Como ações restantes, sobraram esperar por um worm benevolente ou considerar uma mudança de carreira para fazenda de cabras
Impacto no cliente e resposta organizacional
- Alguns clientes podem ter sofrido “resultados de segurança não ideais”
- Houve contato proativo para dar visibilidade da situação às partes interessadas afetadas
- A confiança do cliente permaneceu como “north star”
- Foi criado um grupo de trabalho multifuncional para revisar a postura de segurança, mas ele ainda não se reuniu
- Após revisão jurídica, foi acrescentada a frase de que o shell
fishnão é malware, embora às vezes pareça ser - Este relatório de incidente é o terceiro do trimestre
- O pedido de reforço de pessoal da equipe de segurança continua no backlog desde o Q1 de 2023
Agradecimentos
- Karen Oyelaran descobriu o problema porque seu hostname batia com a regex
- O PR aberto pelo desenvolvedor júnior em Auckland foi aprovado 4 horas depois de o incidente já ter sido resolvido
- Alguns pesquisadores de segurança encontraram o problema antes, mas o reportaram às pessoas erradas
- O autor de
cryptobro-9000não quis ter o nome divulgado, mas pediu para mencionarem seu SoundCloud - O cachorro Kubernetes recusou comentar
- Apesar de tudo, a equipe de segurança cumpriu o SLA deste relatório
1 comentários
Comentários do Hacker News
Para quem ficou confuso: este texto é uma ficção, e bem escrita, sobre um incidente na cadeia de suprimentos
Quando passei o olho por cima, achei que fosse real e fiquei bem preocupado, então acabei lendo com mais atenção :)
nmpFiquei curioso com a parte citada sobre “vulpine-lz4 com 12 estrelas no GitHub ser uma dependência transitiva do próprio cargo”, então puxei rapidamente alguns crates que poderiam se infiltrar em um build do cargo e já ter um
build.rs, ficando menos chamativos:flate2,tar,curl-sys,libgit2-sys,openssl-sys,libsqlite3-sys,blake3,libz-sys,zstd-sys,ccDe quebra, se alguém comprometesse
xz2, também poderia contaminar o rustupPelo menos o
Cargo.locké versionado-syssão só bindings, então fazer qualquer outra coisa ali pareceria bem suspeitoPelo que sei, os outros pertencem a mantenedores principais do Rust, como
alexcrichton, ou ao própriorustlangÉ fácil ficar cínico, porque depois que tudo passa o problema e a solução parecem óbvios demais
Mas, por muito tempo, e talvez ainda hoje, o credo da cultura hacker foi move fast and break things
É bom ver crescer o movimento para corrigir os problemas evidentes de sistemas de cadeia de suprimentos como o
npm, mas me preocupa estarmos entrando numa era de novos problemas de segurança causados em boa parte pelo desenvolvimento orientado por agentesNão só no sentido de Mythos/Glasswing revelar vulnerabilidades em quase tudo em que toca, mas também no modo como estamos criando software, puxando dependências e perdendo nossos modelos mentais humanos sobre sistemas complexos, o que provavelmente vai gerar muito software e infraestrutura improvisados que ninguém entende direito
Espero que, daqui a alguns anos, ao olharmos para hoje, a gente não se arrependa de ter sido tão ingênuo, sem nos preparar direito para a longa cauda do desenvolvimento com IA, enquanto tentávamos resolver problemas recriando sistemas complexos com IA
Mesmo assim, o texto foi engraçado
Como fã do Fish, essa frase me fez sentir atacado e compreendido ao mesmo tempo: “por favor, deixem claro que o shell fish não é malware, só às vezes parece”
Independente do shell, a parte dizendo que “o pedido para ampliar a equipe de segurança estava no backlog desde o 1º trimestre de 2023” também pareceu familiar demais
figletcomapt-getoudnfe então sobrescrever o conteúdo de/etc/motdcom all your base are belong to us em uma fonte gigante de arte ASCIIEu realmente ri alto na parte em que o mantenedor do left-justify recebeu uma YubiKey de
yubikey-official-store.net, e no fim era um pendrive USB de 4 dólares com “lol” escrito noREADMETrollagem total
Gostei do fato de que plugar um dispositivo USB vindo de um site de phishing já é por si só outro vetor de ataque
Não era SCP de verdade, mas foi o texto mais SCP que li recentemente
Eu ri alto na parte da Karen :D ;)
Isso me lembrou um script de build baseado em
makeque recebi ao revisar o projeto de um colega de turma; se o hostname contivessebpavuk, ele tentava fazerrm -rfna minha pasta homeIsso foi na 7ª série!!
Incidentes de cadeia de suprimentos são realmente complicados, e precisamos fazer melhor
Pessoalmente, no Rust eu apoio a fundação financiar alguns crates centrais, submetendo-os ao mesmo processo de auditoria do núcleo da linguagem Rust e investindo em projetos para reduzir vulnerabilidades na cadeia de suprimentos
Não acho que a resposta seja acabar com sistemas como
cratesounpm.cratesenpmajudam muito desenvolvedorcratestambém tem feito esforços para incorporar orustsec, mas, além disso, eu gostaria de ver a comunidade migrar de muitas dependências pequenas para menos dependências grandes, comotokiocrates.iojá são crates primários fornecidos pela organização RustIsso costuma ser ignorado quando as pessoas se preocupam com o grafo de crates do Rust
Se você olhar os 10 mais baixados na página inicial do
crates.io, o único que não foi feito pela organização Rust ou por mantenedores centrais do Rust é o cratebase64npmenmpao mesmo tempo?“O mantenedor oficial ganhou 2,3 milhões de euros na EuroMillions e está pesquisando criação de cabras em Portugal”, e “causa raiz: um cachorro chamado Kubernets comeu a YubiKey”
Ah, claro. Tão irresponsável cair nesse ataque clássico e famoso
A famosa técnica de “deixar alguém desnorteado com o prêmio da loteria enquanto o dongle da outra pessoa parece irresistivelmente saboroso para o pet”
Quando é que as pessoas vão aprender
Ainda bem que eu não uso
npmnempip, e sigo o método recomendado de usar sócurl ... | bashcurl | sudo bashAmadorismo puro