Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente |
prog:fuzzer:afl [2020/05/11 00:11] – Suppression de la taille par défaut pour les images root | prog:fuzzer:afl [2023/10/06 09:55] (Version actuelle) – [Sanitizers] : mise à jour avec afl++ root |
---|
[[http://lcamtuf.coredump.cx/afl/|Américan Fuzzy Lop]] cherche à vérifier l'intégrité d'un logiciel ou d'une librairie dans le cas d'ouverture de fichiers. | [[https://aflplus.plus/|AFL++]] cherche à vérifier l'intégrité d'un logiciel ou d'une librairie dans le cas d'ouverture de fichiers. |
| |
Dans les cas ci-dessous, le dossier ''testcases'' contient les cas de base qui seront altérés et le dossier ''findings'' contient les cas altérés ayant eux un chemin unique dans le programme. | Il est le successeur de [[https://lcamtuf.coredump.cx/afl/|AFL]] qui a été abandonné. |
| |
=====Compilation à l'application===== | =====Compilation de AFL++===== |
| |
| La compilation nécessite Python et donc l'utilisation d'un environnement virtuel. |
| |
| <code bash> |
| cd AFLplusplus |
| python3 -m venv .venv |
| source .venv/bin/activate |
| pip install wheel |
| make distrib |
| </code> |
| |
| [[https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/INSTALL.md|INSTALL.md]] {{ :prog:fuzzer:afl:aflplusplus_docs_install.md_at_stable_aflplusplus_aflplusplus_05_10_2023_11_29_47_.html |Archive du 19/09/2023 le 05/10/2023}} |
| =====Programme à tester===== |
====Cas général==== | ====Cas général==== |
| |
| ===Configurer la compilation=== |
| |
<code bash> | <code bash> |
cd program | cd program |
</code> | </code> |
| |
puis compiler au choix en fonction du programme : | puis compiler au choix en fonction du programme : |
| |
| * configure |
| |
<code bash> | <code bash> |
CC=afl-gcc CXX=afl-g++ ./configure | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as ./configure |
CC=afl-gcc CXX=afl-g++ cmake . | |
</code> | </code> |
et finissez par | |
| * cmake |
| |
| <code bash> |
| mkdir build |
| cd build |
| CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as cmake .. |
| </code> |
| |
| ===Compiler=== |
| |
| <code bash> |
| make -j 8 |
| </code> |
| |
| ===Lancer le fuzzing=== |
| |
| Il faut mettre une liste de fichiers de base dans le dossier ''testcases''. |
| |
| Dans le dossier ''findings'' seront listés tous les cas altérés ayant eux un chemin unique dans le programme. |
<code bash> | <code bash> |
make | |
mkdir findings testcases | mkdir findings testcases |
afl-fuzz -i testcases -o findings -- program/bin/executable @@ | afl-fuzz -i testcases -o findings -- program/bin/executable @@ |
</code> | </code> |
| |
Ici, le double arobase ''@@'' représente le fichier altéré généré par AFL. | Ici, le double arobase ''@@'' représente le fichier altéré généré par AFL. |
| |
| |
| <WRAP center round alert 60%> |
| Toutes les informations après ce tag concerne l'ancienne version de afl. |
| </WRAP> |
| |
====Sanitizers==== | ====Sanitizers==== |
| |
| |
L'usage de variables d'environnement ''AFL_USE_ASAN'' / ''AFL_USE_MSAN'' / ''AFL_HARDEN'' ne donnent pas le même résultat que ''-fsanitizer''. L'usage des variables d'environnement est préférable. | * ''AFL_USE_ASAN'' : ''-U_FORTIFY_SOURCE -fsanitize=address''. Incompatible avec ''AFL_USE_MSAN'' et ''AFL_HARDEN''. |
| * ''AFL_USE_MSAN'' : ''-U_FORTIFY_SOURCE -fsanitize=memory''. Incompatible avec ''AFL_USE_ASAN'' et ''AFL_HARDEN''. |
* ''AFL_USE_ASAN'' : ''-U_FORTIFY_SOURCE -fsanitize=address'' | |
* ''AFL_USE_MSAN'' : ''-U_FORTIFY_SOURCE -fsanitize=memory'' | |
* ''AFL_HARDEN'' : ''-fstack-protector-all -D_FORTIFY_SOURCE=2'' | * ''AFL_HARDEN'' : ''-fstack-protector-all -D_FORTIFY_SOURCE=2'' |
| * ''AFL_USE_UBSAN'' : ''-fsanitize=undefined -fsanitize-undefined-trap-on-error -fno-sanitize-recover=all -fno-omit-frame-pointer'' |
| * ''AFL_USE_TSAN'' : ''-fsanitize=thread -fno-omit-frame-pointer'' |
| * ''AFL_USE_LSAN'' : ''-fsanitize=leak'' |
| * ''AFL_USE_CFISAN'' : ''-fcf-protection=full'' pour gcc, ''-fsanitize=cfi -fvisibility=hidden'' pour clang |
| |
Comme on est dans un environnement multithread, on compile une version de programme pour chaque sanitizer qui serviront lors du fuzzing (voir ci-après). | Comme on est dans un environnement multithread, on compile une version de programme pour chaque sanitizer qui serviront lors du fuzzing (voir ci-après). |
| |
<code bash> | <code bash> |
CC=afl-gcc CXX=afl-g++ AFL_USE_ASAN=1 AFL_INST_RATIO=100 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" ./configure | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_USE_ASAN=1 AFL_INST_RATIO=100 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
CC=afl-clang CXX=afl-clang++ AFL_USE_MSAN=1 AFL_INST_RATIO=100 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" LDFLAGS="-lgcc_s" ./configure | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_USE_MSAN=1 AFL_INST_RATIO=100 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
CC=afl-gcc CXX=afl-g++ AFL_HARDEN=1 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" ./configure | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_HARDEN=1 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
CC=afl-gcc CXX=afl-g++ CFLAGS="-fsanitize=undefined -U_FORTIFY_SOURCE -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -U_FORTIFY_SOURCE -g -fno-omit-frame-pointer" LDFLAGS="-lgcc_s" ./configure | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_USE_UBSAN=1 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
CC=afl-clang CXX=afl-clang++ CFLAGS="-fsanitize=cfi -U_FORTIFY_SOURCE -flto -fvisibility=hidden -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=cfi -U_FORTIFY_SOURCE -flto -fvisibility=hidden -g -fno-omit-frame-pointer" LDFLAGS="-lgcc_s" ./configure | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_USE_TSAN=1 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
| CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_USE_LSAN=1 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
CC=afl-gcc CXX=afl-g++ AFL_USE_ASAN=1 AFL_INST_RATIO=100 cmake . | CC=afl-clang-lto CXX=afl-clang-lto++ RANLIB=llvm-ranlib AR=llvm-ar AS=llvm-as AFL_USE_CFISAN=1 CFLAGS="-g -fno-omit-frame-pointer" CXXFLAGS="-g -fno-omit-frame-pointer" cmake .. |
CC=afl-clang CXX=afl-clang++ AFL_USE_MSAN=1 AFL_INST_RATIO=100 cmake . | |
CC=afl-gcc CXX=afl-g++ AFL_HARDEN=1 cmake . | |
CC=afl-gcc CXX=afl-g++ cmake -DCMAKE_C_FLAGS="-fsanitize=undefined -U_FORTIFY_SOURCE" -DCMAKE_CXX_FLAGS="-fsanitize=undefined -U_FORTIFY_SOURCE" . | |
CC=afl-clang CXX=afl-clang++ cmake -DCMAKE_C_FLAGS="-fsanitize=cfi -U_FORTIFY_SOURCE -flto -fvisibility=hidden" -DCMAKE_CXX_FLAGS="-fsanitize=undefined -U_FORTIFY_SOURCE -flto -fvisibility=hidden" . | |
| |
AFL_USE_ASAN=1 AFL_INST_RATIO=100 afl-g++ -g -fno-omit-frame-pointer -O2 main.cc -o main_asan | |
LDFLAGS="-lgcc_s" AFL_USE_MSAN=1 AFL_INST_RATIO=100 afl-clang++ -g -fno-omit-frame-pointer -O2 main.cc -o main_msan | |
AFL_HARDEN=1 afl-g++ -g -fno-omit-frame-pointer -O2 main.cc -o main_harden | |
afl-g++ -fsanitize=undefined -U_FORTIFY_SOURCE -g -fno-omit-frame-pointer -O2 -lgcc_s main.cc -o main_undefined | |
afl-clang++ -fsanitize=cfi -U_FORTIFY_SOURCE -flto -fvisibility=hidden -g -fno-omit-frame-pointer -O2 -lgcc_s main.cc -o main_cli | |
</code> | </code> |
| |
<WRAP center round important 60%> | Si ''AFL_USE_ASAN'' ou ''AFL_USE_MSAN'' est utilisé, automatiquement, afl ne surveille de 33% (aléatoirement) des branches. Il faut mettre ''AFL_INST_RATIO'' à 100 pour surveiller toutes les branches. |
Si ''AFL_USE_ASAN'' ou ''AFL_USE_MSAN'' est utilisé, automatiquement, afl ne surveille de 33% (aléatoirement) des branches que ''AFL_INST_RATIO'' ne peut pas surcharger. | |
</WRAP> | |
| |
Pour que ''AFL_INST_RATIO'' ne soit pas divisé par 3, il faut appliquer le patch : | |
<file diff afl-as-AFL_INST_RATIO.patch> | |
--- afl-2.52b/afl-as.c.old 2018-02-11 22:05:48.636563804 +0100 | |
+++ afl-2.52b/afl-as.c 2018-02-11 22:07:04.035919083 +0100 | |
@@ -525,7 +525,8 @@ int main(int argc, char** argv) { | |
| |
if (getenv("AFL_USE_ASAN") || getenv("AFL_USE_MSAN")) { | |
sanitizer = 1; | |
- inst_ratio /= 3; | |
+ if (!getenv("AFL_INST_RATIO")) | |
+ inst_ratio /= 3; | |
} | |
| |
if (!just_version) add_instrumentation(); | |
</file> | |
| |
''AFL_USE_ASAN'' et ''AFL_USE_MSAN'', : nécessite ''-m none''. | |
| |
Dans ces cas, 20 To est nécessaire. Mais cette taille n'est pas l'espace mémoire utile en RAM qui sera nécessaire mais seulement la mémoire virtuelle : | |
| |
PID UTIL. PR NI VIRT RES SHR S %CPU %MEM TEMPS+ COM. | |
14810 legarrec 20 0 20,000t 5916 3392 R 19,5 0,0 0:01.89 main | |
| |
<WRAP center round important 60%> | |
Une chute de performance est à prévoir. | |
</WRAP> | |
| |
Les valeurs ci-dessous sont basées sur l'utilisation du logiciel ''pdftohtml'' de ''poppler''. | |
^ Sanitizer ^ Performance ^ Chute ^ | |
| - | 100% |Vitesse maximale| | |
|address | 40% |Division par 2,5| | |
|undefined | 20% |Division par 5 | | |
|address,undefined| 8% |Division par 12 | | |
| |
Je conseille donc de lancer une version ''AFL_USE_ASAN'', ''AFL_USE_MSAN'', ''AFL_HARDEN'', ''-fsanitizer=undefined'' et ''-fsanitizer=undefined'' (soit 5 au total) et toutes les autres instances en parallèle sans ces optimisations. | Une chute de performance est à prévoir. Je conseille donc de lancer une exécution de afl-fuzz en mode esclave de chaque sanitizer et toutes les autres instances en parallèle sans ces vérifications. |
| |
====Dictionnaire==== | ====Dictionnaire==== |
===Hack du préprocesseur=== | ===Hack du préprocesseur=== |
La solution, modifier le préprocesseur pour surcharger ces fonctions : | La solution, modifier le préprocesseur pour surcharger ces fonctions : |
[[https://stackoverflow.com/questions/3545875/custom-gcc-preprocessor|Source]] {{ :prog:fuzzer:afl:custom_gcc_preprocessor_-_stack_overflow_2020-04-27_10_50_12_am_.html |Archive du 23/08/2010 le 27/04/2020}} | [[https://stackoverflow.com/questions/3545875/custom-gcc-preprocessor|Custom gcc preprocessor]] {{ :prog:fuzzer:afl:custom_gcc_preprocessor_-_stack_overflow_2020-04-27_10_50_12_am_.html |Archive du 23/08/2010 le 27/04/2020}} |
| |
Ci-dessous pour la version 7.3.0 de gcc. | Ci-dessous pour la version 7.3.0 de gcc. |
===Conclusion=== | ===Conclusion=== |
Mais l'exécution de la commande de fuzzing ne trouve qu'un seul chemin car l'exécutable n'est pas instrumenté. | Mais l'exécution de la commande de fuzzing ne trouve qu'un seul chemin car l'exécutable n'est pas instrumenté. |
afl-fuzz -t 500 -i testcases -o findings -- /home/legarrec/info/programmation/tmp/wine-afl/build/loader/wine main.exe @@ | afl-fuzz -t 500 -i testcases -o findings -- .../wine-afl/build/loader/wine main.exe @@ |
| |
et malgré le plantage avec succès de wine, il n'y a pas d'information de debug. | et malgré le plantage avec succès de wine, il n'y a pas d'information de debug. |
cd findings | cd findings |
# version hardcore | # version hardcore |
find . -name "id:*" | LD_LIBRARY_PATH="/home/legarrec/info/programmation/tmp/afl-popple/poppler-0.53.0/poppler/.libs:$LD_LIBRARY_PATH" parallel "valgrind --trace-children=yes --track-fds=yes --num-callers=500 --error-limit=no --show-below-main=yes --max-stackframe=2000000 --smc-check=all --read-var-info=yes -v --leak-check=full --show-possibly-lost=yes --leak-resolution=high --show-reachable=yes --undef-value-errors=yes --track-origins=yes ../poppler-0.53.0/utils/.libs/pdftohtml {} /tmp/ &> {}.log" | find . -name "id:*" | LD_LIBRARY_PATH=".../afl-popple/poppler-0.53.0/poppler/.libs:$LD_LIBRARY_PATH" parallel "valgrind --trace-children=yes --track-fds=yes --num-callers=500 --error-limit=no --show-below-main=yes --max-stackframe=2000000 --smc-check=all --read-var-info=yes -v --leak-check=full --show-possibly-lost=yes --leak-resolution=high --show-reachable=yes --undef-value-errors=yes --track-origins=yes ../poppler-0.53.0/utils/.libs/pdftohtml {} /tmp/ &> {}.log" |
# version plus rapide sans read-var-info, track-origins surtout : | # version plus rapide sans read-var-info, track-origins surtout : |
find . -name "id:*" | LD_LIBRARY_PATH="/home/legarrec/info/programmation/tmp/afl-popple/poppler-0.53.0/poppler/.libs:$LD_LIBRARY_PATH" parallel "valgrind -v --leak-check=full --show-leak-kinds=all ../poppler-0.53.0/utils/.libs/pdftohtml {} /tmp/ &> {}.log" | find . -name "id:*" | LD_LIBRARY_PATH=".../afl-popple/poppler-0.53.0/poppler/.libs:$LD_LIBRARY_PATH" parallel "valgrind -v --leak-check=full --show-leak-kinds=all ../poppler-0.53.0/utils/.libs/pdftohtml {} /tmp/ &> {}.log" |
</code> | </code> |
| |
mkdir build | mkdir build |
cd build | cd build |
CC=afl-gcc CXX=afl-g++ cmake DCMAKE_C_FLAGS="-no-integrated-cpp -g -fno-omit-frame-pointer" DCMAKE_CXX_FLAGS="-no-integrated-cpp -g -fno-omit-frame-pointer" .. | CC=afl-gcc CXX=afl-g++ CFLAGS="-no-integrated-cpp -g -fno-omit-frame-pointer" CXXFLAGS="-no-integrated-cpp -g -fno-omit-frame-pointer" cmake .. |
</code> | </code> |
| |
<code bash> | <code bash> |
# Add our own library path to LD_LIBRARY_PATH | # Add our own library path to LD_LIBRARY_PATH |
LD_LIBRARY_PATH="/home/legarrec/info/programmation/tmp/afl-2lgc/poppler-0.53.0/poppler/.libs:$LD_LIBRARY_PATH" | LD_LIBRARY_PATH=".../afl-2lgc/poppler-0.53.0/poppler/.libs:$LD_LIBRARY_PATH" |
</code> | </code> |
| |
<code> | <code> |
Groupe 0 | Groupe 0 |
/home/legarrec/info/programmation/retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000063_06.btfull | .../retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000063_06.btfull |
Groupe 1 | Groupe 1 |
/home/legarrec/info/programmation/retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000419_06.btfull | .../retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000419_06.btfull |
Groupe 2 | Groupe 2 |
/home/legarrec/info/programmation/retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000384_06.btfull | .../retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000384_06.btfull |
Groupe 3 | Groupe 3 |
/home/legarrec/info/programmation/retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000241_06.btfull | .../retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000241_06.btfull |
Groupe 4 | Groupe 4 |
/home/legarrec/info/programmation/retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000356_06.btfull | .../retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000356_06.btfull |
Groupe 5 | Groupe 5 |
/home/legarrec/info/programmation/retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000016_06.btfull | .../retdec/build/src/fileinfo/crash/fuzzer02/crashes/id_000016_06.btfull |
</code> | </code> |
| |