Il existe apparemment une vulnérabilité (CVE-2014-6271) dans bash: l' attaque par injection de code des variables d'environnement spécialement conçues de Bash
J'essaie de comprendre ce qui se passe, mais je ne suis pas tout à fait sûr de comprendre. Comment peut- echo
on l'exécuter tel quel entre guillemets simples?
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
EDIT 1 : Un système patché ressemble à ceci:
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test
EDIT 2 : Il existe une vulnérabilité / correctif associé: CVE-2014-7169 qui utilise un test légèrement différent:
$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
sortie non corrigée :
vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test
version partiellement corrigée (ancienne version) :
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
Sortie corrigée jusqu'à CVE-2014-7169 inclus:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
EDIT 3 : l'histoire continue avec:
bash
shellshock
vulnerability
jippie
la source
la source
vulnerable
apparaît dans la sortie. Le problème principal est que bash analyse et exécute également le code après la définition de la fonction. Voir la/bin/id
partie de seclists.org/oss-sec/2014/q3/650 pour un autre exemple.Réponses:
bash stocke les définitions de fonctions exportées sous forme de variables d'environnement. Les fonctions exportées ressemblent à ceci:
C'est-à-dire que la variable d'environnement
foo
a le contenu littéral:Lorsqu'une nouvelle instance de bash est lancée, elle recherche ces variables d'environnement spécialement conçues et les interprète comme des définitions de fonctions. Vous pouvez même en écrire un vous-même et constater que cela fonctionne toujours:
Malheureusement, l'analyse des définitions de fonction à partir de chaînes (les variables d'environnement) peut avoir des effets plus larges que prévu. Dans les versions non corrigées, il interprète également les commandes arbitraires qui surviennent après la fin de la définition de la fonction. Ceci est dû à des contraintes insuffisantes dans la détermination de chaînes de type fonction acceptables dans l'environnement. Par exemple:
Notez que l'écho en dehors de la définition de la fonction a été exécuté de manière inattendue lors du démarrage de bash. La définition de la fonction est juste une étape pour obtenir l'évaluation et l'exploitation, la définition de la fonction elle-même et la variable d'environnement utilisée sont arbitraires. Le shell examine les variables d'environnement, voit
foo
, qui semble répondre aux contraintes connues sur la définition d'une fonction, et évalue la ligne en exécutant involontairement aussi l'écho (qui peut être n'importe quelle commande, malveillante ou non).Cela est considéré comme non sécurisé car les variables ne sont généralement pas autorisées ni attendues, à elles seules, à provoquer directement l’invocation du code arbitraire qu’elles contiennent. Peut-être que votre programme définit des variables d'environnement à partir d'une entrée utilisateur non fiable. Il serait hautement inattendu que ces variables d'environnement puissent être manipulées de manière à ce que l'utilisateur puisse exécuter des commandes arbitraires sans votre intention explicite de le faire en utilisant cette variable d'environnement pour une telle raison déclarée dans le code.
Voici un exemple d'attaque viable. Vous exécutez un serveur Web qui exécute un shell vulnérable quelque part au cours de sa vie. Ce serveur Web transmet les variables d'environnement à un script bash. Par exemple, si vous utilisez CGI, les informations relatives à la demande HTTP sont souvent incluses en tant que variables d'environnement provenant du serveur Web. Par exemple,
HTTP_USER_AGENT
peut être défini sur le contenu de votre agent utilisateur. Cela signifie que si vous usurpez votre agent utilisateur pour qu'il ressemble à '() {:; }; echo foo 'echo foo
sera exécuté lors de l'exécution de ce script shell . Encore une fois,echo foo
pourrait être n'importe quoi, malveillant ou non.la source
export bar='() { echo "bar" ; }'; zsh -c bar
et qu'il affichebar
plutôt quezsh:1: command not found: bar
? Êtes-vous sûr de ne pas confondre le shell que vous appelez avec celui que vous utilisez pour configurer le test?Cela peut aider à démontrer davantage ce qui se passe:
Si vous exécutez un shell vulnérable, lorsque vous démarrez un nouveau sous-shell (ici, en utilisant simplement l'instruction bash), vous verrez que le code arbitraire (
echo "pwned"
) est immédiatement exécuté dans le cadre de son lancement. Apparemment, le shell voit que la variable d’environnement (dummy) contient une définition de fonction et évalue la définition afin de définir cette fonction dans son environnement (notez qu’il n’exécute pas la fonction: cela afficherait «hi».)Malheureusement, il ne se contente pas d’évaluer la définition de la fonction, il évalue l’ensemble du texte de la valeur de la variable d’environnement, y compris la ou les déclarations éventuellement malveillantes qui suivent la définition de la fonction. Notez que sans la définition de fonction initiale, la variable d'environnement ne serait pas évaluée, elle serait simplement ajoutée à l'environnement en tant que chaîne de texte. Comme Chris Down l'a souligné, il s'agit d'un mécanisme spécifique pour implémenter l'importation de fonctions de shell exportées.
Nous pouvons voir la fonction qui a été définie dans le nouveau shell (et qu’elle a été marquée comme exportée là-bas), et nous pouvons l’exécuter. De plus, le mannequin n'a pas été importé en tant que variable de texte:
Ni la création de cette fonction, ni rien de ce qu'elle ferait si elle était exécutée, ne fait partie de l'exploit - ce n'est que le véhicule par lequel l'exploit est exécuté. Le fait est que si un attaquant peut fournir du code malveillant, précédé d'une définition de fonction minimale et sans importance, dans une chaîne de texte insérée dans une variable d'environnement exportée, elle sera exécutée au démarrage d'un sous-shell, événement courant. dans de nombreux scripts. De plus, il sera exécuté avec les privilèges du script.
la source
export
commandement alors que les autres en avaientenv
? Je pensaisenv
être utilisé pour définir les variables environnementales qui seraient appelées lors du lancement d'un autre shell bash. alors comment est-ce que cela fonctionneexport
env
etexport
les définitions d'environnement d'exportation afin qu'elles soient disponibles dans un sous-shell. Le problème réside en réalité dans la manière dont ces définitions exportées sont importées dans l'environnement d'un sous-shell, et plus précisément dans le mécanisme d'importation des définitions de fonctions.env
exécute une commande avec quelques options et variables d'environnement définies. Notez que dans les exemples de questions d'origine,env
définitx
une chaîne et appellebash -c
avec une commande à exécuter. Si vous le faitesenv x='foo' vim
, Vim se lancera et vous pourrez y appeler son shell / environnement contenant!echo $x
, et il imprimerafoo
, mais si vous quittez etecho $x
, il ne sera pas défini, car il existait uniquement pendant l'exécution de vim via laenv
commande. Auexport
lieu de cela, la commande définit des valeurs persistantes dans l'environnement actuel de sorte qu'un sous-shell exécuté ultérieurement les utilise.J'ai écrit ceci comme une refonte de l'excellente réponse de Chris Down ci-dessus, dans le style d'un tutoriel.
En bash, vous pouvez avoir des variables shell comme ceci
Par défaut, ces variables ne sont pas héritées par les processus enfants.
Mais si vous les marquez pour exportation, bash définira un indicateur qui signifiera qu’ils iront dans l’environnement des sous-processus (bien que le
envp
paramètre ne soit pas très visible, le programmemain
de votre programme C comporte trois paramètres:main(int argc, char *argv[], char *envp[])
où ce dernier tableau de pointeurs est un tableau des variables de shell avec leurs définitions).Exportons donc
t
comme suit:Considérant que ce qui précède
t
était indéfini dans le sous-shell, il apparaît maintenant après son exportation (utilisez-leexport -n t
si vous souhaitez cesser de l'exporter).Mais les fonctions de bash sont un animal différent. Vous les déclarez comme ceci:
Et maintenant, vous pouvez simplement appeler la fonction en l'appelant comme s'il s'agissait d'une autre commande shell:
Encore une fois, si vous créez un sous-shell, notre fonction n'est pas exportée:
Nous pouvons exporter une fonction avec
export -f
:Voici la partie la plus délicate: une fonction exportée comme
fn
est convertie en une variable d’environnement, tout comme notre exportation de la variable shellt
était ci-dessus. Cela n'arrive pas quandfn
était une variable locale, mais après l'exportation, nous pouvons le voir comme une variable shell. Cependant, vous pouvez également avoir une variable shell régulière (c'est-à-dire non fonction) portant le même nom. bash distingue sur la base du contenu de la variable:Nous pouvons maintenant utiliser
env
pour afficher toutes les variables de shell marquées pour l'exportation, ainsi que la fonction normalefn
et la fonctionfn
:Un sous-shell va ingérer les deux définitions: une en tant que variable normale et l'autre en tant que fonction:
Vous pouvez définir
fn
comme nous l’avons fait ci-dessus, ou directement comme une affectation de variable régulière:Notez que c'est une chose très inhabituelle à faire! Normalement, nous définirions la fonction
fn
comme nous l’avons fait ci-dessus avec lafn() {...}
syntaxe. Mais comme bash l'exporte via l'environnement, nous pouvons «raccourcir» directement vers la définition régulière ci-dessus. Notez que (contrairement à votre intuition, peut-être) cela n'entraîne pas une nouvelle fonctionfn
disponible dans le shell actuel. Mais si vous créez un shell ** sous **, alors ce sera le cas.Annulons l'exportation de la fonction
fn
et laissons la nouvelle régulièrefn
(comme indiqué ci-dessus) intacte.Maintenant, la fonction
fn
n'est plus exportée, mais la variable régulière l'fn
est et contient() { echo "direct" ; }
-la.Maintenant, quand un sous-shell voit une variable régulière qui commence par
()
elle interprète le reste comme une définition de fonction. Mais c'est seulement quand un nouveau shell commence. Comme nous l’avons vu plus haut, le simple fait de définir une variable de shell régulière en commençant par()
ne le fait pas se comporter comme une fonction. Vous devez démarrer un sous-shell.Et maintenant le bug "shellshock":
Comme nous venons de le voir, lorsqu'un nouveau shell ingère la définition d'une variable régulière en commençant par
()
il l'interprète comme une fonction. Cependant, s'il y a plus de données après l'accolade fermante qui définit la fonction, elle exécute aussi ce qui est là.Ce sont les exigences, une fois de plus:
Dans ce cas, un bash vulnérable exécutera les dernières commandes.
Exemple:
La variable exportée régulière a
ex
été transmise au sous-shell, ce qui a été interprété comme une fonction,ex
mais les commandes de fin ont été exécutées (this is bad
) lors de l'apparition du sous-shell.Expliquer le test d'une ligne lisse
Un one-liner populaire pour tester la vulnérabilité de Shellshock est celui cité dans la question de @ jippie:
Voici une ventilation: d'abord, le
:
in bash n'est qu'un raccourci pourtrue
.true
et les:
deux évaluent à (vous l'avez deviné) vrai, en bash:Deuxièmement, la
env
commande (également intégrée à bash) affiche les variables d’environnement (comme nous l’avons vu ci-dessus) mais peut également être utilisée pour exécuter une seule commande avec une variable exportée (ou des variables) affectée à cette commande, etbash -c
exécute une seule commande à partir de sa ligne de commande:Donc, en cousant tout cela ensemble, nous pouvons exécuter bash en tant que commande, lui donner une tâche factice (comme
bash -c echo this is a test
) et exporter une variable qui commence par()
pour que le sous-shell l’interprète comme une fonction. Si shellshock est présent, il exécutera immédiatement toutes les commandes de fin du sous-shell. Comme la fonction que nous passons ne nous concerne pas (mais nous devons analyser!), Nous utilisons la fonction valide la plus courte imaginable:La fonction
f
ici exécute simplement la:
commande, qui renvoie true et quitte. Ajoutez maintenant à cela une commande "diabolique" et exportez une variable normale dans un sous-shell et vous gagnerez. Voici à nouveau le one-liner:Donc,
x
est exporté sous forme de variable régulière avec une simple fonction valide avececho vulnerable
clouée à la fin. Ceci est passé à bash, et bash interprètex
comme une fonction (ce qui nous importe peu) puis exécute peut-être leecho vulnerable
si shellshock est présent.Nous pourrions raccourcir un peu le one-liner en supprimant le
this is a test
message:Cela ne le dérange pas,
this is a test
mais lance à nouveau la:
commande silencieuse . (Si vous quittez le,-c :
vous êtes assis dans le sous-shell et devez quitter manuellement.) La version la plus conviviale serait peut-être celle-ci:la source
{ :;};
qui est dit. Ce serait un bon ajout à votre réponse à mon avis. Peut expliquer comment vous obtenez de votre exemple à la commande d'origine dans la question?Si vous pouvez alimenter un programme en variables d’environnement arbitraires, vous pouvez le faire faire à peu près n'importe quoi en le chargeant des bibliothèques de votre choix. Dans la plupart des cas, ceci n'est pas considéré comme une vulnérabilité dans le programme recevant ces variables d'environnement, mais plutôt dans le mécanisme par lequel un tiers externe pourrait alimenter des variables d'environnement arbitraires.
Cependant, CVE-2014-6271 est différent.
Il n'y a rien de mal à avoir des données non fiables dans une variable d'environnement. Il suffit de s’assurer que les variables d’environnement qui modifient le comportement du programme ne sont pas insérées. Pour résumer un peu, pour une invocation particulière, vous pouvez créer une liste blanche de noms de variables d’environnement, qu’il est permis de spécifier directement par un tiers.
Un exemple qui a été mis en avant dans le contexte de CVE-2014-6271 est constitué par les scripts utilisés pour analyser les fichiers journaux. Ceux-ci peuvent avoir un besoin très légitime de transmettre des données non fiables dans des variables d'environnement. Bien entendu, le nom d'une telle variable d'environnement est choisi de manière à ne pas avoir d'effet négatif.
Mais voici ce qui est mauvais à propos de cette vulnérabilité bash particulière. Il peut être exploité par n'importe quel nom de variable. Si vous créez une variable d'environnement appelée
GET_REQUEST_TO_BE_PROCESSED_BY_MY_SCRIPT
, vous ne vous attendriez pas à ce qu'un programme autre que votre propre script interprète le contenu de cette variable d'environnement. Mais en exploitant ce bogue, chaque variable d’environnement devient un vecteur d’attaque.Notez que cela ne signifie pas que les noms des variables d'environnement doivent être secrets. Connaître les noms des variables d'environnement impliquées ne facilite pas l'attaque.
Si des
program1
appels appellentprogram2
à leur tourprogram3
, ilsprogram1
peuvent alors transmettre des donnéesprogram3
via des variables d’environnement. Chaque programme a une liste spécifique de variables d'environnement qu'il définit et une liste spécifique sur laquelle il agit. Si vous avez choisi un nom non reconnu parprogram2
, vous pouvez transmettre des données deprogram1
àprogram3
sans vous soucier des conséquences négativesprogram2
.Un attaquant connaissant les noms exacts des variables exportées par
program1
et les noms des variables interprétés parprogram2
ne peut pas exploiter cette connaissance afin de modifier le comportement de 'program2` s'il n'y a pas de chevauchement entre l'ensemble des noms.Mais ceci s’est rompu s’il
program2
s’agissait d’unbash
script, car en raison de ce boguebash
, chaque variable d’environnement serait interprétée comme un code.la source
C'est expliqué dans l'article que vous avez lié ...
Ce qui signifie que le bash appelé avec
-c "echo this is a test"
exécute le code entre guillemets simples quand il est appelé .Cela signifie que l'exemple de code que vous avez posté exploite le fait que le bash invoqué n'arrête pas d'évaluer cette chaîne après avoir effectué l'affectation. Une affectation de fonction dans ce cas.
Si j'ai bien compris, l'extrait de code que vous avez posté est en fait spécial: en mettant une définition de fonction avant le code que nous voulons exécuter, certains mécanismes de sécurité peuvent être contournés.
la source