Skip to main content

Comprendre les vulnérabilités de prise de contrôle du système de fichiers dans le gestionnaire de paquets JavaScript npm

Écrit par
prioritize vulns header

7 janvier 2020

0 minutes de lecture

Le 11 décembre 2019, une faille de sécurité touchant tous les principaux gestionnaires de paquets JavaScript (npm, yarn et pnpm) a été rendue publique. Découverte par le chercheur en sécurité Daniel Ruf, cette vulnérabilité permet à des acteurs malveillants de recourir à diverses méthodes pour écraser arbitrairement des fichiers.

Dans cet article :

Comment fonctionnent les paquets en ligne de commande Node.js ?

Les paquets npm spécifient souvent une clé bin dans le fichier manifeste du paquet, package.json. Le client du gestionnaire de paquets — npm, par exemple, ou ses alternatives — utilise cette clé bin pour déclarer les exécutables disponibles dans l’invite de commande, via la variable d’environnement globale $PATH.

Vous avez probablement déjà rencontré cette fonctionnalité si vous avez installé des paquets en ligne de commande à l’échelle globale, comme Angular CLI via @angular/cli, typescript ou Snyk CLI via snyk — : ils sont alors accessibles partout dans votre chemin d’accès, quel que soit le répertoire du projet npm. Pour comprendre l’utilisation de la clé bin, nous consultons sur unpkg le fonctionnement du projet Angular CLI en parcourant son fichier package.json.

