
Fuzzing haute performance utilisant des traductions binaires riscv vers x86 et des techniques de fuzzing modernes
Date de début : déc. 2021
Il s'agit d'un fuzzer greybox basé sur l'émulation et guidé par la couverture, qui exploite un compilateur Just-In-Time personnalisé pour atteindre des performances proches du natif. Il fonctionne en convertissant les binaires ELF RISC-V en une représentation intermédiaire avant de les compiler en JIT vers x86 pendant l'exécution. Lors de la compilation JIT, le code est instrumenté pour permettre des améliorations pour le fuzzing telles que le suivi de couverture, asan, cmpcov, ou le fuzzing basé sur des snapshots.

L'objectif de ce projet est de mettre en évidence les avantages de l'utilisation d'un environnement émulé pour le fuzzing. De nombreux fuzzers basés sur l'émulation existent déjà, mais ils utilisent presque tous exclusivement le moteur d'émulation qemu pour l'émulation sous-jacente. Bien que ce moteur dispose d'un compilateur juste-à-temps assez mature et génère de très bons codes, il n'est pas conçu pour le fuzzing. Pendant le fuzzing, nous avons l'intention d'exécuter le même processus des milliers de fois par seconde. Cela laisse place à des optimisations spécialisées que qemu n'exploite pas pleinement, comme la réutilisation du même espace mémoire pour chaque exécution du processus et la réinitialisation d'une quantité limitée de mémoire via les mécanismes de bits sales (dirty bits).
À bien des égards, il s'agit davantage d'une preuve de concept sur laquelle je voulais travailler pour apprendre les rouages des compilateurs et disposer d'un terrain de jeu basé sur l'émulation pour expérimenter diverses techniques de fuzzing telles que différentes métriques de couverture, des ordonnanceurs de seeds et le fuzzing basé sur des snapshots. Avec davantage d'optimisations JIT et, surtout, des extensions pour inclure des architectures plus populaires comme mips ou arm, cet outil pourrait cependant certainement être utilisé pour fuzzer efficacement du code closed source qui ne peut pas simplement être instrumenté par recompilation.
Compte tenu des tests que j'ai effectués jusqu'à présent, sfuzz a beaucoup moins de surcoût (overhead) que beaucoup d'autres fuzzers populaires, ce qui se traduit par des performances très rapides, en particulier pour de petits cas de fuzzing.
Plus de détails sur les fonctionnalités/choix effectués pour ce fuzzer sont listés dans le billet de blog associé (https://seal9055.com/blog/fuzzing/sfuzz) et dans les fichiers de documentation listés ci-dessous :
Ce fuzzer est entièrement écrit en rust, donc après avoir cloné le dépôt, exécutez simplement cargo build --release pour compiler.
Étant donné que le fuzzer ne supporte actuellement que RISC-V, la cible doit être compilée pour RISC-V en utilisant la chaîne d'outils ci-dessous (ou une similaire). Vous pouvez également utiliser un binaire RISC-V déjà existant, cela fonctionnera très bien.
Une fois cela configuré, créez simplement des répertoires d'entrée/sortie, ajoutez quelques fichiers seed initiaux dans le répertoire d'entrée et lancez le fuzzer.
./sfuzz -i in -o out -- ./test_cases/simple_test @@
Des options supplémentaires peuvent être passées via les arguments de ligne de commande pour spécifier le nombre de threads, activer le fuzzing par snapshots, ajouter un dictionnaire au mutateur, etc. La liste des options supplémentaires peut être affichée en exécutant sfuzz avec l'option -h.
Si vous souhaitez tester le fuzzer sur des cibles de complexité variable, le progrem_generator situé dans tools/program_generator peut être utilisé pour générer automatiquement des programmes de complexité variable. Notez que vous aurez besoin d'une chaîne d'outils RISC-V pour compiler la cible.
Ceci configure une chaîne d'outils pour compiler des binaires riscv qui peuvent être chargés/utilisés par ce projet.
Riscv compiler/tooling:
sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev \
libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev \
libexpat-dev
git clone https://github.com/riscv/riscv-gnu-toolchain && cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv --with-arch=rv64i
sudo make
Debugger:
gdb-multiarch
Cette liste représente un ensemble de fonctionnalités que je prévois d'implémenter à l'avenir.