Placez-vous dans un nouveau répertoire de travail et recopiez dans
ce répertoire des fichiers nécessaires au TP :
cp -r ~mounlaur/TP_AFL/* .
Exercice 1 : Prise en main du fuzzer AFL
Le fuzzer AFL n'est pas
installé en standard, il vous faut donc régler des chemins d'accès
par la commande
source ~mounlaur/installe_afl.sh
(cette commande est à taper dans chaque nouveau shell lancé).
Pour utiliser AFL, il faut procéder en plusieurs étapes :
- Recompiler le programme que l'on veut tester avec un
compilateur permettant d'ajouter au code binaire produit des
informations qui seront utilisées par AFL (il est possible
d'utiliser AFL sans recompiler le programme, à l'aide d'un
émulateur, mais nous n'utiliserons pas cette possibilité ici).
- Fournir des fichiers de test initiaux dans un répertoire
; AFL commencera à exécuter le programme cible à l'aide de ces
fichiers puis il les fera évoluer pour tenter de "couvrir" de
nouvelles parties du code.
- Enfin, lancer AFL en lui indiquant le nom du répertoire
contenant les fichiers initiaux, le nom du répertoire dans
lequel il devra fournir les résultats, et le nom du programme
(exécutable) cible.
Essayer de mettre en oeuvre ces étapes sur le programme
exemple1.c en exécutant les commandes suivantes :
- compiler exemple1.c avec le compilateur afl-gcc :
afl-gcc exemple1.c -o exemple1
- créer un répertoire afl_in et mettez dans ce répertoire un
fichier test1.txt contenant un entier (strictement inférieur à
100)
mkdir afl_in
echo 42 > afl_in/test1.txt
- vérifiez que le programme exemple1 ne "plante" pas sur le
fichier test1.txt
./exemple1 afl_in/test1.txt
- lancez AFL pour détecter un (ou plusieurs) "crash", et laissez
le fuzzer tourner jusqu'à ce qu'un crash soit détecté ...
afl-fuzz -i afl_in/ -o afl_out/
./exemple1 @@
- Examinez le contenu du répertoire afl_out/crashes ; il doit
contenir un fichier de test ayant provoqué le crash (de nom
id
...)
- Vérifiez que le programme exemple1 se provoque bien un crash
lorsqu'on l'exécute ce test ... Vous pouvez éventuellement
re-compiler le programme avec l'option "-g" et examiner son
comportement avec gdb pour comprendre le crash ...
Exercice 2 : Créer / Trouver des
vulnérabilités dans du code
Il s'agit maintenant de mieux comprendre les forces et
faiblesses de AFL en le faisant tourner sur des exemples de
programmes de votre choix contenant des "vulnérabilités".
N'oubliez pas que :
- AFL ne peut détecter que des crash
- sa stratégie d'exploration du code est forcément limitée (il
peut très bien ne pas détecter certain crashs ..)
Pour chacun de vos exemples, indiquez :
- pourquoi le programme est sensé provoquer un crash ?
- est-ce que AFL a détecté ce crash ou non ? Selon vous
pourquoi ?
Indications : vous pouvez commencer par de "petits" exemples
(comme exemple1.c), puis essayer sur des exemples de TPs que vous
avez déjà réaliser. Vous pouvez aussi si nécessaire inclure
"artificiellement" des bugs dans ces TPs et vérifier si AFL les
retrouve ou non ...
Exercice 3 : Un exemple plus gros
On s'intéresse maintenant à l'utilisation de AFL pour
trouver des erreurs dans un programme que l'on veut évaluer mais que
l'on ne connait pas a priori (il serait donc difficile d'écrire une
suite de test pertinente pour ce programme). Il s'agit ici d'un
parser générique, permettant de décrire facilement la syntaxe d'un
langage et d'effectuer des traitements sur ce langage (il n'est pas
nécessaire d'en savoir plus pour utiliser AFL !).
Ce programme se trouve dans le répertoire parser_example
.
- Compilez ce programme avec la commande make (qui va produire
plusieurs exécutables dans le répertoire examples)
- Notre cible sera le programme
example/maths
.
Exécuter ce programme sur le fichier test2.txt
: examples/maths test2.txt
- Essayez de modifier à la main
test2.txt
pour
voir si vous obtenez des crashs à l'exécution
- Exécutez ensuite AFL en prenant
test2.txt
comme
jeu de test initial .. vous devez obtenir 40 crashs
unique :-)
- Essayez de trouver avec gdb la cause de l'un de ces crashs ...
Exercice 4 : Retour sur le projet ...
Vous pouvez maintenant essayer AFL sur votre projet en
vous rappelant que les données d'entrées su programme doivent se
trouver dans un fichier (il faudra donc peut-être légèrement adapter
votre code ?)
Typiquement ceci vous permettra de vérifier si votre traitement du
fchier XML est "sécurisée" ...