Une faille de sécurité critique~? baptisée "BatBadBut"~? a été découverte dans la bibliothèque standard Rust
Mais elle affecte également Erlang, Go, Haskell, Java, Node.js, PHP, Python et Ruby
Le 2024-04-11 16:42:19, par Anthony, Chroniqueur Actualités
Une faille de sécurité critique, baptisée "BatBadBut", a été découverte entre autres dans la bibliothèque standard Rust, affectant toutes les versions antérieures à 1.77.2 sous Windows. La vulnérabilité, identifiée comme CVE-2024-24576, a un score CVSS de 10.0 et permet à un attaquant d'exécuter des commandes shell arbitraires en contournant le mécanisme d'échappement lors de l'invocation de fichiers batch avec l'API Command.
La vulnérabilité "BatBadBut" a été découverte par le chercheur en sécurité RyotaK et divulguée de manière responsable à l'équipe de sécurité de Rust, qui a donc expliqué comment l'équipe Rust a géré l'alerte, et patché la faille, ce qui n'est pas encore le cas sur tous les autres langages affectés.
Selon le billet de blog de RyotaK, le problème provient des règles complexes d'analyse de cmd.exe, l'invite de commande de Windows, qui est implicitement lancée lors de l'exécution de fichiers batch. La bibliothèque standard Rust ne parvient pas à échapper correctement les arguments de commande pour cmd.exe, ce qui permet l'injection potentielle de commandes.
Alors que les API Command::arg et Command::args de Rust garantissent que les arguments seront transmis tels quels au processus créé et ne seront pas évalués par un shell, la mise en œuvre sous Windows est plus complexe.
L'API Windows ne fournit qu'une seule chaîne de caractères contenant tous les arguments, laissant au processus créé la responsabilité de les diviser. La plupart des programmes utilisent la chaîne d'exécution standard argv en C, ce qui permet d'obtenir un comportement cohérent en matière de division des arguments. Cependant, cmd.exe possède sa propre logique de découpage des arguments, qui nécessite un échappement personnalisé par la bibliothèque standard Rust.
"Pour éviter l'exécution inattendue de fichiers batch, vous devriez envisager de déplacer les fichiers batch dans un répertoire qui n'est pas inclus dans la variable d'environnement PATH.", a noté RyotaK dans son billet de blog. "Dans ce cas, les fichiers batch ne seront pas exécutés à moins que le chemin d'accès complet ne soit spécifié, ce qui permet d'éviter l'exécution inattendue de fichiers batch."
L'équipe de sécurité de Rust a reconnu que la logique d'échappement existante dans la bibliothèque standard était insuffisante, ce qui permettait à des arguments malveillants de contourner l'échappement et d'entraîner une exécution arbitraire de l'interpréteur de commandes. La gravité de la vulnérabilité "BatBadBut" est considérée comme critique si des arguments non fiables sont transmis lors de l'invocation de fichiers batch sous Windows.
BatBadBut ne se limite pas à un seul identifiant CVE
Alors que l'attention s'est d'abord portée sur le langage de programmation Rust, il est apparu que la vulnérabilité "BatBadBut" ne se limite pas à un seul identifiant CVE. La vulnérabilité affecte plusieurs langages de programmation et outils, chacun se voyant attribuer un identifiant CVE différent en fonction de la mise en œuvre et de l'impact spécifiques.
Outre CVE-2024-24576, qui concerne la bibliothèque standard Rust, "BatBadBut" englobe également CVE-2024-1874, CVE-2024-22423 (qui affecte yt-dlp avec un score de risque élevé de 8,3) et CVE-2024-3566 (qui affecte Haskell, Node.js, Rust, PHP et yt-dlp). Cela met en évidence la nature étendue de la vulnérabilité et la nécessité pour les développeurs d'évaluer leurs applications et dépendances à travers différents langages de programmation et outils.
Atténuation
Pour remédier à la vulnérabilité "BatBadBut", l'équipe Rust a publié la version 1.77.2, qui inclut un correctif pour le problème. Ce correctif améliore la robustesse du code d'échappement et modifie l'API Command pour qu'elle renvoie une erreur InvalidInput lorsqu'elle ne peut pas échapper un argument en toute sécurité. Cette erreur sera émise lors du lancement du processus.
Pour les développeurs qui implémentent leur propre échappement ou qui ne gèrent que des entrées fiables sous Windows, la méthode CommandExt::raw_arg peut être utilisée pour contourner la logique d'échappement de la bibliothèque standard.
Il est important de noter que la vulnérabilité n'affecte que le code Rust fonctionnant sous Windows qui exécute des fichiers batch avec des arguments non fiables. Les autres plateformes ou utilisations de Windows ne sont pas concernées.
La communauté Rust a exprimé sa gratitude à RyotaK pour avoir divulgué la vulnérabilité de manière responsable, à Simon Sawicki (Grub4K) pour avoir identifié certaines des règles d'échappement adoptées, et aux membres du projet Rust qui ont aidé à développer le correctif, à le réviser et à coordonner le processus de divulgation.
Il est fortement conseillé aux développeurs utilisant Rust sur Windows de mettre à jour vers la version 1.77.2 dès que possible afin de réduire le risque d'attaques potentielles par injection de commandes. Il est essentiel de s'assurer que les entrées non fiables sont correctement validées et assainies avant d'être transmises en tant qu'arguments à des fichiers batch.
État des lieux sur les autres langages de programmation affectés
Sources : Équipe Rust, "BatBadBut: You can't securely execute commands on Windows" (RyotaK, chercheur en sécurité)
Et vous ?
Quelle lecture faites-vous de cette situation ?
Voir aussi :
Comment Rust améliore la sécurité de son écosystème : la Rust Foundation publie un rapport sur ce que leur initiative de sécurité a accompli au cours des six derniers mois de 2023
« Choisir Rust est opter pour une meilleure sécurisation des logiciels qu'avec le C, mais une efficacité énergétique et une performance d'exécution que seul le C offre », d'après l'équipe AWS
La vulnérabilité "BatBadBut" a été découverte par le chercheur en sécurité RyotaK et divulguée de manière responsable à l'équipe de sécurité de Rust, qui a donc expliqué comment l'équipe Rust a géré l'alerte, et patché la faille, ce qui n'est pas encore le cas sur tous les autres langages affectés.
Selon le billet de blog de RyotaK, le problème provient des règles complexes d'analyse de cmd.exe, l'invite de commande de Windows, qui est implicitement lancée lors de l'exécution de fichiers batch. La bibliothèque standard Rust ne parvient pas à échapper correctement les arguments de commande pour cmd.exe, ce qui permet l'injection potentielle de commandes.
Alors que les API Command::arg et Command::args de Rust garantissent que les arguments seront transmis tels quels au processus créé et ne seront pas évalués par un shell, la mise en œuvre sous Windows est plus complexe.
L'API Windows ne fournit qu'une seule chaîne de caractères contenant tous les arguments, laissant au processus créé la responsabilité de les diviser. La plupart des programmes utilisent la chaîne d'exécution standard argv en C, ce qui permet d'obtenir un comportement cohérent en matière de division des arguments. Cependant, cmd.exe possède sa propre logique de découpage des arguments, qui nécessite un échappement personnalisé par la bibliothèque standard Rust.
"Pour éviter l'exécution inattendue de fichiers batch, vous devriez envisager de déplacer les fichiers batch dans un répertoire qui n'est pas inclus dans la variable d'environnement PATH.", a noté RyotaK dans son billet de blog. "Dans ce cas, les fichiers batch ne seront pas exécutés à moins que le chemin d'accès complet ne soit spécifié, ce qui permet d'éviter l'exécution inattendue de fichiers batch."
L'équipe de sécurité de Rust a reconnu que la logique d'échappement existante dans la bibliothèque standard était insuffisante, ce qui permettait à des arguments malveillants de contourner l'échappement et d'entraîner une exécution arbitraire de l'interpréteur de commandes. La gravité de la vulnérabilité "BatBadBut" est considérée comme critique si des arguments non fiables sont transmis lors de l'invocation de fichiers batch sous Windows.
BatBadBut ne se limite pas à un seul identifiant CVE
Alors que l'attention s'est d'abord portée sur le langage de programmation Rust, il est apparu que la vulnérabilité "BatBadBut" ne se limite pas à un seul identifiant CVE. La vulnérabilité affecte plusieurs langages de programmation et outils, chacun se voyant attribuer un identifiant CVE différent en fonction de la mise en œuvre et de l'impact spécifiques.
Outre CVE-2024-24576, qui concerne la bibliothèque standard Rust, "BatBadBut" englobe également CVE-2024-1874, CVE-2024-22423 (qui affecte yt-dlp avec un score de risque élevé de 8,3) et CVE-2024-3566 (qui affecte Haskell, Node.js, Rust, PHP et yt-dlp). Cela met en évidence la nature étendue de la vulnérabilité et la nécessité pour les développeurs d'évaluer leurs applications et dépendances à travers différents langages de programmation et outils.
Atténuation
Pour remédier à la vulnérabilité "BatBadBut", l'équipe Rust a publié la version 1.77.2, qui inclut un correctif pour le problème. Ce correctif améliore la robustesse du code d'échappement et modifie l'API Command pour qu'elle renvoie une erreur InvalidInput lorsqu'elle ne peut pas échapper un argument en toute sécurité. Cette erreur sera émise lors du lancement du processus.
Pour les développeurs qui implémentent leur propre échappement ou qui ne gèrent que des entrées fiables sous Windows, la méthode CommandExt::raw_arg peut être utilisée pour contourner la logique d'échappement de la bibliothèque standard.
Il est important de noter que la vulnérabilité n'affecte que le code Rust fonctionnant sous Windows qui exécute des fichiers batch avec des arguments non fiables. Les autres plateformes ou utilisations de Windows ne sont pas concernées.
La communauté Rust a exprimé sa gratitude à RyotaK pour avoir divulgué la vulnérabilité de manière responsable, à Simon Sawicki (Grub4K) pour avoir identifié certaines des règles d'échappement adoptées, et aux membres du projet Rust qui ont aidé à développer le correctif, à le réviser et à coordonner le processus de divulgation.
Il est fortement conseillé aux développeurs utilisant Rust sur Windows de mettre à jour vers la version 1.77.2 dès que possible afin de réduire le risque d'attaques potentielles par injection de commandes. Il est essentiel de s'assurer que les entrées non fiables sont correctement validées et assainies avant d'être transmises en tant qu'arguments à des fichiers batch.
État des lieux sur les autres langages de programmation affectés
Sources : Équipe Rust, "BatBadBut: You can't securely execute commands on Windows" (RyotaK, chercheur en sécurité)
Et vous ?
Voir aussi :
-
FagusMembre expertEn fait c'est plus un défaut de conception dans cmd.exe qui oblige les langages à contourner le défaut de manière alambiquée.
Envoyé par RyotaK le 12/04/2024 à 16:01 -
UtherExpert éminent séniorEn effet, ou pour être plus précis, le défaut vient de la fonction CreateProcess de l'API de Windows qui fait insidieusement appel à cmd.exe quand le fichier exécuté est un fichier de commande (de type bat ou cmd). Cela à pour conséquence que les arguments ne sont plus traités comme tels, mais comme une ligne d'un fichier batch à exécuter.
Le principal problème vient du fait que ce comportement est mal documenté par Microsoft. La documentation MSDN actuelle n'indique pas du tout le comportement spécifique dans le cas des fichiers de commande. Au contraire elle indique que pour exécuter un fichier de commande, il faut invoquer cmd.exe manuellement.le 13/04/2024 à 6:39 -
UtherExpert éminent séniorC'est assez ironique d'avouer ne pas très bien comprendre le problème dont on parle, et en même temps de conclure que le problème vient des développeurs qui ne comprennent pas bien l’outil qu'ils utilisent.
Plus sérieusement, bien sur que les développeurs se doivent de maitriser les API qu'ils utilisent. Mais pour cela, encore faudrait-il qu'il puissent se renseigner sur leur comportement. Le fait que la fonction CreateProcess de l'API Win32 fasse appel à cmd.exe et surtout que les paramètres sont interprétés comme une ligne de commande, n'est pas documenté officielement.
Difficile de reprocher aux développeur de ne pas connaitre un comportement non documenté.
Microsoft peut difficilement corriger ça sans risquer de casser la compatibilité.
Mais à défaut de corriger la fonction CreateProcess, ils devraient au moins correctement la documenter pour indiquer qu'elle fait appel à cmd.exe pour les fichiers de commande et que ça implique des règles d’échappement différentes et bien plus complexes.le 18/04/2024 à 8:39 -
UtherExpert éminent séniorLe problème c'est justement que ça ne concerne pas que les fichiers externes. Si tu fais appel à un fichier de commande, même interne, avec des paramètres variables, tu peux tout à fait être concerné.le 15/04/2024 à 7:43
-
chrtopheResponsable SystèmesJe vais prendre une métaphore. Tu te ballades dans la foret (dans ce cas, on pourrait dire la jungle), tu as faim, et tu vois un champignon. Tu n'as pas avec toi le "petit manuel des champignons dangereux" (et que même si tu l'as, tu ne trouve rien sur ce champignon), que fais-tu ? Perso, je ne mange pas le champignon... Remplace foret par développement, champignon par API, et le manuel par la documentation
Je n'avais pas compris le prob au départ, car pour moi je ne m'attendais pas à ce que createprocess appelle cmd (après je suis pas développeur), donc si je devais développer un programme appelant createprocess pourquoi je devrais formater les arguments comme si je passais par cmd ? Et après on va dire que c'est mon code qui est pas bon, alors que comme il n'est pas précisé dans la doc que je dois échapper les arguments comme si j'appelais cmd, je ne l'ai pas fait.le 18/04/2024 à 18:07 -
chrtopheResponsable SystèmesQue je sois développeur ou non, j'ai accès à la même documentation technique. Le prob. n'est pas là.
Pour reprendre tes exemples :
Un garagiste tout compétent qu'il soit ne pourra pas correctement réparer ta voiture si il n'a pas accès à une documentation technique fiable, sauf si il a lui-même fabriqué le moteur.
Un médecin te prescris un médicament qui a pignon sur rue. Plusieurs années plus tard, on découvre que ce médicament provoque de graves problèmes, le médecin est responsable ?
Un développeur utilise un OS incluant des fonctions, si celle-ci ne sont pas correctement documentées, ou ne réagit pas comme documenté, on ne peut pas incriminer le développeur en question.le 18/04/2024 à 20:55 -
UtherExpert éminent séniorLe cas du logiciel embarqué critique est particulier : on se limite à des OS assez simples avec une API minimale, voire pas d'OS du tout. On a forcément plus de contrôle des détails. Et encore, si tu te retrouves à travailler avec des OS comme VxWorks, ou similaire, je serais surpris que tu analyses systématiquement son comportement dans absolument tous les cas possibles pour t'assurer que la doc est correcte et exhaustive.
Pour le sujet en question, à savoir l'API Win32, c'est hors sujet. Si tu fais de l'embarqué en Rust, tu vas travailler en mode "no_std", où tu n’auras pas non plus de problème avec l'API Win32, vu que la bibliothèque standard est amputée de ses dépendances à l'OS.
Auditer la fiabilité de l'OS ne rentre pas dans le domaine de compétence d'un langage de programmation. Les dev de la bibliothèque standard de Rust ont utilisé l'API standard de Microsoft qu'ils n'avaient aucune raison particulière d'imaginer problématique, comme beaucoup d'autres l'ont fait depuis bien plus longtemps qu'eux sans que personne n'ait vu le problème.
Rust a beau prendre la sécurité au sérieux, ça reste un langage de programmation, il ne prétend pas être un outil magique qui résoudra tous les problèmes de sécurité possible à tous les niveaux.
Tous les gens qui font appels à des fichiers de commande avec des paramètres manipulables par un tiers sont touchés par ce problème sous Windows, que le langage soit directement impliqué ou non :
Les langages qui ont eu des bulletins d’alertes sont ceux qui avaient mis en place une abstraction autour de CreateProcess censé fournir un échappement sécurisé des paramètres. Cet échappement ne fonctionnait pas dans le cas particulier des scripts de commande, ce qu'ils ont du corriger ou documenter.
Pour les langages qui n'ont pas eu de CVE, comme le C et le C++, ça n'est pas parce qu'ils ont anticipé quoi que ce soit, mais au contraire parce qu'ils ne font rien et laissent l'utilisateur appeler CreateProcess directement, ou quasi directement, sans fournir la moindre garantie. Il n'y a en effet rien à corriger au niveau du langage vu que c'est l'utilisateur qui doit faire l'échappement lui même. Cependant, comme le problème n’était pas vraiment connu, pas officiellement documenté, et pas facile à résoudre correctement, il est à peu près certain que aucun des utilisateurs actuels de CreateProcess, dans les cas qui posaient problème en Rust, ne l'utilise de manière sécurisée. Et vu que rien n'a changé pour les langages qui n'encapsulent pas les appel a CreateProcess, il est probable que la situation dure pour leurs utilisateurs, là où Rust protège maintenant contre ce type de problèmes.
J'ai juste pris ça comme exemple de comportement inattendu d'une API (peut importe qu'il soit malicieux ou non), difficile à anticiper, et qui ne constitue qu'un cas parmi une infinité de possibilité. On ne peut pas attendre de l'utilisateur d'une l'API, quelque soit sont niveau de technique, qu'il anticipe tous les cas non documentés possibles, c'est infini. S'il ne peut pas faire confiance au comportement décrit dans la documentation, la seule solution serait d'auditer le code, mais ça n'est clairement pas le boulot du créateur d'un langage, ce n'est même pas possible officiellement dans le cas de l'API Win32.
Justement, alors que le problème existe depuis possiblement 30 ans, il a été découvert en premier sur du Rust, où il a rapidement été rendu inexploitable depuis sa bibliothèque standard. D'un autre coté, Java a décidé de ne rien faire et Microsoft n'a, semble-il à l'heure actuelle, même pas mis à jour sa documentation officielle.
On voit quand même une sacré différence dans la gestion des risques. Pour rappel, Rust n'a jamais prétendu empêcher 100% des failles de sécurité, mais clairement, il prend le problème au sérieux.
CreateProcess est il me semble une fonction historique de l'API Win32, je ne sais pas exactement si elle est présente depuis le tout début de l'API et si elle a toujours permis d’exécuter les fichiers de commande, mais si c'est le cas, ce qui ne me parais pas impossible, ça remonterait au milieu des années 90.le 19/04/2024 à 23:14 -
chrtopheResponsable SystèmesAppeler un fichier externe avec cmd est une mauvaise idée.le 15/04/2024 à 6:45
-
chrtopheResponsable SystèmesJ’avais compris que c'était lié à cmd.exe, Donc utilisé pour appeler une commande externe au logiciel.
Pas clair pour moi.le 15/04/2024 à 21:15 -
UtherExpert éminent sénior
Envoyé par OuftiBoy
Supposons qu'un développeur utilise la fonction système de copie de fichiers dans son application et que l'on découvre plus tard que cette fonction modifie certains types de fichiers images à la volée pour ajouter un watermark invisible sans le préciser. Est-ce qu'on devrait rendre le développeur responsable du fait que son application leake des informations, parce qu'il aurait du l'anticiper en vérifiant le comportement de la fonction pour tous les types de fichiers possibles ?
Et des exemple du genre, on peut en imaginer des dizaines sur quasiment toutes les fonctions possibles d'une API. Si on doit anticiper tous les cas imaginables de mauvais fonctionnement, on ne peut plus rien utiliser.le 19/04/2024 à 8:55