Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
FormatFuzzer — Fuzzer de formats binaires piloté par des modèles qui génère et analyse des entrées de test valides à grande vitesse, avec intégration AFL++ pour un fuzzing guidé par couverture. | Kitploit
Outils/GitHubGitHub/uds-se/formatfuzzer
FuzzingAnalyse de Binaires
GitHubuds-se/formatfuzzer

FormatFuzzer

Fuzzer de formats binaires piloté par des modèles qui génère et analyse des entrées de test valides à grande vitesse, avec intégration AFL++ pour un fuzzing guidé par couverture.

Voir le dépôtSite web
44638il y a 5 moisVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

FormatFuzzer

FormatFuzzer est un framework pour la génération et l'analyse de haute qualité et haute efficacité d'entrées binaires. Il prend un modèle binaire qui décrit le format d'une entrée binaire et génère un exécutable qui produit et analyse le format binaire donné. Par exemple, à partir d'un modèle binaire pour GIF, FormatFuzzer produit un générateur GIF – également connu sous le nom de fuzzer GIF.

Les générateurs produits par FormatFuzzer sont très efficaces, produisant des milliers d'entrées de test valides par seconde – contrairement aux fuzzers basés sur la mutation, où la grande majorité des entrées est invalide. Les entrées générées par FormatFuzzer sont indépendantes du programme testé (ou en fait, de tout programme), vous pouvez donc également les utiliser dans des contextes en boîte noire. Cependant, FormatFuzzer s'intègre également avec AFL++ pour produire des entrées valides qui visent également une couverture maximale. Dans nos expériences, cette approche "best of two worlds" surpasse tous les autres paramètres ; consultez notre article pour plus de détails.

Les modèles binaires utilisés par FormatFuzzer proviennent de l'éditeur 010. Il existe plus de 170 modèles binaires, qui peuvent être utilisés directement pour FormatFuzzer ou adaptés à son utilisation. Dès le départ, FormatFuzzer produit des formats tels que AVI, BMP, GIF, JPG, MIDI, MP3, MP4, PCAP, PNG, WAV et ZIP ; et nous continuons d'étendre cette liste chaque semaine.

Les contributeurs sont les bienvenus ! Visitez la page du projet FormatFuzzer pour soumettre des idées et des problèmes, ou ajouter des pull requests. Pour plus de détails sur le fonctionnement de FormatFuzzer et ses comparaisons, lisez notre article pour plus d'informations.

Obtention

FormatFuzzer est disponible depuis la page du projet FormatFuzzer. Vous pouvez télécharger et décompresser la dernière version depuis la page des versions.

Pour la toute dernière version, vous pouvez également cloner son dépôt git :

root@kitploit:~
git clone https://github.com/uds-se/FormatFuzzer.git

Toutes les actions suivantes se déroulent dans son dossier principal :

root@kitploit:~
cd FormatFuzzer

Prérequis

Pour exécuter FormatFuzzer, vous avez besoin de ce qui suit :

  • Python 3
  • Un compilateur C++ avec les bibliothèques GNU (notamment getopt_long()) tel que clang ou gcc
  • Les paquets Python py010parser, six et intervaltree
  • Une bibliothèque zlib (pour les fonctions de compression)
  • Une bibliothèque boost (pour les fonctions de somme de contrôle)

Si vous prévoyez de modifier les scripts de construction et de configuration (fichiers .ac et .am), vous aurez également besoin de

  • GNU autoconf
  • GNU automake

Installation des prérequis sur Linux (paquets Debian, en utilisant un environnement virtuel python)

root@kitploit:~
sudo apt install git g++ make automake python3-full zlib1g-dev libboost-dev
python3 -m venv ~/fuzz
source ~/fuzz/bin/activate
pip3 install py010parser six intervaltree

Installation des prérequis sur MacOS (avec Xcode & Homebrew)

root@kitploit:~
xcode-select --install
brew install python3 automake boost
pip3 install py010parser six intervaltree

