jeudi 5 mai 2016

Fuzzing Vulnserver avec Sulley

Je disais dans un post précédent que je m'étais un peu exercé sur vulnserver.exe durant les semaines ayant précédé mon exam OSCE. Dans un premier temps j'ai bêtement reproduit le schéma du cours, avec SPIKE, sauf que ce n'est pas génial et que j'ai été assez vite confronté à un certain nombre de limitations de l'outil :
- l'affichage de SPIKE n'est pas super compréhensible ;
- il est difficile de faire le lien entre un crash et un paquet précis, ni même une taille de données ;
- l'outil ne vérifie pas si le programme a crashé ou non ;
- et il ne se charge pas de le relancer non plus

Bref, SPIKE c'est le moyen-âge. Ces problèmes là sont fort heureusement assez bien comblés par "Sulley" :
- qui bénéficie d'une interface "web" assez compréhensible, bien que sobre et simple ;
- conserve les paquets envoyés à chaque itération des tests dans des .pcap ;
- qui vérifie que le programme a crashé ou non et indique le numéro du test (et donc du .pcap) correspondant, avec des informations de debug ;
- qui relance le programme testé s'il a planté
- et qui, en plus, a une bonne tête ! :)



Alors je vais pas faire une explication détaillée de l'architecture de Sulley. En version TL;DR, on déploie des agents sur une machine exécutant le binaire à cibler, qui seront en charge de diverses opérations de monitoring :
- un agent réseau, prenant en paramètre un filtre (type BPF) correspondant au flux réseau à sauvegarder (genre tout le traffic reçu sur le port FTP, si on fuzz du FTP), qui attendra un "go" pour commencer à sniffer, et qui s'arrêtera quand on le lui dira
- un agent de processus, en charge du monitoring du processus que l'on fuzze, et qui surveillera l'activité de ce dernier à l'aide d'un process monitor, lui indiquant si le processus a démarré, s'il a crashé, si oui avec quelles infos (eip, seh, ...), et qui sera en charge de le redémarrer (via wmic) s'il a planté

Et de l'autre côté, on a un script qui instrumente le tout, dans lequel on définit la syntaxe du protocole mangé par le programme que l'on souhaite fuzzer, ainsi que différents paramètres liés à la cible (ip, port des monitors, port du service, délai entre deux paquets, etc).

L'installation de Sulley se passe sans encombres, la documentation sur le wiki du projet est excellente et se passe sans accrocs (testé sur un WinXP SP3). Je ne vais pas la détailler davantage.

On va donc passer à la mise en place du monitoring sur le WindowsXP, pour lequel on peut ouvrir deux interpréteurs de ligne de commande (cmd.exe), se positionner dans le dossier de Sulley (c:\sulley\sulley dans mon cas) et lancer les deux monitors :
- Pour le monitor réseau : python network_monitor.py -d 0 -f "src or dst port 9999" -P audits\vulnserver. En gros, on écoute sur la première interface (-d 0) tous les paquets en provenance ou à destination du port 9999 (port par défaut de vulnserver), et on sauvegardera tout ça dans le dossier audits\vulnserver relatif au dossier courant
- Pour le monitor de processus : python process_monitor.py -c audits\vulnserver.crashbin -p vulnserver.exe. En gros on sauvegarde le résumé de nos tests dans le fichier vulnserver.crashbin et on monitore l'état du processus "vulnserver.exe"

On doit se retrouver avec un affichage proche du screenshot suivant :

Le monitoring étant en place, on a plus qu'à créer notre script en charge de l'instrumentation de l'ensemble et de génération des mutations. Dans mon cas, il ressemble à ça :

#!/usr/bin/python
from sulley   import *

s_initialize("VULNSERVER VERBS")
s_group("verbs", values=[ "GMON", "LTER", "HTER", "GTER", "KSTET", "TRUN", "SRUN", "RTIME", "LTIME" ])
if s_block_start("body", group="verbs"):
    s_delim(" ")
    s_string("1")
    s_static("\r\n")
s_block_end()

sess = sessions.session(session_filename="audits/vulnserver.session", sleep_time=0.3, log_level=10)
target                 = sessions.target("192.168.242.66", 9999)
target.netmon          = pedrpc.client("192.168.242.66", 26001)
target.procmon         = pedrpc.client("192.168.242.66", 26002)
target.procmon_options = {
 "proc_name"      : "vulnserver.exe",
 "stop_commands"  : ['wmic process where (name="vulnserver.exe") delete'],
 "start_commands"  : ['c:\\fuzz\\sulley\\vulnserver.exe 9999'],
}
sess.add_target(target)
sess.connect(s_get("VULNSERVER VERBS"))
sess.fuzz()

La première partie du script est globalement la partie qui changera d'une séance de fuzzing à une autre, car elle correspond au protocole que vous souhaitez fuzzer. Il en existe une multitude pour tout un tas de protocoles (certains étant fournis de base avec Sulley, d'autres sur des repositories type github). On définit un groupe de commandes sur lesquelles itérer (gmon, lter, etc) ainsi que leur syntaxe (ici, un séparateur de type espace, suivi d'une chaine pouvant être fuzzée, et d'un saut de ligne).

La seconde partie est améliorable, mais restera globalement toujours la même. On définit où on veut garder l'état de notre séance de fuzzing, ainsi que l'ip/port du service à fuzzer, ainsi que les ip/ports de nos moniteurs (sur lesquels notre script va envoyer les "go" et "stop"), ainsi que les commandes permettant de relancer le service en cas de crash.

Une fois l'ensemble terminé, on a plus qu'à lancer notre script python (python machin.py). Après quelques instants on devrait avoir déjà un affichage sur nos différentes consoles :



Et surtout, ce qui est pratique, c'est l'interface web de monitoring, par défaut sur le port 26000 :


Il n'y a plus qu'à attendre un petit peu et on se retrouvera avec une jolie collection de crashs, qu'on aura plus qu'à analyser (en cliquant sur le "test case #" correspondant), voire rejouer, en récupérant le fichier .pcap dont le nom correspond au numéro du crash qui nous intéresse.

Il existe déjà pas mal de littérature existante sur l'exploitation des différentes vulnérabilités présentes dans vulnserver.exe, généralement bien indexée par Google. Je ferai peut-être un post ou deux sur des cas intéressants rencontrés dans ce binaire...Certains des exploits sont disponibles sur mon repository GitHub. En attendant, allons fuzzer la planète !

Aucun commentaire: