Exploiter les paramètres par défaut non sécurisés de npm pour dérober les raccourcis clavier de macOS
28 juin 2023
0 minutes de lectureLes paquets npm malveillants et les dangers qu’ils représentent sont souvent évoqués : qu’il s’agisse de centaines de paquets malveillants Cobalt Strike de commande et de contrôle, de typosquattage ou de logiciels malveillants publiés sur le registre npm (ainsi que sur PyPI et d’autres registres). Pour aider les développeurs et les responsables de la maintenance à se protéger contre ces risques de sécurité, Snyk a publié un guide sur les bonnes pratiques de sécurité pour npm.
Cela étant dit, l’ampleur de l’attaque décrite ci-dessous, dont Yagiz Nizipli a averti des responsables de la maintenance de longue date, et le risque réel de compromission des données illustrent parfaitement l’importance de réduire les risques d’exécution de commandes arbitraires avec les gestionnaires de paquets, notamment via les hooks de cycle de vie postinstall de npm.
Scripts de cycle de vie de npm
Node Package Manager (npm) fournit aux développeurs et aux responsables de la maintenance des paquets un ensemble de scripts permettant de gérer les événements du cycle de vie d’un paquet. Ces scripts sont très utiles aux développeurs, car ils leur permettent d’effectuer différentes tâches ou configurations lors de l’installation d’un paquet. Par exemple, avec les scripts postinstall, les développeurs peuvent automatiser des tâches comme la compilation des ressources, la configuration des variables d’environnement, l’exécution de migrations ou toute autre tâche automatisable.
La propriété scripts d’un fichier package.json définit les commandes déclenchées par le cycle de vie du paquet et par les dépendances du paquet que vous développez. À ce jour, npm prend en charge un nombre limité de scripts de cycle de vie dans toute propriété scripts d’un fichier package.json.
Par souci de simplicité, la suite de cet article se concentre sur la commande postinstall. Toutefois, tous les concepts présentés s’appliquent également aux autres opérations du cycle de vie.
Incidents de sécurité passés
Plusieurs incidents très médiatisés ont eu des conséquences réelles pour les développeurs JavaScript, notamment :
L’incident de sécurité de cross-env découvert par Oscar Bolmsten.
L’attaque menée au moyen d’event-stream contre des développeurs d’applications de cryptomonnaie.
De nombreux autres incidents de sécurité liés à JavaScript et Node.js sont répertoriés dans le dépôt Awesome Node.js Security.
Sécurité des données au repos
Les spécialistes de la sécurité parlent de protection des données Data-at-rest lorsqu’elles sont stockées, par opposition aux données en transit ou en cours de traitement. Cette notion concerne la protection des informations sensibles stockées dans des bases de données, des systèmes de fichiers ou un stockage persistant. La sécurité des données au repos vise à empêcher tout accès non autorisé, toute divulgation ou toute altération des données lorsqu’elles sont inactives. Différentes mesures permettent de garantir cette sécurité, notamment :
Déchiffrement à la demande : déchiffrer uniquement les données nécessaires à la tâche en cours et conserver le reste sous forme chiffrée afin d’empêcher tout accès non autorisé.
Logique de contrôle d’accès : vérifier l’identité du demandeur à l’aide d’un mécanisme tel qu’un mot de passe, une authentification à deux facteurs ou la biométrie fournie par un système d’exploitation (comme Face ID), afin de limiter l’exposition de la ressource aux personnes non autorisées.
La surface d’attaque d’un développeur
Les bonnes pratiques du secteur nous imposent de suivre certains principes pour développer des applications. Elles présentent de nombreux avantages lorsque l’on travaille avec différentes équipes et différents développeurs, mais elles élargissent également la surface d’attaque.
Quelles données se trouvent sur le poste d’un développeur sans être chiffrées ?
Les variables d’environnement enregistrées dans des fichiers texte brut, comme
.env(accessibles via le paquetdotenv).Les fichiers de configuration des projets stockés au format JSON, comme
config.json.Les clés SSH permettant d’accéder à Github/Gitlab, disponibles dans le dossier
~/.ssh.Et… les raccourcis clavier de macOS !
Remplacements de texte dans macOS
Par défaut, macOS propose une fonctionnalité appelée Text Replacements, dissimulée dans l’application Préférences Système. Elle permet de remplacer rapidement un mot par un autre. J’ai récemment appris qu’un développeur d’une entreprise connue utilisait les remplacements de texte pour substituer le mot-clé @card aux informations de sa carte bancaire. Même si le numéro de carte, sans sa date d’expiration ni son cryptogramme visuel, ne permet pas à lui seul de dérober votre argent, il élargit la surface d’attaque.

Exfiltration des remplacements de texte du clavier
Les raccourcis clavier sont enregistrés dans defaults, qui correspond à un fichier .plist adossé au système de fichiers, quelque part dans votre dossier local. L’exécution de la commande suivante renvoie les remplacements de texte configurés, également accessibles depuis l’application Préférences Système.
Notez que le code suivant ne nécessite pas d’accès sudo et peut être exécuté par n’importe quel processus sur votre ordinateur.
La même commande peut être exécutée avec execSync dans Node.js, puis analysée sans difficulté via l’opération de cycle de vie postinstall prise en charge par le gestionnaire de paquets npm.
Voici un exemple de script Node.js que des acteurs malveillants peuvent utiliser pour accéder aux remplacements de texte de macOS et exfiltrer des données sensibles :
Pour que le code ci-dessus s’exécute lors de l’installation du paquet, nous allons modifier le fichier manifeste du paquet, package.json, comme suit :
Distribuée via npm et téléchargée par un développeur, cette bibliothèque exécutera directement notre script personnalisé pour récupérer et traiter les remplacements du clavier. Si vous n’y prenez pas garde, il est facile de ne pas voir la ligne contenant > node ./retrieve.js.
Protection
En tant que développeur, que pouvez-vous faire pour limiter les risques de sécurité liés aux paquets npm malveillants et les risques généraux d’exécution de commandes arbitraires par des paquets de votre arbre de dépendances ?
Ignorer les scripts lors de l’installation de paquets npm
Vous pouvez vous protéger contre les paquets qui utilisent des scripts postinstall. npm propose l’option de configuration --ignore-scripts lors de l’installation de paquets.
Utiliser des paramètres par défaut sûrs pour npm
Le gestionnaire de paquets npm dispose également d’un fichier de configuration appelé .npmrc. Vous pouvez modifier les préférences par défaut à l’aide de l’interface en ligne de commande npm afin de garantir des paramètres sécurisés :
Stockage sécurisé
Surtout, ne stockez jamais d’informations sensibles en texte brut. Si d’autres exigences vous obligent à les stocker ainsi, veillez à toujours protéger l’accès à la ressource par une authentification multifacteur.
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.
