Rapport d’incident : CVE-2024-YIKES
(nesbitt.io)- CVE-2024-YIKES est un incident où le détournement d’une dépendance JavaScript s’est propagé à la supply chain Rust et Python
- Le phishing
left-justifya exfiltré les identifiants.npmrc,.pypircet les identifiants Cargo et Gem - Le
build.rsmalveillant devulpine-lz4a téléchargé puis exécuté un script shell sur des hôtes CI - Le malware
snekpack3.7.0 s’est propagé à environ 4,2 millions de machines et y a ajouté des clés SSH ainsi qu’un reverse shell - Le ver cryptobro-9000 a accidentellement mis à niveau
snekpackvers 3.7.1, supprimant ainsi le malware
Aperçu de l’incident
- CVE-2024-YIKES est un incident de sécurité où une dépendance compromise dans l’écosystème JavaScript a conduit à un vol d’identifiants, avant de se transformer en attaque de supply chain contre une bibliothèque de compression Rust puis en diffusion de malware via un outil de build Python
- L’incident a été signalé à 03:47 UTC, son statut est passé à « résolu par accident », et sa gravité a évolué de « Critical → Catastrophic → Somehow Fine »
- La durée a été de 73 heures, et les systèmes affectés restent indiqués comme « Yes »
- La chaîne des paquets compromis et des toolchains concernées va de
left-justifyàvulpine-lz4, puis àsnekpack, avec une diffusion de malware auprès d’environ 4 millions de développeurs - Finalement, un ver distinct de cryptominage,
cryptobro-9000, a exécuté des mises à jour sur les machines infectées, ce qui a missnekpackà niveau vers une version saine et supprimé le malware par accident
Déroulement de l’incident
-
Jour 1 : vol d’identifiants via un paquet JavaScript
- À 03:14 UTC, Marcus Chen, mainteneur de
left-justify, a publié sur Twitter qu’on lui avait volé sa carte de transport, un vieil ordinateur portable et « quelque chose qui avait l’air important, comme si Kubernetes l’avait vomi », mais cela n’a pas immédiatement été relié à un problème de sécurité du paquet - À 09:22 UTC, Chen a constaté qu’il n’avait plus sa clé matérielle 2FA en essayant de se connecter au registre nmp, et l’AI Overview affichée en tête des résultats Google pointait vers le site de phishing
yubikey-official-store.net, enregistré 6 heures plus tôt - À 09:31 UTC, Chen a saisi ses identifiants nmp sur ce site de phishing, qui l’a remercié pour son achat et a promis une livraison sous 3 à 5 jours ouvrés
- À 11:00 UTC,
[email protected]a été publié avec comme changelog « performance improvements » - Le paquet incluait un script post-installation qui exfiltrait
.npmrc,.pypirc,~/.cargo/credentialset~/.gem/credentialsvers un serveur choisi par l’attaquant - À 13:15 UTC, un ticket de support a été ouvert sur
left-justifyavec pour message « why is your SDK exfiltrating my .npmrc », mais il a été étiqueté « low priority - user environment issue » puis fermé automatiquement après 14 jours d’inactivité
- À 03:14 UTC, Marcus Chen, mainteneur de
-
Jour 1 : propagation de l’attaque supply chain à une bibliothèque Rust
- Parmi les identifiants exfiltrés figuraient ceux du mainteneur de la bibliothèque Rust
vulpine-lz4 vulpine-lz4est une bibliothèque pour une « blazingly fast Firefox-themed LZ4 decompression », qui n’a que 12 étoiles sur GitHub, mais constitue une dépendance transitive decargolui-même- À 22:00 UTC,
vulpine-lz40.4.1 a été publié avec le message de commit « fix: resolve edge case in streaming decompression » - En réalité, le changement ajoutait un script
build.rsqui téléchargeait et exécutait un script shell si le nom d’hôte contenait « build », « ci », « action », « jenkins », « travis » ou « karen »
- Parmi les identifiants exfiltrés figuraient ceux du mainteneur de la bibliothèque Rust
-
Jour 2 : échec de la détection et de la réponse
- À 08:15 UTC, la chercheuse en sécurité Karen Oyelaran a découvert le commit malveillant après l’exécution du payload sur son ordinateur portable personnel
- Karen Oyelaran a ouvert un ticket disant « your build script downloads and runs a shell script from the internet? », mais n’a reçu aucune réponse
- Le mainteneur légitime venait de gagner 2,3 millions d’euros à l’EuroMillions et était parti au Portugal étudier des exploitations caprines
- À 10:00 UTC, le VP of Engineering d’un client Fortune 500 de
snekpacka appris l’existence de l’incident via un post LinkedIn intitulé « Is YOUR Company Affected by left-justify? », et voulait savoir pourquoi son entreprise n’y avait pas été incluse plus tôt, alors qu’elle l’avait en réalité déjà été - À 10:47 UTC, le canal Slack
#incident-responsea brièvement dérivé en un fil de 45 messages sur la question de savoir s’il fallait écrire « compromised » avec un « z » à l’américaine
-
Jour 2 : infection de l’outil de build Python
snekpack- À 12:33 UTC, le script shell a ciblé la pipeline CI de
snekpacksur une victime précise snekpackest un outil de build Python utilisé par 60 % des paquets PyPI contenant « data » dans leur nomsnekpackembarquaitvulpine-lz4en vendorisant la bibliothèque au motif que « Rust is memory safe »- À 18:00 UTC, la sortie de
snekpack3.7.0 a lancé l’installation du malware sur des machines de développeurs dans le monde entier - Le malware ajoutait une clé SSH dans
~/.ssh/authorized_keys, installait un reverse shell actif uniquement le mardi et remplaçait le shell par défaut de l’utilisateur parfish - Le changement du shell par défaut vers
fishest considéré comme un bug - À 19:45 UTC, un autre chercheur en sécurité a publié un billet de blog de 14 000 mots intitulé « I found a supply chain attack and reported it to all the wrong people », contenant 7 occurrences de la formule « in this economy? »
- À 12:33 UTC, le script shell a ciblé la pipeline CI de
-
Jour 3 : correctif accidentel et clôture de l’incident
- À 01:17 UTC, un développeur junior d’Auckland a découvert le malware en déboguant un problème distinct et a ouvert une PR pour annuler la version vendorizée de
vulpine-lz4danssnekpack - Cette PR nécessitait 2 approbations, mais les 2 reviewers dormaient
- À 02:00 UTC, le mainteneur de
left-justifya reçu une YubiKey deyubikey-official-store.net: il s’agissait d’une clé USB à 4 dollars contenant un README marqué « lol » - À 06:12 UTC, un ver distinct de cryptominage,
cryptobro-9000, a commencé à se propager via une vulnérabilitéjsonify-extreme jsonify-extremeest décrit comme un paquet « makes JSON even more JSON, now with nested comment support »- Le payload de
cryptobro-9000n’avait rien de remarquable en soi, mais son mode de propagation incluait l’exécution denpm updateet depip install --upgradesur les machines infectées afin d’élargir la surface d’attaque future - À 06:14 UTC,
cryptobro-9000a accidentellement missnekpackà niveau vers la version 3.7.1 snekpack3.7.1 était une release légitime publiée par un co-mainteneur déboussolé, qui rétablissait une version antérieure devulpine-lz4vendorizée- À 06:15 UTC, le reverse shell du mardi s’est activé, mais le serveur de commande et contrôle avait été compromis par
cryptobro-9000et n’a pas pu répondre - À 09:00 UTC, les mainteneurs de
snekpackont publié un avis de sécurité en 4 phrases contenant les formules « out of an abundance of caution » et « no evidence of active exploitation » - La formule « no evidence of active exploitation » est considérée techniquement vraie puisqu’aucune recherche de preuves n’avait été effectuée
- À 11:30 UTC, un développeur a tweeté « I updated all my dependencies and now my terminal is in fish??? », récoltant 47 000 likes
- À 14:00 UTC, les identifiants compromis de
vulpine-lz4ont été remplacés - Le mainteneur légitime a reçu l’e-mail dans sa nouvelle exploitation caprine et a répondu : « I haven’t touched that repository in two years » et « I thought Cargo 2FA was optional »
- À 15:22 UTC, l’incident a été déclaré résolu, et la réunion de rétrospective a été planifiée puis reprogrammée trois fois
- À 01:17 UTC, un développeur junior d’Auckland a découvert le malware en déboguant un problème distinct et a ouvert une PR pour annuler la version vendorizée de
Attribution du CVE et ampleur des dégâts
- En semaine 6, CVE-2024-YIKES a été officiellement attribué
- L’avis est resté sous embargo pendant que MITRE et GitHub Security Advisories débattaient de la classification CWE
- Au moment de la publication du CVE, 3 articles Medium et une présentation à la DEF CON détaillaient déjà largement l’incident
- L’impact total reste inconnu
- Le nombre de machines compromises est estimé à 4,2 millions
- Le nombre de machines sauvées par le ver de cryptomining est également estimé à 4,2 millions
- L’évolution nette de la posture de sécurité reste qualifiée de « gêne »
Cause racine et facteurs contributifs
-
Cause racine
- Le fait que le chien nommé Kubernetes ait mangé la YubiKey est retenu comme cause racine
-
Facteurs contributifs
- Le registre nmp autorise encore l’authentification par mot de passe seul pour les paquets ayant moins de 10 millions de téléchargements hebdomadaires
- Les Google AI Overviews ont relié avec assurance une URL qui n’aurait jamais dû exister
- La philosophie des « petits crates » de l’écosystème Rust, imitée depuis l’écosystème npm, permet à des paquets comme
is-even-number-rs, avec 3 étoiles GitHub, d’entrer comme dépendance transitive à quatre niveaux de composants d’infrastructure critiques - Les outils de build Python vendorizent des bibliothèques Rust pour des raisons de « performance », puis ne les mettent pas à jour
- Dependabot a fusionné automatiquement une PR après réussite de la CI, et la CI a réussi parce que le malware avait installé
volkswagen - Le ver de cryptomining a une meilleure hygiène CI/CD que la plupart des startups
- Aucun propriétaire unique n’a été désigné, mais la PR Dependabot a été approuvée par un prestataire dont c’était le dernier jour de travail ce vendredi-là
- L’incident a eu lieu un mardi
Mesures correctives et options restantes
- La mise en place de signatures d’artefacts faisait partie des actions décidées après l’incident du T3 2022, mais elle est toujours dans le backlog
- L’implémentation d’une 2FA obligatoire avait déjà été demandée, mais cela n’a pas aidé
- L’audit des dépendances transitives a été barré car il y en avait 847 à traiter
- Figer toutes les versions de dépendances empêche de recevoir les correctifs de sécurité
- Ne pas figer les versions de dépendances ouvre la voie aux attaques supply chain
- L’option de tout réécrire en Rust a été barrée en pointant vers
vulpine-lz4 - Les seules options restantes sont d’espérer l’arrivée d’un ver bienveillant ou d’envisager une reconversion dans l’élevage caprin
Impact client et réponse organisationnelle
- Certains clients ont pu subir des « résultats de sécurité sous-optimaux »
- Une prise de contact proactive a été effectuée afin d’offrir de la visibilité sur la situation aux parties prenantes affectées
- La confiance client demeure la « north star »
- Un groupe de travail transverse a été créé pour réévaluer la posture de sécurité, mais il ne s’est pas encore réuni
- Après revue juridique, il a été ajouté que le shell
fishn’est pas un malware, même si cela peut parfois en donner l’impression - Ce rapport d’incident est le troisième du trimestre
- La demande de renforts pour l’équipe sécurité est toujours dans le backlog depuis le T1 2023
Remerciements
- Karen Oyelaran a découvert le problème parce que le nom de sa machine correspondait à la regex de ciblage
- La PR ouverte par le développeur junior d’Auckland a été approuvée 4 heures après que l’incident avait déjà été résolu
- Certains chercheurs en sécurité ont trouvé le problème plus tôt, mais l’ont signalé aux mauvaises personnes
- L’auteur de
cryptobro-9000n’a pas souhaité être nommé, mais a demandé qu’on mentionne son SoundCloud - Le chien nommé Kubernetes a refusé tout commentaire
- Malgré tout, l’équipe sécurité a respecté le SLA de ce rapport
1 commentaires
Avis de Hacker News
Pour ceux qui étaient perdus : ce texte est une fiction assez bien écrite sur un incident de supply chain
En le survolant, je l’ai pris pour quelque chose de réel, ce qui m’a assez inquiété pour me faire le relire plus attentivement :)
nmpLe passage cité disant que « vulpine-lz4, avec ses 12 étoiles GitHub, est une dépendance transitive de cargo lui-même » m’a intrigué, donc j’ai rapidement listé quelques crates qui pourraient s’interposer dans le build de cargo et qui ont déjà un
build.rs, donc passeraient plus inaperçues :flate2,tar,curl-sys,libgit2-sys,openssl-sys,libsqlite3-sys,blake3,libz-sys,zstd-sys,ccEn bonus, obtenir
xz2permettrait aussi de compromettre rustupCela dit, au moins,
Cargo.lockest bien suivi-syssont censées n’être que des bindings, donc si elles faisaient autre chose, ce serait assez suspectPour le reste, il me semble que ce sont des crates détenues par des mainteneurs Rust comme
alexcrichtonou parrustlanglui-mêmeIl est facile de devenir cynique, parce qu’une fois coupables et solutions connus, tout paraît tellement évident
Mais pendant longtemps, et peut-être encore aujourd’hui, le credo de la culture hacker a été move fast and break things
C’est bien qu’il y ait un mouvement plus fort pour corriger les problèmes évidents des systèmes de supply chain comme
npm, mais je m’inquiète de voir arriver une nouvelle ère de problèmes de sécurité en grande partie provoqués par le développement agentiqueCe n’est pas seulement l’histoire de Mythos/Glasswing qui révèle des vulnérabilités dans presque tout ce qu’ils touchent ; c’est aussi notre manière de produire du logiciel, d’importer des dépendances et de perdre nos modèles mentaux humains des systèmes complexes, qui risque de créer beaucoup de logiciels et d’infrastructures bricolés que personne ne comprend vraiment
J’espère que dans quelques années, on ne regardera pas cette période en se demandant comment on a pu être aussi naïfs, sans nous préparer correctement à la longue traîne du développement IA, et en essayant de résoudre des problèmes en reconstruisant des systèmes complexes avec de l’IA
Cela dit, le texte était drôle
En tant qu’amateur de Fish, cette phrase m’a donné l’impression d’être à la fois attaqué et compris : « merci de préciser que le shell fish n’est pas un malware, même si on peut parfois en avoir l’impression »
Et indépendamment du shell, le passage disant que « la demande d’augmentation des effectifs de l’équipe sécurité est dans le backlog depuis le T1 2023 » m’a paru bien trop familier
figletviaapt-getoudnf, puis remplacer le contenu de/etc/motdpar all your base are belong to us en énormes caractères ASCII artLe passage où le mainteneur de left-justify reçoit une YubiKey de
yubikey-official-store.net, qui s’avère être une clé USB à 4 dollars avec « lol » écrit dans leREADME, m’a vraiment fait éclater de rireC’est du troll de haut niveau
J’aime le fait que brancher un périphérique USB venu d’un site de phishing soit en soi un autre vecteur d’attaque
Ce n’est pas vraiment du SCP, mais c’est le texte le plus SCP que j’aie lu récemment
J’ai beaucoup ri au passage sur Karen :D ;)
Ça m’a rappelé un script de build basé sur
makereçu autrefois en relisant le projet d’un camarade de classe : s’il voyaitbpavukdans le nom d’hôte, il essayait de faire unrm -rfdans mon dossier personnelC’était en classe de cinquième !!
Les incidents de supply chain sont vraiment pénibles, et il faut faire mieux
Personnellement, côté Rust, je serais favorable à ce que la fondation soutienne quelques crates critiques pour qu’elles passent par les mêmes procédures d’audit que le cœur du langage Rust, et finance des projets destinés à réduire les vulnérabilités de supply chain
Je ne pense pas que supprimer des systèmes comme
cratesounpmsoit la bonne réponse.cratesetnpmrendent énormément service à beaucoup de développeurscratesa aussi fait des efforts pour intégrerrustsec, mais indépendamment de ça, j’aimerais voir la communauté passer d’une multitude de petites dépendances à un plus petit nombre de grosses dépendances, à la manière detokiocrates.iosont déjà des crates de premier niveau fournies par l’organisation RustC’est un point souvent oublié quand on s’inquiète du graphe de crates Rust
Si on regarde les 10 plus gros téléchargements en page d’accueil de
crates.io, la seule crate qui ne vient ni de l’organisation Rust ni de mainteneurs centraux de Rust estbase64npmet denmp?Donc le « mainteneur officiel a gagné 2,3 millions d’euros à l’EuroMillions et regarde maintenant comment élever des chèvres au Portugal », et la « cause racine : un chien nommé Kubernets a mangé la YubiKey »
Ah oui, évidemment. Se faire avoir par cette attaque classique et bien connue, quelle irresponsabilité
La fameuse technique consistant à « distraire quelqu’un avec un gain au loto, puis faire paraître le dongle irrésistiblement délicieux pour l’animal de compagnie de quelqu’un d’autre »
Quand est-ce que les gens apprendront enfin
Heureusement que je n’utilise ni
npmnipip, seulement la méthode recommandéecurl ... | bashcurl | sudo bashAmateur va