Les attaquants qui ciblent les dépôts de paquets open source tels que PyPI (Python Package Index) ont mis au point une technique pour dissimuler leur code malveillant aux scanners de sécurité, aux examens manuels et à d'autres formes d'analyse de sécurité. Dans un cas, les chercheurs ont trouvé un code malveillant caché dans un fichier PYC (Python bytecode) qui peut être exécuté directement, contrairement aux fichiers de code source qui sont interprétés par le moteur d'exécution Python. « Il pourrait s'agir de la première attaque de la chaîne d'approvisionnement à tirer parti du fait que les fichiers bytecode Python peuvent être directement exécutés, et elle survient au milieu d'un pic de soumissions malveillantes à l'index des paquets Python », ont déclaré les chercheurs de la société de sécurité ReversingLabs dans un rapport. « Si c'est le cas, cela pose un nouveau risque pour la chaîne d'approvisionnement, car ce type d'attaque risque de ne pas être détecté par la plupart des outils de sécurité, qui n'analysent que les fichiers de code source Python ».
La grande majorité des paquets trouvés sur des dépôts publics tels que npm pour JavaScript, PyPI pour Python et RubyGems pour Ruby consistent en des fichiers de code open source qui sont empaquetés dans des archives. Ils sont faciles à décompresser et à lire, et c'est pourquoi les scanners de sécurité de ces dépôts ont été conçus pour gérer ce type de paquet. Les attaquants livrent une bataille constante avec les sociétés de sécurité pour échapper à la détection, et la technique d'évasion la plus courante lorsqu'il s'agit de code en clair est l'obscurcissement. Cette technique consiste à utiliser les caractéristiques du langage de programmation lui-même, telles que le codage, le décodage ou l'évaluation, pour rendre le code illisible mais fonctionnel. Par exemple, l'encodage d'un code malveillant en base64 est une technique couramment utilisée, mais les outils de sécurité peuvent traiter ce type d'encodage.
Des charges utiles difficiles à détecter...
Dans l'écosystème PyPI, les cybercriminels à l'origine du logiciel malveillant W4SP Stealer sont connus pour utiliser des techniques telles que l'encodage base64, la compression LZMA et la minification (suppression des espaces et des commentaires dans le code pour le rendre plus compact, mais aussi plus difficile à lire). Pour ce faire, le groupe utilise des outils open source tiers tels que Pyminifier, Kramer ou Hyperion. Dans une variante des attaques W4SP, le code malveillant obscurci dans les fichiers était déplacé au-delà des bords de l'écran par défaut, de sorte qu'une personne examinant manuellement le fichier de code source ne le verrait pas. Cependant, les fichiers PYC sont différents car ils ne sont pas lisibles par l'homme comme les scripts PY en texte clair. Les fichiers PYC sont générés lorsque l'interpréteur Python importe ou exécute un script de ce type. Comme il s'agit d'un code déjà interprété (compilé), il peut être exécuté directement par l'interpréteur Python sans réinterpréter le script d'origine. Cela améliore les performances car les temps d'exécution sont plus rapides. L'utilisation la plus courante de ces fichiers est la distribution de modules Python.
Dans la plupart des cas de logiciels malveillants PyPI, le code obfusqué malveillant est destiné à atteindre une URL externe et à télécharger le logiciel malveillant - généralement un stealer - ce qui constitue une autre occasion pour les outils de sécurité de détecter un comportement suspect. Dans le dernier incident en date, un paquet appelé fshec2 contenant un fichier PYC malveillant, sa charge utile complète peut être cachée dans le fichier et il est beaucoup plus difficile de la détecter si l'outil de sécurité n'est pas conçu pour la décompiler. « Les scripts de chargement tels que ceux découverts dans le paquet fshec2 contiennent une quantité minimale de code Python et exécutent une action simple : le chargement d'un module Python compilé », expliquent les chercheurs de ReversingLabs. « Il se trouve qu'il s'agit d'un module malveillant.
Inspector, l'outil par défaut fourni par l'équipe de sécurité de PyPI pour analyser les paquets PyPI, ne permet pas, pour l'instant, d'analyser les fichiers binaires pour repérer les comportements malveillants. Le code compilé du fichier .PYC a dû être décompilé afin d'analyser son contenu ». Le paquet fshec2 trouvé par ReversingLabs présentait un comportement supplémentaire qui visait probablement à échapper à la détection. Normalement, un module est importé d'un script Python à l'aide de la directive import. Cependant, dans ce cas, le module PYC malveillant a été chargé à l'aide d'importlib, un package qui met en œuvre la fonctionnalité d'importation et qui n'est utilisé que dans des cas particuliers, par exemple lorsqu'une bibliothèque importée est modifiée dynamiquement lors de l'importation. Dans ce cas, le PYC malveillant n'a pas été modifié, il n'y a donc aucune raison technique d'utiliser importlib, si ce n'est pour éviter d'utiliser la directive d'importation normale, probablement pour échapper à la détection.
...Et poussées en tant que script Python
Une fois exécutée sur une machine, la charge utile malveillante fshec2 recueille des informations sur le système, telles que les noms d'utilisateur, les listes de répertoires et les noms d'hôte, puis met en place une tâche CRON sous Linux ou une planifiée sous Windows pour exécuter des commandes récupérées sur un serveur distant. Ces dernières donnent la possibilité au malware de se mettre à jour automatiquement, les attaquants étant en mesure de fournir une nouvelle version, ainsi que des charges utiles supplémentaires sous la forme de scripts Python.
Les chercheurs de ReversingLabs ont analysé le serveur de commande et de contrôle et ont trouvé des configurations erronées qui leur ont permis de jeter un coup d'œil sur certaines informations. Par exemple, ils ont constaté que les machines victimes recevaient un ID incrémentiel et ont pu confirmer que le logiciel malveillant avait bien été exécuté par plusieurs victimes. « Le nombre de ces erreurs pourrait nous amener à conclure que cette attaque n'est pas le fait d'un acteur bénéficiant d'un soutien étatique ni d'une menace persistante avancée (APT) », ont déclaré les chercheurs. « Bien que mon équipe n'ait pas recueilli suffisamment d'éléments pour prouver cette hypothèse d'une manière ou d'une autre, le fait de récolter les noms de fichiers en incrémentant l'ID du fichier nous a permis de déterminer que l'attaque avait réussi dans certains cas. Nos chercheurs ne sont toujours pas en mesure de dire qui étaient les cibles ou ce qu'elles étaient. Cependant, nous pouvons confirmer que des développeurs ont installé le paquet PyPI malveillant et que leurs noms de machine, noms d'utilisateur et listes de répertoires ont été récoltés en conséquence ». Certains des noms de fichiers trouvés sur le serveur suggèrent que les attaquants ont déployé une fonctionnalité de keylogging sur certaines des machines. « Historiquement, npm a été le leader malheureux et PyPI a également fait la course pour voir quelle plateforme open source attire le plus d'attention de la part des auteurs de logiciels malveillants », ont déclaré les chercheurs. « Toutefois, au cours des six derniers mois, ReversingLabs et d'autres ont observé une nette augmentation du volume de logiciels malveillants publiés sur PyPI. En fait, en mai, la création de nouveaux comptes d'utilisateurs et de projets sur PyPI a été temporairement suspendue pendant quelques heures en raison d'un volume élevé d'activités malveillantes ».
Aller au-delà de l'analyse statique du code
ReversingLabs a signalé ce dernier vecteur d'attaque à l'équipe de sécurité de PyPI, qui a supprimé le paquet et déclaré n'avoir jamais vu cette technique d'attaque auparavant. Cela n'exclut pas la possibilité que d'autres paquets similaires fassent leur apparition dans le dépôt. Pour faire face à ces menaces modernes qui pèsent sur la chaîne d'approvisionnement logicielle, les entreprises ont besoin d'aller au-delà des solutions d'analyse statique du code. Elles doivent recourir à des outils capables de surveiller les systèmes de développement sensibles pour détecter la création de processus suspects, l'exécution de fichiers, l'accès non autorisé à des URL, les commandes de collecte d'informations et l'utilisation de fonctions faciles à abuser telles que get_path ou importlib.