Installation des paquets Python uniquement (tous les systèmes d'exploitation)

Sur tous les systèmes, en utilisant pip :

root@kitploit:~
pip install py010parser
pip install six
pip install intervaltree

Construction

Remarque : toutes les commandes de construction nécessitent que vous soyez dans le même dossier que ce fichier README. La construction d'un fuzzer en dehors de ce dossier n'est pas encore prise en charge.

Méthode 1 : Utilisation du script build.sh

Il existe un script build.sh qui automatise toutes les étapes de construction. Exécutez simplement

root@kitploit:~
./build.sh gif

pour créer un fuzzer GIF.

Cela fonctionne pour tous les formats de fichiers fournis dans templates/ ; s'il existe un fichier templates/FOO.bt, alors ./build.sh FOO construira un fuzzer.

Méthode 2 : Utilisation de Make

Il existe un Makefile (source dans Makefile.am) qui automatise toutes les étapes de construction. (Nécessite GNU make.) Tout d'abord, faites

root@kitploit:~
touch configure Makefile.in

puis

root@kitploit:~
./configure

et ensuite

root@kitploit:~
make gif-fuzzer

pour créer un fuzzer GIF.

Cela fonctionne pour tous les formats de fichiers fournis dans templates/ ; s'il existe un fichier templates/FOO.bt, alors make FOO-fuzzer construira un fuzzer.

Méthode 3 : Étapes manuelles

Si la méthode make ci-dessus ne fonctionne pas, ou si vous souhaitez plus de contrôle, vous devrez peut-être procéder manuellement.

Étape 1 : Compilation des fichiers de modèles binaires en code C++

Exécutez le compilateur ffcompile pour compiler le modèle binaire en code C++. Il prend deux arguments : le modèle binaire .bt et un fichier .cpp C++ à générer.

root@kitploit:~
./ffcompile templates/gif.bt gif.cpp

Étape 2 : Compilation du code C++

Utilisez les commandes suivantes pour créer un fuzzer gif-fuzzer. Tout d'abord, compilez le pilote générique en ligne de commande :

root@kitploit:~
g++ -c -I . -std=c++17 -g -O3 -Wall fuzzer.cpp

(-I . désigne l'emplacement du fichier bt.h ; -std=c++17 définit la norme C++.)

Ensuite, compilez l'analyseur/compilateur binaire :

root@kitploit:~
g++ -c -I . -std=c++17 -g -O3 -Wall gif.cpp

Enfin, liez l'analyseur/compilateur binaire avec le pilote en ligne de commande pour obtenir un exécutable. Si vous utilisez des bibliothèques supplémentaires (telles que -lz), assurez-vous de les spécifier ici aussi.

root@kitploit:~
g++ -O3 gif.o fuzzer.o -o gif-fuzzer -lz

Exécution du Fuzzer

FormatFuzzer peut être exécuté comme un analyseur, générateur ou mutateur autonome de formats spécifiques. De plus, il peut être appelé par des fuzzers généralistes tels que AFL++ pour intégrer ces capacités spécifiques au format dans le processus de fuzzing (voir la section ci-dessous sur l'intégration AFL++).

Le fuzzer généré prend une commande comme premier argument, suivie d'options et d'arguments pour cette commande.

La commande la plus importante est fuzz, pour produire des sorties. Ses arguments sont les fichiers à générer dans le format approprié.

Exécutez le générateur comme

root@kitploit:~
./gif-fuzzer fuzz output.gif

pour créer un fichier binaire aléatoire output.gif, ou

root@kitploit:~
./gif-fuzzer fuzz out1.gif out2.gif out3.gif

pour créer trois fichiers GIF out1.gif, out2.gif et out3.gif.

Notez que le template gif.bt que nous fournissons a été augmenté avec des fonctions spéciales pour faciliter la génération de fichiers valides. Si vous utilisez des fichiers template .bt originaux sans adaptations, vous pouvez obtenir des avertissements lors de la génération et créer des fichiers invalides.

Exécution d'Analyseurs

Vous pouvez également exécuter le fuzzer comme un analyseur de fichiers binaires, en utilisant la commande parse. Cela est utile si vous voulez tester la précision du modèle binaire, ou si vous voulez muter une entrée (voir 'Fichiers de Décision', ci-dessous).

Pour exécuter l'analyseur, utilisez

root@kitploit:~
./gif-fuzzer parse input.gif

Vous verrez des messages d'erreur si input.gif ne peut pas être analysé avec succès.

Fichiers de Décision

Lors de l'analyse, vous pouvez également stocker toutes les décisions d'analyse (c'est-à-dire quelles alternatives d'analyse ont été prises) dans un fichier de décision. Il s'agit d'une séquence d'octets énumérant les décisions prises. Chaque octet représente une seule décision d'analyse. Une valeur d'octet de 0 signifie que la première alternative a été prise, une valeur d'octet de 1 signifie que la deuxième alternative a été prise, et ainsi de suite.

Vous pouvez générer un tel fichier de décision lors de l'analyse d'une entrée :

root@kitploit:~
./gif-fuzzer parse --decisions input.dec input.gif

Ici, input.dec stocke les décisions prises pour analyser input.gif.

Vous pouvez également utiliser un tel fichier de décision lors de la génération d'entrées. Le fuzzer prendra alors exactement les mêmes décisions que celles trouvées lors de l'analyse. La commande suivante génère un nouveau fichier GIF en utilisant les décisions déterminées lors de l'analyse de input.gif :

root@kitploit:~
./gif-fuzzer fuzz --decisions input.dec input2.gif

Si tout fonctionne bien, les deux fichiers devraient être identiques :

root@kitploit:~
cmp input.gif input2.gif

En mutant un fichier de décision (par exemple en remplaçant des octets individuels), vous pouvez créer des entrées qui sont similaires au fichier original analysé. Ceci est utile pour interfacer avec des stratégies de test spécifiques et des fuzzers tels qu'AFL, où vous pouvez utiliser gif-fuzzer et similaires comme traducteurs de fichiers de décision en fichiers binaires et vice versa : AFL muterait les fichiers de décision, et le programme testé s'exécuterait sur les fichiers binaires traduits. Contrairement à la mutation directe des fichiers binaires (comme AFL le ferait normalement), cela aurait l'avantage d'avoir toujours des entrées valides – et donc de progresser beaucoup plus rapidement vers la couverture.

Intégration AFL++

En plus des fuzzers spécifiques au format, tels que gif-fuzzer, FormatFuzzer peut également être compilé en bibliothèques partagées spécifiques au format, telles que gif.so (pour cela, exécutez simplement ./build.sh gif ou make gif.so). Ces bibliothèques partagées peuvent être chargées par des fuzzers généralistes, tels que AFL++.

Pour exécuter AFL++ avec FormatFuzzer, suivez simplement les instructions sur notre version modifiée d'AFL++. Nous prenons en charge différentes stratégies de fuzzing, notamment :

  • AFL+FFMut : exécute AFL++ en utilisant FormatFuzzer pour fournir des mutations intelligentes spécifiques au format.

  • AFL+FFGen : utilise FormatFuzzer comme générateur spécifique au format, tandis qu'AFL++ mute ses graines de décision.

Création et personnalisation de modèles binaires

Pour écrire vos propres modèles binaires .bt (et ainsi créer un fuzzer/analyseur haute efficacité pour ce format), lisez la section Introduction to Templates and Scripts du manuel de l'éditeur 010.

Dans de nombreux cas, un modèle du format que vous recherchez (ou un modèle similaire) peut déjà exister. Jetez un œil à la collection de modèles binaires de l'éditeur 010 pour voir s'il y a quelque chose que vous pouvez utiliser ou sur lequel baser votre format.

Notez que les fichiers .bt fournis dans le dépôt ciblent généralement l'analyse de fichiers. Ils peuvent également être utilisés pour la génération de fichiers ; mais ils manquent souvent d'informations précises sur les parties de l'entrée qui sont requises.

Dans cette section, nous discutons de certaines des façons dont vous pouvez personnaliser les fichiers .bt pour bien fonctionner avec FormatFuzzer.

Par exemple, pour le format GIF, le fichier templates/gif-orig.bt montre le modèle binaire original, qui n'était conçu que pour l'analyse, tandis que le fichier templates/gif.bt est une version modifiée capable de générer des GIF valides. En comparant les deux fichiers, nous voyons qu'un petit nombre de modifications a été nécessaire pour y parvenir.

Si vous avez créé un gif-fuzzer, soit en exécutant make gif-fuzzer, soit en utilisant l'outil ffcompile, vous avez déjà obtenu un fichier C++ gif.cpp qui contient une implémentation du générateur et analyseur GIF. Cela est utile pour voir comment les modifications que vous apportez au modèle binaire se traduisent en code exécutable. Plus de détails sur le code C++ sont présentés dans la section suivante.

Le modèle binaire GIF utilise des fonctions de lookahead ReadUByte() et ReadUShort() pour regarder à l'avance les valeurs des prochains octets du fichier avant de les analyser réellement dans un champ de structure. Au moment de la génération, nous permettons à ces fonctions de recevoir un argument supplémentaire spécifiant un ensemble de bonnes valeurs connues à choisir pour les octets que nous regardons à l'avance. De plus, nous permettons également de spécifier un ensemble global de bonnes valeurs connues à toujours utiliser lors de l'appel d'une fonction de lookahead particulière, telle que ReadUByte(). Celles-ci sont stockées dans le vecteur ReadUByteInitValues.

Par défaut, notre procédure de traduction ffcompile essaie de extraire les valeurs intéressantes qui ont été utilisées dans des comparaisons avec les octets de lookahead et de les utiliser comme un ensemble global de valeurs connues. Lors de l'exécution de

root@kitploit:~
./ffcompile templates/gif.bt gif.cpp

un message imprimé montre les fonctions de lookahead identifiées, ainsi que les valeurs intéressantes extraites :

root@kitploit:~
Finished creating cpp generator.

Lookahead functions found:

ReadUByte
ReadUShort

Mined interesting values:

GlobalColorTableFlag: ['1']
LocalColorTableFlag: ['1']
ReadUByte: ['0x3B', '0x2C']
ReadUShort: ['0xF921', '0xFE21', '0x0121', '0xFF21']
Signature: ['"GIF"']

Pour la génération GIF, cependant, il est préférable de spécifier l'ensemble de bonnes valeurs connues pour ReadUByte() individuellement à chaque appel de la fonction. Nous définissons donc un tableau vide (taille 0)

root@kitploit:~
const local UBYTE ReadUByteInitValues[0];

pour écraser l'ensemble des ReadUByteInitValues globaux et pour chaque appel à ReadUByte(), nous utilisons un argument supplémentaire pour spécifier l'ensemble de bonnes valeurs à utiliser pour cet emplacement particulier. Le langage de modèle binaire est également assez puissant pour permettre que ce choix soit fait en fonction des conditions d'exécution. Par exemple, dans le code suivant, nous montrons comment le choix de valeurs appropriées pour un appel ReadUByte() peut dépendre de la version GIF en cours de génération. Une version GIF 89a permet une valeur supplémentaire possible pour l'octet (0x21).

root@kitploit:~
	if(GifHeader.Version == "89a")
		local UBYTE values[] = { 0x3B, 0x2C, 0x21 };
	else
		local UBYTE values[] = { 0x3B, 0x2C };

	while (ReadUByte(FTell(), values) != 0x3B) {
		...
	}

Les modifications restantes nécessaires pour le modèle binaire GIF sont similaires. Par exemple, pour chaque champ de structure, vous pouvez également spécifier un ensemble de bonnes valeurs connues. Par exemple, cela spécifie les valeurs correctes pour le champ Version : 87a et 89a.

root@kitploit:~
	char	Version[3] = { {"87a"}, {"89a"} };

Comprendre le code C++ généré

À des fins de débogage, ainsi que pour comprendre comment apporter les modifications appropriées pour améliorer vos générateurs et analyseurs, il peut être utile de comprendre certains fonctionnements internes du code C++ généré. Idéalement, vous devriez pouvoir modifier les fichiers de modèle binaire jusqu'à ce qu'ils puissent être utilisés pour générer des fichiers valides avec une probabilité élevée, afin de ne pas avoir à modifier le code C++ généré.

Le code C++ crée une classe pour chaque struct et union définis dans le modèle binaire, ainsi que pour les types natifs, tels que int.

Lors de la construction, lors de l'initialisation d'une variable, nous pouvons définir un ensemble de bonnes valeurs connues que cette variable peut prendre. Par exemple, l'appel constructeur

root@kitploit:~
char_array_class cname(cname_element, { "IHDR", "tEXt", "PLTE", "cHRM", "sRGB", "iEXt", "zEXt", "tIME", "pHYs", "bKGD", "sBIT", "sPLT", "acTL", "fcTL", "fdAT", "IHDR", "IEND" });

spécifierait 17 bonnes valeurs à utiliser pour la variable cname. Mais cela n'est souvent pas suffisant, car le choix des types de chunks appropriés dépend du contexte. Nous permettons donc également de spécifier un ensemble de bonnes valeurs au moment de la génération lors de la génération d'un nouveau chunk. Par exemple, cet appel pourrait être utilisé pour générer une instance de chunk pour le premier chunk, qui doit être de type IHDR.

root@kitploit:~
GENERATE(chunk, ::g->chunk.generate({ "IHDR" }, false));

Lors de la génération du deuxième chunk, nous pourrions utiliser cette longue liste de chunks possibles qui peuvent se trouver entre le chunk IHDR et le chunk PLTE :

root@kitploit:~
GENERATE(chunk, ::g->chunk.generate({ "iCCP", "sRGB", "sBIT", "gAMA", "cHRM", "pHYs", "sPLT", "tIME", "zTXt", "tEXt", "iTXt", "eXIf", "oFFs", "pCAL", "sCAL", "acTL", "fcTL", "fdAT", "fRAc", "gIFg", "gIFt", "gIFx", "sTER" }, true));

Le générateur choisira alors uniformément l'une des bonnes valeurs connues à utiliser pour la nouvelle instance. Nous permettons également le choix d'une valeur malveillante qui n'est pas l'une des bonnes valeurs connues avec une faible probabilité de 1/128. Cette fonctionnalité peut être activée ou désactivée à tout moment en utilisant la méthode set_evil_bit.

Tous les choix aléatoires effectués par le générateur se font en appelant la méthode rand_int().

root@kitploit:~
long long rand_int(unsigned long long x, std::function<long long (unsigned char*)> parse);

Lorsque le programme est exécuté en tant que générateur, cette méthode échantillonne un entier de 0 à x-1 en lisant des octets du tampon aléatoire. Lorsque le programme est exécuté en tant qu'analyseur, cette méthode utilise la fonction parse() pour trouver quels octets aléatoires doivent être présents dans le tampon aléatoire afin de générer le fichier cible, puis écrit ces octets dans le tampon aléatoire. La fonction parse reçoit en argument le tampon à la position actuelle du fichier et doit ensuite retourner la valeur que l'appel actuel à rand_int() devrait retourner afin de générer cette configuration exacte du fichier.

Auteurs

FormatFuzzer a été conçu et écrit par Rafael Dutra <[email protected]>.

Le concept d'un compilateur de fuzzer a été introduit par Rahul Gopinath <[email protected]> et Andreas Zeller <[email protected]>.

Copyright et Licences

FormatFuzzer est Copyright © 2020, 2021 par CISPA Helmholtz Center for Information Security. Les licences suivantes s'appliquent :

  • Le code de FormatFuzzer (notamment, tout le code C++ et le code lié à sa génération) est soumis à la GNU GENERAL PUBLIC LICENSE, comme indiqué dans COPYING.

  • Par exception à ce qui précède, le code C++ généré par FormatFuzzer (c'est-à-dire les fuzzers et analyseurs pour des formats spécifiques) est dans le domaine public.

  • Le code original pfp sur lequel FormatFuzzer est basé est soumis à une licence MIT, comme indiqué dans LICENSE-pfp.

Télécharger l’outil