fuzzing partie 2

Fuzzing Partie 2 – Fuzzing avec AFL

Comme je l'ai écrit dans le dernier chapitre, dans cet article j'expliquerai seulement comment fuzzer lorsqu'il y a accès au code source en utilisant AFL. Pour démontrer, j'ai pris un vieux programme open-source que j'ai trouvé sur GitHub appelé ccalc. Comme son nom l'indique, il s'agit d'une simple calculatrice écrite en C. Je l'ai choisie car il était probable que le fuzzing y trouverait facilement de nombreux plantages, et comme vous le verrez, cette hypothèse s'est avérée correcte.

Tout d'abord, nous devons déterminer une cible. J'ai décidé de fuzzer la fonction main(), au lieu de trouver une fonction spécifique à fuzzer. Le raisonnement est que le programme analyse l'entrée brute dans une série de fonctions avant de transmettre l'entrée traitée aux fonctions qui effectuent elles-mêmes les calculs. Étant donné que le programme filtre les mauvaises entrées lors de l'analyse, il n'est pas juste de fuzzer une fonction spécifique.

Le main() original ressemble plus ou moins à ceci (je l'ai un peu abrégé):

Fonction principale

En général, il contient deux branches : soit il reçoit une entrée via argc, argv[], ou via l'entrée standard (stdin). Je ne sais pas pourquoi, mais le créateur de l'AFL recommande explicitement ne sauraient passer à travers argc, argv[], ainsi que toutes les autres sources en ligne. Je l'ai donc un peu modifié : j'ai d'abord supprimé la section qui traite des entrées provenant de argc, argv, puis j'ai essayé de l'optimiser au maximum. Après tout, chaque fois que le fuzzer essaie une autre entrée, cette fonction est exécutée. Petite boîte donc Les inefficacités peuvent entraîner de graves ralentissements. Voici le résultat final :

Fonction principale après modification

Remarquez la boucle que j'ai ajoutée. Il demande à AFL d'utiliser le mode persistant. Dans le mode par défaut d'AFL, chaque fois qu'AFL exécute les programmes, il utilise l'appel système fork() pour créer un nouveau sous-processus. Cet appel système a une surcharge importante, ce qui ralentit considérablement l'ensemble du processus de fuzzing. Lorsque le mode persistant est utilisé, le fuzzer utilise le même processus encore et encore. La seule exigence est d'effacer toutes les variables et les tampons à chaque exécution de la boucle.

J'ai appelé le fichier avec la fonction modifiée harnais.c, et pour compiler le programme avec ce fichier et non avec main.c, j'ai changé la forme du fichier automake :

fichier automake avant le changement

à

fichier automake après le changement

Il est maintenant temps de fuzzer le programme. J'ai exécuté automake afin de générer les fichiers make, puis de se créer avec la commande :

commande automake

Pour que le programme compile avec l'instrumentation AFL.

La seule chose qui reste à faire maintenant est de créer le dossier d'entrée initial pour AFL, que j'ai appelé "in", et le dossier de sortie "out". Dans le dossier d'entrée, on met des fichiers texte simples (sans format) qui contiennent des entrées légitimes, comme « 20/2 » ou « 5*4 ». Puisque nous voulons exécuter quelques processus AFL (chaque processus s'exécutant sur son propre cœur de processeur), nous créons un dossier d'entrée séparé pour chaque processus.

dossier d'entrée pour chaque processus

Pour fuzzer, on lance simplement la commande :

Commande d'exécution AFL pour la première utilisation

Pour le premier processus, le second étant

Commande d'exécution AFL pour une deuxième utilisation

Et ainsi de suite.

Comme vous pouvez le voir dans la capture d'écran suivante, AFL a une interface graphique qui donne des informations importantes sur le processus de fuzzing. Par exemple, les mesures de la couverture sont données sous couverture de la carte, et sous découvertes approfondies l'interface graphique fournit également le nombre de plantages et des informations connexes.

Interface graphique de progression AFL
Interface graphique de progression AFL

Une fois qu'un nombre suffisant (le nombre exact dépend de vous) de plantages a été trouvé, généralement après une longue période sans nouveau plantage unique, vous pouvez mettre fin au processus. Pour chaque processus d'AFL que vous exécutez, un dossier séparé sera généré dans le dossier de sortie :

Dossier de sortie

Dans ces dossiers, les données sont organisées comme ceci :

Contenu du dossier de sortie

Il est important d'expliquer quelles informations chacune de ces informations contient :

  • plot_data - met les informations sous une forme conduisant à la génération d'un tracé.
  • fuzzer_stats – statistiques sur le processus de fuzzing.
  • fuzz_bitmap - un bitmap dans lequel chaque octet correspond à une branche du programme.
    "AFL maintient un" bitmap fuzz ", chaque octet du bitmap représentant le nombre de fois qu'une branche particulière du programme flou a été prise. AFL n'effectue pas de mappage un à un entre une branche particulière et un octet dans le bitmap. Au lieu de cela, l'instrumentation intégrée d'AFL place un ID constant aléatoire de deux octets dans chaque branche. Chaque fois que l'exécution atteint une branche instrumentée, AFL effectue un XOR de l'ID de la nouvelle branche et du dernier ID de branche vu avant d'arriver à la nouvelle branche. Cela capture à la fois la branche actuelle et le chemin unique emprunté pour l'atteindre (par exemple lorsque la même fonction est appelée à partir de plusieurs emplacements dans le code). AFL applique ensuite une fonction de hachage à la valeur XOR'd pour déterminer quelle entrée dans le bitmap représente cette combinaison de branches. Chaque fois qu'une combinaison de branches particulière est exercée, l'octet approprié est incrémenté dans le bitmap.
  • cmdline - la commande qui a été fournie à AFL. En pratique le nom du programme.
  • .cur_input - l'entrée actuelle.
  • file d'attente - toutes les entrées qui ont été essayées jusqu'à présent.
  • se bloque et se bloque - les résultats. Chaque fichier de ces dossiers contient des entrées qui ont provoqué des plantages ou des blocages. Spécifié dans le nom de chaque fichier est le signal du noyau du plantage (non pertinent dans les blocages, bien sûr), l'ID de l'entrée utilisée par AFL pour créer l'entrée qui a causé le plantage, le temps écoulé depuis qu'AFL a commencé à s'exécuter, et la mutation utilisée pour générer l'entrée à partir de sa graine.
Passer au contenu