vendredi 6 mai 2016

Analyse d'un "dropper" de ransomware

C'est vendredi, c'est permis. Comme beaucoup (trop) de monde, je reçois pas mal d'e-mails contenant des pièces jointes malveillantes. Ces derniers temps, la tendance est aux ransomwares. Après tout, pas besoin de dépenser des fortunes dans des exploits touchant la dernière version du navigateur ou du client mail de l'utilisateur, quand on peut compter sur sa coopération lorsqu'il s'agira de lui demander d'ouvrir un document, et ensuite de payer pour récupérer (ou pas) l'accès à ses fichiers.

Alors le document du jour a été envoyé par l'adresse IP 182.180.112.194 (au Pakistan, mais ça on s'en fout un peu vu qu'il s'agit probablement d'une machine compromise) depuis une adresse gmail, visiblement spoofée en raison d'un en-tête SPF en "softfail" (signifiant que l'IP ayant envoyé l'e-mail n'est pas autorisée via les règles SPF à utiliser le domaine GMail, mais que le propriétaire du domaine le tolère). La pièce jointe est un document Word 2007+ d'environ 45ko :


Alors on peut évidemment aller droit au but et balancer le document dans notre sandbox préférée, voire sur VirusTotal, si l'on a pas de contraintes de confidentialité des données etc. Dans mon cas, il s'agit d'une boite mail perso, je n'ai pas de contraintes particulières. Dans le pire des cas, on peut calculer le hash du document, et le rechercher directement sur les sites mentionnés ci-dessus, comme ça, si l'on ne peut pas (pour diverses raisons) soumettre le fichier, on saura si des informations existent à son sujet.

Mais on peut aussi avoir envie de décortiquer un peu le document. Alors attention, l'analyse qui suit est loin d'être un modèle, mais certains y trouveront sûrement des informations intéressantes.

Un outil que j'ai découvert il n'y a pas si longtemps, c'est "mraptor" de la suite "oletools". Son verdict est immédiat :


On voir direct le gros "SUSPICIOUS" (qui ne se traduit pas par "SUSPICIEUX", mais "SUSPECT"), ainsi que les flags signifiant que la macro s'exécute dès l'ouverture du document (pour peu que les macros soient activées), que des données sont écrites sur le disque, et que la macro exécute un binaire.

D'ailleurs, intéressons nous davantage à cette macro. On va utiliser l'outil "olevba", toujours de la suite oletools :


Malgré plusieurs essais d'options du script, il n'a pas été en mesure de déchiffrer les chaines obfusquées. Ce n'est pas parce que c'est complexe, mais parce qu'il n'a pas été en mesure d'identifier le pattern et de les décoder. Ce n'est pas bien grave, ça se fait très facilement à la main. Avec le même outil, on obtient le code de la macro (juste au dessus du tableau). Au premier abord, le code de la macro ressemble à un set de fonctions de conversions d'unités de mesures diverses, comme par exemple des conversions de volumes, de pressions, etc. Puis on repère assez vite ce morceau de code (pas reproduit dans son intégralité) :


Evidémment, vu comme ça ça ne ressemble à rien. Juste une sorte de chaine de caractères comportant plusieurs valeurs numériques séparées par des caractères ressemblant à des guillemets, qui est splittée, vraissemblablement en prenant ces caractères comme séparateurs, afin de ne garder en sortie qu'un tableau d'entiers, qui ne correspondent pas à un charset connu. On regarde si "sOvetSPL" est utilisé ailleurs dans le code, pour voir quel traitement est fait sur ce tableau :


On a donc une itération sur chacun des entiers, divisé par 16, et converti ensuite en caractère. C'est vrai que si on regarde la gueule de la chaîne d'origine, on repère des patterns à l'oeil nu. Les premiers caractères évoquent assez facilement un "http://". Plutôt que faire chaque caractère à la main (vu la longueur de la chaîne obfusquée ça peut se faire cela dit), on va scripter ça :


On obtient donc une URL. Le reste de l'obfuscation est assez lourde à décortiquer, certaines informations étant obtenues depuis les fichiers embarqués dans le document, mais il est assez facile de déterminer qu'il s'agit d'une fonction effectuant le téléchargement du fichier présent à l'URL ci-dessus, et que ce fichier est par la suite exécuté. L'analyse de ce malware nécessiterait un post à part entière, mais sans surprises, il s'agit d'un ransomware, visiblement un bon vieux Locky :


Notons qu'il s'agit ici des seuls anti-virus qui détectent cette variante de Locky :-)

Autre point amusant vu sur Malwr, le malware refuse visiblement de s'exécuter sur une machine virtuelle. C'est bon à savoir pour ne pas se faire chiffrer ses données :-)

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 !