
Manul est un fuzzer parallèle guidé par la couverture pour binaires open-source et blackbox sur Windows, Linux et MacOS

Manul est un fuzzer parallèle guidé par couverture pour les binaires open-source et boîte noire sur Windows, Linux et macOS (bêta) écrit en pur Python.
pip3 install psutil
git clone https://github.com/mxmssh/manul
cd manul
mkdir in
mkdir out
echo "AAAAAA" > in/test
python3 manul.py -i in -o out -n 4 "linux/test/test_afl @@"
sudo apt-get install gcc make git wget
git clone https://gitlab.com/akihe/radamsa.git && cd radamsa && make && sudo make install
Il n'est pas nécessaire d'installer radamsa sur Windows, Manul est distribué avec la bibliothèque native radamsa sur cette plateforme.
| Identifiants CVE | Produit | Découvreur |
|---|---|---|
| CVE-2019-9631 CVE-2019-7310 CVE-2019-9959 | Poppler | Maksim Shudrak |
| CVE-2018-17019 CVE-2018-16807 CVE-2019-12175 | Bro/Zeek | Maksim Shudrak |
Si vous avez réussi à trouver un nouveau bogue en utilisant Manul, veuillez me contacter et je vous ajouterai à la liste.

pip install pywin32) sur la plateforme Windows (nécessaire uniquement pour le mode persistance DBI).Actuellement, Manul prend en charge deux types d'instrumentation : basée sur AFL (afl-gcc, afl-clang et afl-clang-fast) et DBI.
Instrumentez votre cible avec afl-gcc ou afl-clang-fast et Address Sanitizer (recommandé pour de meilleurs résultats). Par exemple :
CC=afl-gcc CXX=afl-g++ CFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address cmake <chemin_vers_votre_cible>
make -j 8
USE_ASAN=1 CC=afl-clang-fast CXX=afl-clang-fast++ cmake <chemin_vers_votre_cible>
make -j 8
Voir ces instructions pour plus de détails.
Vous n'avez pas besoin d'instrumenter votre cible dans ce mode mais vous devez télécharger la dernière version du framework DynamoRIO pour Windows ou Linux.
Manul est distribué avec des clients x86/x64 précompilés pour Linux et Windows. Vous pouvez les trouver dans les dossiers suivants :
linux/dbi_32|dbi_64/libbinafl.so (client DynamoRIO)
win/dbi_32|dbi_64/binafl.dll
Malheureusement, DynamoRIO n'est pas officiellement pris en charge sur MacOS.
Vous pouvez trouver les derniers paquets de version de DynamoRIO sur la page de téléchargement de DynamoRIO.
Vous devez décommenter les lignes suivantes dans le fichier manul.config et fournir le chemin correct vers le lanceur et le client DynamoRIO.
# Choisir le framework DBI pour fournir la couverture à Manul ("dynamorio" ou "pin"). Exemple dbi = dynamorio
dbi = dynamorio
# Si le paramètre dbi n'est pas None, le chemin vers le lanceur du moteur DBI et le client DBI doivent être spécifiés.
dbi_root = /home/max/DynamoRIO/bin64/drrun
dbi_client_root = /home/max/manul/linux/dbi_64/libbinafl.so
dbi_client_libs = None
De plus, vous pouvez augmenter les performances de votre campagne de fuzzing en boîte noire en utilisant le fuzzing persistant en mémoire. Dans ce mode, vous devez indiquer à Manul d'instrumenter une fonction particulière (oui, vous devez la trouver en désassemblant votre binaire) et il l'exécutera en boucle en décommentant les lignes suivantes :
dbi_persistence_mode = 1
dbi_target_module = afl_test
dbi_target_method = open_file
#dbi_target_offset = 0x3198 # optionnellement, vous pouvez fournir l'offset de cette fonction au lieu du nom
dbi_fuzz_iterations = 1000
Les auteurs de winAFL fournissent une très bonne explication sur son fonctionnement ici. Manul utilise une grande partie du code de la bibliothèque d'instrumentation de winAFL pour communiquer et instrumenter une cible.
NOTE IMPORTANTE : Vous devez utiliser un lanceur 32 bits et un client 32 bits pour fuzzer les binaires 32 bits et un lanceur 64 bits et un client 64 bits pour les binaires 64 bits !
Pour compiler la bibliothèque d'instrumentation, vous devez utiliser la dernière version de DynamoRIO. Le code source de la bibliothèque d'instrumentation se trouve dans dbi_clients_src situé dans le dossier principal de Manul.
Linux 64 bits
cd dbi_clients_src
wget <DynamoRIO-x86_64-Linux-X.XX.XXXX-X.tar.gz> - télécharger la dernière version de DynamoRIO
tar xvf DynamoRIO-x86_64-X.XX.XXXX-X.tar.gz
mkdir client_64
cd client_64
cmake ../dr_cov/ -DDynamoRIO_DIR=/home/max/manul/dbi_clients_src/DynamoRIO-x86_64-Linux-X.XX.XXXX-X.tar.gz/cmake
make
Linux 32 bits
cd dbi_clients_src
wget <DynamoRIO-i386-Linux-X.XX.XXXX-X.tar.gz> - télécharger la dernière version de DynamoRIO
tar xvf DynamoRIO-x86_64-X.XX.XXXX-X.tar.gz
mkdir client_64
cd client_64
CFLAGS=-m32 CXXFLAGS=-m32 cmake ../dr_cov/ -DDynamoRIO_DIR=/home/max/manul/dbi_clients_src/DynamoRIO-i386-Linux-X.XX.XXXX-X.tar.gz/cmake
make
Sur Windows, la façon la plus simple de compiler la bibliothèque serait d'installer Visual Studio (testé sur les versions 2017 et 2013), de lancer VS20XX Cross Tools Command Prompt et d'exécuter les commandes suivantes :
Windows 64 bits
cd dbi_clients_src
<Télécharger et extraire la dernière version de DynamoRIO>
mkdir client_64
cd client_64
cmake -G"Visual Studio 15 Win64" ..\dr_cov\ -DDynamoRIO_DIR=C:\Users\max\manul\dbi_clients_src\DynamoRIO-Windows-XXXX.XX.X.X\cmake
cmake --build . --config RelWithDebInfo (ou Debug si nécessaire)
Windows 32 bits
cd dbi_clients_src
<Télécharger et extraire la dernière version de DynamoRIO>
mkdir client_32
cd client_32
cmake -G"Visual Studio 15" ..\dr_cov\ -DDynamoRIO_DIR=C:\Users\max\manul\dbi_clients_src\DynamoRIO-Windows-XXXX.XX.X.X\cmake
cmake --build . --config RelWithDebInfo (ou Debug si nécessaire)
Manul prenait initialement en charge le fuzzing guidé par couverture Intel PIN mais en raison de faibles performances et d'une surcharge de maintenance élevée, ce n'est plus pris en charge.
Les options les plus fréquemment utilisées peuvent être fournies via la ligne de commande. Davantage d'options sont prises en charge via le fichier de configuration (manul.config).
Exemple : python3 manul.py -i corpus -o out_dir -n 40 "cible @@"
arguments positionnels :
target_binary Le binaire cible et les options à exécuter (n'oubliez pas d'inclure les guillemets, par exemple "cible e @@").
arguments optionnels :
-h, --help affiche ce message d'aide et quitte
-n NFUZZERS Nombre de fuzzers parallèles
-s Exécuter un fuzzing aveugle (aucune instrumentation de code)
-c CONFIG Chemin vers le fichier de configuration avec des options supplémentaires (voir la section Options du fichier de configuration ci-dessous)
-r Restaurer la session précédente
Paramètres requis :
-i INPUT Chemin vers le répertoire contenant le corpus initial
-o OUTPUT Chemin vers le répertoire de sortie
Manul est distribué avec le fichier manul.config par défaut où l'utilisateur peut trouver toutes les options prises en charge et des exemples d'utilisation. Les options doivent être spécifiées au format suivant Format: <nom_option> = <valeur>. Le symbole # peut être utilisé pour ignorer une ligne.
dict = /home/max/dictionaries/test.dict. La stratégie de mutation AFL permet à l'utilisateur de spécifier une liste de jetons personnalisés qui peuvent être insérés à des endroits aléatoires dans le fichier fuzzé. Manul prend en charge cette fonctionnalité via cette option (chemins absolus de préférence).
mutator_weights=afl:7,radamsa:2,my_mutator:1. Les poids des mutateurs permettent à l'utilisateur d'indiquer à Manul combien de mutations par 10 exécutions doivent être effectuées par un certain fuzzer. Dans cet exemple, le mutateur AFL sera exécuté dans 7/10 mutations, Radamsa 2/10 et un mutateur personnalisé my_mutator obtiendra 1/10. Si vous voulez désactiver un certain mutateur, le poids doit être attribué à 0 (par exemple mutator_weights=afl:0,radamsa:1,my_mutator:9).
deterministic_seed = False|True. En fournissant True, les mutations Radamsa deviendront déterministes, ainsi chaque exécution de Manul produira les mêmes sorties.
print_per_thread = False|True. En activant cette option, Manul affichera un résumé pour chaque thread exécuté au lieu d'un résumé total.
disable_volatile_bytes = False|True En activant cette option, Manul ne mettra pas sur liste noire les chemins volatils.
forkserver_on = False|True Activer ou désactiver le forkserver d'AFL.
dbi = dynamorio|pin. Cette option indique à Manul quel framework DBI sera utilisé pour instrumenter la cible.
dbi_root = <chemin>. Cette option indique à Manul où trouver le lanceur principal du framework DBI.
dbi_client_root = <chemin>. Cette option indique à Manul où trouver le client DBI pour effectuer l'instrumentation.
dbi_client_libs = nom_#1,nom_#2|None. Cette option peut être utilisée pour spécifier la liste des bibliothèques qui doivent être instrumentées avec la cible principale (par exemple, vous avez un exécutable qui charge la bibliothèque cible + plusieurs autres où vous voulez rechercher des bogues).
dbi_persistence_mode = 0|1|2. Cette option est utilisée pour choisir entre les modes persistants DBI. 0 - pas de persistance, 1 - persistance standard (encapsulation de fonction), 2 - pas encore pris en charge.
Si dbi-persistence_mode = 1|2, les options suivantes doivent être spécifiées :
dbi_target_module = <nom du module>. Manul essaiera de rechercher la fonction cible dans le module spécifié ici.
dbi_target_method = <nom de la fonction>. Nom de la fonction à encapsuler pour la persistance.
dbi_target_offset = <offset de la fonction, par exemple 0x3198>. Offset de la fonction à encapsuler pour la persistance. Cette option peut être utilisée à la place de dbi_target_method si les symboles de débogage ne sont pas disponibles.
dbi_fuzz_iterations = 500. Le nombre d'itérations de fuzz à exécuter en mémoire avant que le programme entier ne redémarre. Vous pouvez jouer avec cet argument pour trouver la valeur qui fonctionne le mieux avec votre cible.
dbi_thread_coverage = False. Instrumenter la couverture uniquement à partir d'un thread qui a exécuté la fonction cible (pas encore pris en charge).
timeout = 10. Temps d'attente avant de tuer la cible et d'envoyer le prochain cas de test.
init_wait = 1. Cette option peut être utilisée pour définir un délai d'attente nécessaire à l'initialisation de la cible.
Les options net_config_master et net_config_slave sont utilisées pour distribuer des instances Manul sur le réseau. Vous devez effectuer les 3 étapes suivantes pour exécuter du fuzzing distribué.
IP:port où vos esclaves seront exécutés.net_config_slave = 0.0.0.0:1337. Manul lancera l'instance et attendra une connexion entrante de l'instance maître sur le port 1337.net_config_master = file_name.debug = False|True - afficher les informations de débogage.
logging_enable = False|True - enregistrer les informations de débogage dans le journal.
manul_logo = False|True - afficher le logo Manul au début.
no_stats = False|True - enregistrer les statistiques.
sync_freq = 10000. Permet à l'utilisateur de modifier la fréquence de synchronisation du bitmap de couverture. Cette option indique à Manul à quelle fréquence il doit synchroniser la couverture entre les instances de fuzzing parallèles. Une valeur plus faible diminue les performances mais augmente la coordination entre les instances.
#custom_path = test_path - cette option permet d'enregistrer le cas de test dans un dossier personnalisé (si la cible veut le charger depuis un endroit prédéfini).
cmd_fuzzing = True|False. Si cette option est activée, Manul fournira l'entrée dans la cible via la ligne de commande au lieu de l'enregistrer dans le fichier.
user_signals = 6,2,1|None. L'utilisateur peut indiquer à Manul quels signaux de la cible doivent être ignorés (non considérés comme un crash).
target_ip_port = 127.0.0.1:7715|None - utilisé pour spécifier l'IP et le PORT cibles.
target_protocol = tcp|tcp - utilisé pour spécifier le protocole pour envoyer l'entrée dans la cible sur le réseau.
net_sleep_between_cases = 0.0. Cette option peut être utilisée pour définir un délai entre les envois de cas de test dans la cible.
Actuellement, le fuzzing réseau est une fonctionnalité expérimentale (voir les issues pour plus de détails).
Un mutateur personnalisé peut être ajouté en suivant les trois étapes suivantes : Étape 1. Créez un fichier python (.py) et donnez-lui un nom (par exemple example_mutator.py)
Étape 2. Créez deux fonctions def init(fuzzer_id) et def mutate(data). Voir example_mutator pour plus de détails. Manul appellera la fonction init lors de l'initialisation du fuzzing et mutate pour chaque fichier fourni dans la cible.
Étape 3. Activez le mutateur en spécifiant son nom à l'aide de mutator_weights dans manul.config. Par exemple mutator_weights=afl:2,radamsa:0,example_mutator:8.
NOTE : Les mutateurs AFL et Radamsa doivent toujours être spécifiés. Si vous voulez désactiver AFL et/ou Radamsa, attribuez-leur simplement un poids de 0.
TBD
