Connexion Premium

Nouvelle attaque contre NPM, cette fois à une cadence industrielle

Les temps modernes

Nouvelle attaque contre NPM, cette fois à une cadence industrielle

Illustration : Flock

Alors que le dépôt NPM était déjà marqué par une importante attaque le 8 septembre, une autre attaque est en cours depuis 48 heures. Plusieurs centaines de paquets ont été compromis, les pirates à l’origine de la campagne ayant industrialisé le processus, au point de l’avoir transformé en ver. Explications.

L’écosystème NPM (Node Package Manager) fait actuellement face à une nouvelle attaque sophistiquée. De type chaine d’approvisionnement, elle consiste à infecter un maillon de la chaine de distribution en amont, afin que l’infection se répande automatiquement en aval.

Cette nouvelle attaque, d’un genre différent de celle que nous rapportions récemment, reprend dans les grandes lignes le modus operandi de l’attaque du 27 aout. À ceci près que les pirates ont entièrement automatisé le processus, conduisant à un vol de nombreuses informations d’authentification et à leur publication dans des dépôts publics, créés automatiquement ici aussi par les pirates.

Ce comportement de ver informatique a donné son nom à cette attaque : Shai-Hulud, en référence au célèbre ver des sables de l’univers de Dune. L’ingénieur Daniel Pereira a été le premier à signaler un problème le 15 septembre, avant que les sociétés Socket et StepSecurity prennent le relai. Elles notaient d’abord que 40 paquets avaient été compromis, avant que le chiffre s’envole progressivement : dans la seule journée du 16 septembre, le nombre avait atteint 200 paquets, avant de grimper à près de 500 en fin de journée.

Que fait Shai-Hulud ?

Le ver est auto-répliquant et a plusieurs missions. La principale est de voler des informations d’authentification et de les publier sur GitHub dans des dépôts créés pour l’occasion et rendus publics, afin que tout le monde puisse piocher dedans.

Plus en détail, le ver commence par analyser l’hôte et son environnement d’intégration continue pour chercher tout ce qui ressemble à un secret (au sens cybersécurité du terme, tout ce qui touche à l’authentification). Le ver scanne également, via Trufflehog, les points de terminaison des métadonnées des environnements cloud principaux (dont AWS et GCP) pour récupérer des jetons d’identification (GITHUB_TOKEN, NPM_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY…).

Vient ensuite l’exfiltration, en deux phases. Le ver crée un dépôt Shai-Hulud sur le compte GitHub compromis et y envoie, via un commit, un fichier JSON collectant tout ce qui a été volé : variables d’environnement, éléments d’authentification, informations système, etc. Via un workflow GitHub Actions, ces informations sont envoyées vers un serveur contrôlé par les pirates. Une copie est écrite dans les logs Actions.

Un mécanisme performant de propagation

Enfin, la phase de propagation. Si le vol d’informations a pu mener à des jetons npm, le ver les utilise pour tenter de s’y répliquer. S’il y parvient, toute la chaine recommence, expliquant que des centaines de paquets aient été compromis. Chaque fois qu’un compte privé est ainsi compromis, il est rendu public par le ver, qui en change les paramètres.

« Les versions compromises incluent une fonction (NpmModule.updatePackage) qui télécharge une archive de paquets, modifie package.json, injecte un script local (bundle.js), recompresse l’archive et la republie, permettant ainsi la trojanisation automatique des paquets en aval », explique la société Socket.

Les recommandations faites aux développeurs sont nombreuses, résume Trend Micro : auditer toutes les dépendances (en particulier les paquets mis à jour récemment), révoquer et faire tourner les informations d’authentification (surtout pour les comptes NPM), surveiller d’éventuels signes de présence de Trufflehog ou d’autres outils de balayage, se tenir au courant avec des sources fiables d’informations (dont le registre officiel de NPM), et renforcer la protection des accès ainsi que les politiques de sécurité. Il est notamment conseillé d’activer l’authentification à facteurs multiples (MFA) pour l’ensemble des développeurs et des points d’accès CI/CD.

Encore et toujours du phishing

Comment toute cette attaque a commencé ? Exactement comme les précédentes : par un e-mail frauduleux, demandant au développeur de renouveler son authentification à deux facteurs. Un lien proéminent l’emmenait vers une page ressemblant trait pour trait à celle de NPM, mais permettait aux pirates de capter le jeton d’authentification et les identifiants. Après quoi, les informations étaient utilisées pour accéder au dépôt et débuter l’infection.

En l’occurrence, c’est le dépôt du paquet ctrl/tinycolor qui a été contaminé en premier. Via une mise à jour malveillante, le paquet contenait une fonction NpmModule.updatePackage) capable d’enchainer les opérations : télécharger un tarball, modifier le fichier package.json, injecter un script local, rempaqueter le tout et le republier. C’est ce comportement qui a été repéré initialement par Daniel dos Santos Pereira. Mais le mal était déjà fait, car ctrl/tinycolor est un paquet populaire : 2,2 millions de téléchargements par semaine en moyenne.

