Attaques typosquatting : attention aux packages et aux dépendances
Sommaire
I. Présentation
Dans cet article, nous allons nous intéresser aux attaques par typosquatting visant les packages et dépendances logicielles. Le terme typosquatting décrit d'ordinaire les attaques se fondant principalement sur les fautes de frappe et d'orthographe commises par l'internaute au moment de saisir une adresse web dans un navigateur. Nous avions introduit ce type d'attaque dans notre article Protéger son domaine contre le Phishing : techniques basées sur l’OSINT. Nous allons voir dans cet article que ce type d'attaque ne se retreint plus aux noms de domaine et se propage sur d'autres types d'éléments.
II. Package typosquatting : qu'est ce que c'est ?
En effet depuis quelques années, plusieurs cas de typosquatting visant les packages et bibliothèques de programmation sont apparues. Ces attaques visent à exploiter les erreurs de saisies humaines lors d'installation de packages ou dépendances.
Il est arrivé à tout informaticien, développeur ou administrateur système d'avoir à installer une dépendance nécessaire à l'exécution d'un script ou d'une solution logicielle plus complexe, par exemple :
# Python pip install requests # Node.js npm install express
Parfois, des fichiers de dépendances sont proposés et permettent rapidement d'installer un ensemble de packages en une commande, par exemple en python :
# Python pip install -r requirements.txt
Il est cependant assez rare que l'on regarde de près ce qui est installé lors de l'installation d'une solution, même parfois venant d'un simple dépôt Github. Également, des erreurs peuvent être faites par les développeurs dans leur script d'installation ou documentation. Ils deviennent alors vulnérables au typosquatting. Prenons un exemple concret. Je souhaite installer sur mon poste un bout de code présent sur un dépôt Github, un simple wrapper nommé "MaMeteo" utilisant l'API d'un site web permettant de récupérer la météo. Il se base donc sur le package Python requests permettant de faire des requêtes web aisément. Le développeur propose un fichier requirements.txt pour faciliter l'installation des dépendances :
root@debian:/tmp# cat requirements.txt equest urllib root@debian:/tmp# pip install -r requirements.txt ERROR: Could not find a version that satisfies the requirement equest ERROR: No matching distribution found for equest
Dans ce cas précis, le package n'est pas trouvé auprès du dépôt de référence, le développeur à donc certainement fait une erreur de saisie lors de la création du fichier requirements.txt. En tant qu'attaquant, il s'agit d'une opportunité de typosquatting, il devient possible de créer un package nommé equest sur le dépôt officiel requêté (par défaut : Pypi.org), tous les utilisateurs installant le projet "MaMeteo" et souhaitant installer le package equest téléchargeront mon package d'attaquant, contenant du code malveillant. Pour encore plus de discrétion, l'attaquant peut cloner le package request pour en faire son package equest, et ajouter à un endroit précis son code malveillant, ce qui ne perturbera pas l'exécution du projet "MaMeteo".
L'attaque peut être résumée par le schéma suivant :
À titre d'exemple, voici le code contenu dans le package malveillant ascsii2text, mis en ligne sur la plateforme Pypi.org pendant quelques jours et copie conforme du package populaire art :
On peut voir que le package télécharge puis exécute une DLL malveillante. Après quelques recherches, il est aisé de trouver des repositories Python utilisant ce package malveillant (qui a été supprimé du dépôt Pypi depuis) :
Le typosquatting entre dans le champ des Supply chain attacks ou attaques sur la chaîne d'approvisionnement. Selon le framework MITRE ATT&CK qui référence les tactiques, techniques et procédures (TTP) des attaquants, ces attaques sont référencées par la technique T1195 Supply Chain Compromise. Dans l'idée, il s'agit aussi d'une forme de phishing qui vise à tromper l'utilisateur et exploite une faiblesse ou un comportement humain.
Les vecteurs d'infection
Ce type d'attaque vise donc notamment les développeurs qui peuvent réaliser des erreurs dans leur programme et ainsi proposer à leur utilisateur des instructions ou scripts d'installation qui installent des dépendances malveillantes. Également, les administrateurs système déployant des solutions contenant ce genre d'erreur ou qui réalisent des installations manuelles de dépendances peuvent également être ciblés. Dans la plupart des cas, les noms des packages populaires de chaque langage son visés.
Au-delà d'une erreur pouvant apparaître lors de la création d'un script ou d'un programme, une erreur peut être injectée à chaque modification ou mise à jour du code. En effet, la modification du fonctionnement d'un programme dans le cadre de l'ajout d'une nouvelle fonctionnalité peut entraîner l'ajout d'un nouvel import de package. Le fait de considérer un outil comme sûr à la première installation n'est donc pas suffisant.
Dans l'absolu, ces attaques peuvent également porter sur les packages non maintenus qui finissent par être supprimés sur les dépôts, mais qui continuent à être importés en tant que dépendance par les scripts et programmes.
Dans cet article, j'ai pris différents exemples de commande utilisant Python, qui est celui que je maîtrise le mieux. Il ne faut pas oublier que ces attaques peuvent apparaître sur tout type de langage utilisant des dépendances externes installables en quelques commandes (Python, Node.js, Go, fork Github, pourquoi pas Docker ?).
En outre, il faut savoir que les dépôts officiels ne sont pas des sources sûres à 100%. Il est facile pour quiconque de créer un dépôt, par exemple nommé equest ou rrequests ou requestss sur Pypi.org pour y positionner du code malveillant. La création d'un package sur Pypi est aussi simple que la création d'un repository Github et ne subit aucun contrôle ou revue (Voir cet article).
III. Quelques exemples concrets
Comme nous l'avons vu précédemment, il est aisé de trouver sur Github des projets avec des importations de packages contenant des erreurs typographiques. Exemple d'erreur d'import sur la bibliothèque python requests :
Inversement, les cas d'attaque par création de packages exploitant le typosquatting se font de plus en plus nombreux :
- (08/2022) Typosquatting Campaign Targeting Python’s Top Packages, Dropping GitHub Hosted Malware with DGA Capabilities : package Python utilisant le typosquatting sur des packages populaires, télécharge et exécute un exécutable malveillant
- (07/2022) Supply chain attacks using malicious NPM Packages compromised the details of thousands of web users : package npm utilisant le typosquatting sur des packages populaires (exemple icon-package au lieu de ionicons), collecte les données utilisateurs (17 000 téléchargements/infections).
- (08/2022) CloudGuard Spectral detects several malicious packages on PyPI – the official software repository for Python developers : Différents exemples de code malveillant implémentés dans des packages Python utilisant le typosquatting sur des packages populaires.
IV. Comment se protéger du typosquatting visant les packages ?
Plusieurs mécanismes et outils peuvent être utilisés pour se protéger de ce type d'attaque, mais aucune solution miracle n'existe.
La première ligne de défense est bien sûr les développeurs eux-mêmes, qui doivent vérifier à deux fois les packages importés. Également, les utilisateurs finaux utilisant des projets open-source doivent être vigilants et regarder attentivement les projets et logiciels qu'ils utilisent. Avoir le réflexe de regarder les imports réalisés et la fiabilité des packages téléchargés avant installation peut par exemple aider à prévenir de potentiellement infections.
À ce titre, il existe des outils pour aider les développeurs et utilisateurs finaux dans cette tâche. Le site web snyk.io met à disposition plusieurs outils permettant de vérifier la fiabilité de package Go, Node.js ou Python :
Plusieurs éléments semblent être utilisés comme la date de création et de mise à jour du projet, le nombre de téléchargement, de vulnérabilités connues, de commit, etc.
Le projet open-source npq semble également suivre ce même principe, il permet de réaliser un audit rapide d'un package npm afin de déterminer sa maturité, son auteur, sa popularité, etc. :
Je ne suis pas parvenu à trouver d'outils similaires (type script à exécuter en local) pour Python/Pypi.
Du côté des administrateurs systèmes ou utilisateurs finaux (qui peuvent aussi être d'autres développeurs), différents processus organisationnels peuvent être mis en place lors du développement ou de la mise à jour d'une application sur un système.
Le premier est le patch management, qui consiste à étudier en détail ce que les mises à jour apportent ou retirent sur un logiciel et de valider le comportement après mise à jour dans un environnement de test avant le déploiement en production. Côté développeur, ce patch management peut passer par une revue des dépendances incluses dans le projet, mais qui ne sont plus utilisés ou plus maintenues, une suppression des fonctions, fichiers et codes non nécessaires, etc. Également, un scan de vulnérabilité automatisé peut permettre d'analyser, ou au moins lister, les dépendances utilisées par un projet.
Enfin, il peut dans certains cas être envisagé d'installer et d'utiliser un serveur local ou intermédiaire de package. Les utilisateurs d'une entreprise n'utiliseront alors que ces serveurs locaux et maîtrisés pour mettre à jour ou télécharger des packages. Ces derniers ne seront installés sur le serveur intermédiaire qu'après une revue et un contrôle de leur mainteneur. Il est par exemple possible d'installer son propre pypiserver. Ce cas de figure n'est bien sur utile que dans des cas biens particuliers.
Pour aller plus loin
Pour aller plus loin dans le domaine des supply chain attacks sur les packages, sachez que les attaquants peuvent également cibler les identifiants/comptes des développeurs de package populaires afin d'y injecter du code malveillant dans le cadre d'une montée de version. Ces cas de figure sont encore plus dangereux, car il s'agit de packages légitimes, déjà très largement utilisés et importés, exemple : Hacker Infects Node.js Package to Steal from Bitcoin Wallets.