Le fichier package.json du package @angular/cli met en évidence la clé bin, qui associe la commande ng à ./bin/ng.
Champ package.json de ng-cli illustrant l’utilisation de la clé JSON « bin » pour définir un exécutable lors de l’installation de ce package par npm (source : unpkg https://unpkg.com/browse/@angular/cli)

Comme vous pouvez le voir ci-dessus, dans cette version du paquet, le fichier manifeste package.json déclare un fichier exécutable nommé ng, qui pointe vers un fichier inclus dans le paquet et disponible à l’emplacement ./bin/ng.

Ce fichier JavaScript ./bin/ng est rendu exécutable par l’utilisateur grâce à l’ajout, au début du fichier, d’une instruction Unix Shebang. Celle-ci indique au shell quel interpréteur utiliser pour évaluer le fichier. Pour les applications basées sur Node.js, le binaire Node.js est installé sur le système d’exploitation de l’utilisateur.

Pour Angular CLI, le contenu du fichier exécutable apparaît dans l’image suivante :

Code source de l’exécutable ng d’Angular CLI affichant une vérification de la version de Node.js et un message d’erreur pour les versions non prises en charge.
(source : https://unpkg.com/browse/@angular/cli@6.0.4/package.json)

Quel est l’impact de cette faille de sécurité sur le client du gestionnaire de paquets npm ?

Pour comprendre les implications de cette vulnérabilité, nous devons examiner npm d’un peu plus près, et notamment le mécanisme qui permet à npm de rendre disponibles les exécutables installés.

Le client npm gère les « bins » déclarés par les paquets installés globalement dans un répertoire spécifique. Il s’en sert pour créer des liens symboliques entre les exécutables de ces paquets et les liens présents dans ce répertoire.

Pour déterminer quel répertoire héberge ces exécutables, nous utilisons le client npm comme suit :

$ npm bin --global
/Users/lirantal/.nvm/versions/node/v10.16.3/bin

En examinant la variable d’environnement $PATH disponible dans votre shell, vous trouverez une entrée correspondant au répertoire de votre système d’exploitation. C’est ainsi que les paquets installés globalement qui déclarent des bins sont accessibles depuis n’importe quel répertoire du système.

Maintenant que nous disposons de ces informations, on peut se demander si un paquet peut déclarer un fichier exécutable bin fourni par un autre paquet. C’est précisément ce que Daniel cherchait à comprendre, et ce qui l’a amené à découvrir des vulnérabilités permettant l’écrasement arbitraire de fichiers dans les principaux gestionnaires de paquets : npm, yarn et pnpm.

Comment cette faille de sécurité de npm se concrétise-t-elle ?

Chez Snyk, nous reproduisons cette vulnérabilité d’écriture arbitraire de fichiers et montrons comment l’exploitation fonctionne, grâce aux preuves de concept fournies à l’équipe de sécurité de Snyk par Daniel.

Le premier paquet définit un ensemble global d’exécutables comme suit :

{
  "name": "binary-replacer",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Daniel Ruf <mac1@daniel-ruf.de>",
  "license": "MIT",
  "bin": {
    "curl-test": "./bin/index.js",
  }
}

L’exécutable curl-test se contente d’afficher du texte dans la console :

#!/usr/bin/env node
console.log('hi')

Si nous l’installons globalement avec npm install -g binary-replace, l’exécution de la commande curl-test dans le shell doit afficher hi à l’écran.

Imaginons maintenant un autre paquet, binary-replacer-2, qui définit lui aussi un exécutable avec exactement la même clé bin que le premier : curl-test

{
  "name": "binary-replacer-2",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Daniel Ruf <mac1@daniel-ruf.de>",
  "license": "MIT",
  "bin": {
    "curl-test": "./bin/index.js",
  }
}

Lorsque l’utilisateur installe ce paquet globalement, npm remplace le lien symbolique précédent par l’exécutable fourni par ce paquet, qui est inoffensif dans le cadre de cette démonstration :

#!/usr/bin/env node
console.log('hi 2')

Mais que se passerait-il si un paquet malveillant ciblait certains des paquets globaux les plus connus ? Les possibilités sont nombreuses : du paquet now de Zeit à l’interface en ligne de commande fkill de Sindre Sorhous.

Daniel a également décrit de nombreuses variantes de cette vulnérabilité dans npm, yarn et pnpm. Par exemple, que se passerait-il si, au lieu de la clé curl-test, nous la remplacions par le chemin relatif d’un lien ?

 "bin": {
    "../../aaa": "/bin/date"
  }

Ou si nous définissions plutôt la clé comme un chemin absolu vers un outil en ligne de commande connu, souvent utilisé par l’utilisateur depuis une invite shell, par exemple :

"bin": {
  "/usr/bin/date": "./fake-date"
}

Il faut saluer le fait que pnpm, dirigé par son seul développeur Zoltan Kochan, adopte généralement un comportement raisonnable et n’est vulnérable que lorsqu’un chemin relatif est fourni. Cela reste toutefois un problème ; il est donc également possible de passer à des versions corrigées de npm.

Pourquoi cette faille de sécurité de npm est-elle si grave ?

Cette vulnérabilité est d’autant plus préoccupante que l’écrasement arbitraire de fichiers se produit même pour les paquets installés avec l’option de ligne de commande npm —ignore-scripts, qui devrait pourtant empêcher les binaires malveillants de procéder de la même manière.

En outre, même si nous avons évoqué le cas des paquets installés globalement et de leurs exécutables, le problème concerne tout autant les dépendances transitives de votre projet. Lorsqu’elles sont installées avec une commande npm install classique, un paquet peut écraser arbitrairement des fichiers dans le répertoire du projet ou en dehors. Cela peut notamment conduire à injecter des logiciels malveillants, à modifier des fichiers de verrouillage ou, plus généralement, à corrompre le système de fichiers.

Suis-je concerné et que dois-je faire ? 

Vous risquez d’être concerné dans deux cas :

  1. Vous installez un paquet malveillant, soit parce que vous avez été manipulé pour le faire, soit parce qu’un attaquant a publié un paquet au nom trompeur, proche de celui d’un paquet populaire, que vous finissez par installer.

  2. Un paquet non malveillant est compromis et son fichier package.json est modifié pour que ses clés bin écrasent des fichiers et incluent un fichier malveillant à exécuter. C’est très improbable, certes, mais c’est déjà arrivé deux fois : [1], [2]

L’impact de cette vulnérabilité a également entraîné la publication de mises à jour de sécurité de Node.js, car le client du gestionnaire de paquets npm est fourni avec Node.js et nécessitait une mise à jour vers la version corrigée 6.13.4 de npm.

Daniel a d’abord communiqué ses découvertes sur la faille à l’équipe de recherche en sécurité de Snyk afin de coordonner la divulgation publique responsable auprès de tous les projets et responsables de ces gestionnaires de paquets. Il a également fourni plus d’informations sur les types d’attaques dans son article de blog.

Si vous utilisez l’une des versions suivantes de npm, yarn ou pnpm, vous êtes vulnérable et devez impérativement procéder à une mise à niveau immédiatement :

Il est rare d’ajouter npm, yarn ou pnpm comme dépendance d’un projet. Toutefois, si Snyk surveille votre projet et détecte une version vulnérable de l’un de ces outils, vous en serez informé par les alertes régulières de Snyk. De plus, si vous avez connecté votre dépôt GitHub (ou Bitbucket), nous créons automatiquement une pull request pour mettre à niveau ces gestionnaires de paquets vers leurs versions corrigées.

Nous vous recommandons également d’adopter de bonnes pratiques de sécurité pour les développeurs lorsque vous utilisez des gestionnaires de paquets comme npm. Pour vous simplifier la tâche, nous avons compilé des règles et bonnes pratiques de sécurité à suivre dans notre guide 10 bonnes pratiques de sécurité pour npm.

Vous pensez avoir découvert une vulnérabilité dans un paquet open source ? Chez Snyk, nous accordons une grande importance à la communauté de la sécurité et sommes convaincus que la divulgation responsable des vulnérabilités dans les paquets open source contribue à protéger la sécurité et la confidentialité des utilisateurs. Si vous pensez avoir découvert une vulnérabilité dans un paquet open source, vous pouvez la signaler dans le programme de divulgation des vulnérabilités des paquets Snyk Open Source, et nous nous occuperons du reste ! https://snyk.io/vulnerability-disclosure/

Lancez-vous dans les compétitions Capture The Flag

Apprenez à résoudre des défis de capture du drapeau en regardant à la demande notre atelier virtuel d’initiation.

Lire la suite

blog feature snyk container custom base recommendations
Blog

Découvrez Evo Agentic AppSec : une sécurité au rythme du développement de l’IA

Le développement piloté par l’IA dépasse les capacités des processus de sécurité traditionnels. Agentic AppSec de Snyk s’appuie sur des agents de sécurité pour détecter, corriger et vérifier les vulnérabilités en continu, tandis que les équipes définissent les exigences.

blog feature ai violet
Blog

VulnBump : les agents IA peuvent-ils corriger les dépendances vulnérables sans casser la build ?

VulnBump évalue des agents IA sur 307 mises à niveau réelles de dépendances. Une correction n’est validée que si la vulnérabilité disparaît et que la build et les tests restent au vert.

Blog

Les modèles de pointe ont trouvé les vulnérabilités. Seul l’attaquant a trouvé les chaînes d’exploitation.

L’analyse statique a détecté les failles, mais seuls des tests d’attaque en conditions réelles ont prouvé comment elles pouvaient être enchaînées pour provoquer des compromissions. Comparaison d’Evo COS, de Claude Security et de Claude Code Security.