Car les paquets téléchargés et installés sur des postes clients contiennent également une charge utile leur étant destinée. Comme pour l’attaque précédente, on y trouve un voleur de cryptomonnaies, qui permet les interceptions des transferts au sein du navigateur et leur orientation vers des portefeuilles contrôlés par les pirates.

Vers une empreinte durable ?

On ne connait pas encore l’ampleur des conséquences de cette campagne. Shai-Hulud risque cependant de remettre en question le modèle de gestion de nombreux dépôts et accentue les questionnements autour de la sécurité. Toutes les sociétés ayant formulé des recommandations sur le sujet reviennent toujours à deux consignes : la généralisation de l’authentification forte à facteurs multiples et la surveillance continue de l’activité sur les dépôts.

Par le nombre de paquets NPM touchés, l’attaque pourrait également remettre en cause le fonctionnement habituel de l’écosystème open source et à sa confiance inhérente. À une époque où les applications web (encapsulées ou non) sont omniprésentes, une contamination de la chaine d’approvisionnement peut signifier rapidement des millions de machines infectées.

Et si cette contamination vous rappelle, en d’autres circonstances, le fiasco mondial de la panne CrowdStrike, le dépôt de l’entreprise a été touché par Shai-Hulud, de multiples paquets ayant été contaminés.

Pour l’instant, on ignore si l’attaque du 8 septembre peut être considérée comme une première manifestation de la nouvelle. La méthode de départ est la même, mais l’exécution technique semble bien plus sophistiquée aujourd’hui. Dans son déroulement, Shai-Hulud ressemble davantage à l’attaque de fin août, même si – là encore – le périmètre et l’automatisation sont bien supérieurs. Si les auteurs sont les mêmes, alors les attaques précédentes ont peut-être été des galops d’essai.

Commentaires (33)

votre avatar
si Trufflehog detecte les secrets et les envoie, pourquoi github/gitlab/NPM ne bloque pas tous les dépôts qui ne sont pas "verified without leaked secret" ?
votre avatar
Comme dit Daniel Stenberg, le développeur de curl : « Who could have figured out that automatically downloading half the internet and ten thousand always-changing dependencies every time you build could actually be a weakness? »
votre avatar
Ouais, enfin, ce n'est pas spécifique à Javascript. Rust, par exemple, a pile le même problème (et d'autres aussi, bien sûr).
votre avatar
+1 pour Rust, il souvent cité pour sa gestion rigoureuse de la mémoire et la sécurité qu'elle apporte mais par contre des qu'on build un gros projet le nombre de dépendance se compte souvent en centaine voir en millier ce qui n'est pas forcément très rassurant non plus.

C'est des extrème mais le Cargo.lock de Zed github.com GitHub il n'a pas grand chose a envier (façon de dire) au package-lock de VS Code github.com GitHub (qui contient le célèbre is-array...)
votre avatar
Ouais, enfin, ce n'est pas spécifique à Javascript. Rust, par exemple, a pile le même problème (et d'autres aussi, bien sûr).
Ce qui est d'autant plus inquiétant vu de ma fenêtre puisque le langage est constamment associé à "plus sécurisé".

J'avais déjà pointé ça dans des articles à son sujet : à trop répéter cet argument (qui est sûrement vrai, ce n'est pas mon domaine donc je ne saurais le remettre en cause), on endort sa vigilance.
votre avatar
Des développeurs qui se font encore avoir par du phishing, ils ne doivent pas être très compétents ou alors ils vivent depuis 10 ans dans une caverne sans accès internet ...
votre avatar
Ou bien ils sont continuellement sous pression et dans l'urgence…
Ça rappelle quelque chose à ceux qui bossent dans l'IT ? 😉
votre avatar
On peut avoir effectivement ce genre de réflexion, mais dès que tu passes sur des grands nombres, les stats disent bien que cela finira par réussir.
votre avatar
Ça s’appelle du victim shaming et ce n’est vraiment pas cool. Personne n’est à l’abri d’une attaque par hameçonnage et la compétence technique de la victime dans un domaine donné n’a pas grand-chose à voir avec la choucroute.
votre avatar
Toujours l'occasion de rappeler que même Troy Hunt, consultant en cyber et auteur de Have I Benn Pwnd, s'est fait avoir pas plus tard qu'au mois de mars (cf son article de blog : "A Sneaky Phish Just Grabbed my Mailchimp Mailing List")
votre avatar
Prévisible, prévu, arrivu.

Même si on me disait "mais nonnnnnnnnn y'a aucun problème avec cette façon de codeeeeeeeer" 🔥
votre avatar
Quelle "façon" ?

Si on parle de l'urgence permanente et la pression productiviste, alors le problème est d'ampleur au niveau des entreprises.
Si on parle du langage JavaScript & dérivé NodeJS et de son écosystème, alors le problème est d'ampleur à ces niveaux.

Dans ces deux cas, je ne comprends toujours pas "façon".
votre avatar
Développer sans se soucier de "comment ça marche", "pourquoi ça marche"...
votre avatar
développer en utilisant 100 millions de dépendances aussi stupides et surfaites que is-array, isOdd, isEven, etc.
genre le gars code sans connaître son code ou savoir faire un modulo, c'est ça?
votre avatar
J'aime beaucoup le JavaScript, mais je ne supporte plus son écosystème... On peut plus lancer le moindre projet JS sans se récupérer plus d'un millier de dépendances (et même plusieurs versions des mêmes dépendances bien souvent)...

Et parfois pour des bouts de codes qui tiennent dans 1 tweet (ou dans un quart de toot suivant votre unité de mesure ^^)... Quand je dis ça j'ai des trucs comme isarray, leftpad (qui avait causé un sacré bazar à une époque), ou encore is-even (qui dépend de is-odd qui dépend de is-number) qui pourrait s'écrire en moins de 10 caractères...

Bref, l'écosystème JS actuel me rend fou /o\
votre avatar
is-odd

Tu devineras jamais ce que fait le module qui teste les chiffres pairs...
votre avatar
Oh bah justement si je sais, c'est bien pour ça que ça me rend chèvre ! 🐐️

Si les devs d'aujourd'hui ne sont même plus capables de faire un modulo ou d'inverser un booléen eux-mêmes, on a pas le postérieur sorti des ronces... 😖️
votre avatar
github.com GitHub

celui-là ?
votre avatar
Vu que Github refuse d'afficher le fichier chez moi tellement il est gros, j'imagine que c'est une liste des entiers pairs ?
votre avatar
non, c'est une suite de if( i == xxx) return true/false pour xxx allant de 0 à 375000
votre avatar
C'est même pire :

function isEven(number) {
if (number === "even" || number === "Even" || number === "eVen" || number === "evEn" || number === "eveN" || number === "EVen" || number === "EvEn" || number === "EveN" || number === "eVEn" || number === "eVeN" || number == "evEN" || number === "eVEN" || number === "EvEN" || number === "EVeN" || number === "EVEn" || number === "EVEN") return true;
else if(number === 0 || number === "0" || number === "zero" || number === "Zero" || number === "ZERO") return true;
else if(number === 1 || number === "1" || number === "one" || number === "One" || number === "ONE") return false;
else if(number === 2 || number === "2" || number === "two" || number === "Two" || number === "TWO") return true;



À ce niveau-là, ça fait pleurer tout court ! 😭
votre avatar
OMG j'étais pas prêt pour celui-là ! T_T
votre avatar
J'imagine (enfin j'espère) que ce genre de lib est à la base créé comme une blague.
Le problème c'est quand la blague se retrouve dans 10000 dependant
votre avatar
Cette lib est bien une blague. Les joies du code avaient fait un article dessus il y a quelques années : https://lesjoiesducode.fr/ivre-developpeur-ecrit-fonction-qui-pese-100-mo-pour-savoir-si-nombre-pair

On retrouve d'ailleurs une trace de cela dans le README du projet, à condition bien sûr de saisir l'ironie dans la partie About
votre avatar
On peut aussi avoir ce genre de réflexion sur Composer pour PHP non ? (vrai question je suis pas un spécialiste)
votre avatar
J'ai pas trop suivi PHP ces dernières années, mais j'ai pas l'impression qu'on soit à un niveau aussi extrême (des dépendances par millier, pour des fonctions ultra basiques)
votre avatar
J'ai installé la dernière version de Laravel 12 la semaine dernière et j'ai halluciné sur le nombre de composants PHP installés + Node et NPM
votre avatar
La principale est de voler des informations d’authentification et de les publier sur GitHub dans des dépôts créés pour l’occasion et rendus publics, afin que tout le monde puisse piocher dedans.
Je vois pas l'intérêt pour le hacker de faire ça car il perd en discrétion.
Quelqu'un peut m'éclairer là-dessus ?
votre avatar
Au pif, dénoncer une faille béante pour que les acteurs concernés réagissent et se décident à repenser tout l'écosystème niveau sécurité/authenticité/fiabilité ?

Dans le même genre, avec docker, il y a des tas de problèmes...
votre avatar
On peut toujours rêver.
votre avatar
Ça peut se tenir avec le fait qu'ils ne fassent "que" faire du vol de cryptomonaie.
votre avatar
C'est révélateur d'une merdification du monde logiciel, un aveu d'échec total de maîtrise.
votre avatar
un aveu d'échec total de maîtrise.
Tu résumes ici toute mon expérience dans l'IT avec les SI d'entreprise :D