Umarł AFL, niech zyje AFL! Czyli 10 faktów o afl++

Ten wpis jest częścią cyklu “Od zera do bughuntera” – listę wszystkich postów znajdziesz tutaj.

Niestety, od listopada 2017, legendarny już, fuzzer autorstwa lcamtufa – AFL nie jest rozwijany. Co prawda Google uchroniło projekt przed zapomnieniem, wrzucając go na GitHuba, lecz widoki na wsparcie projektu przez autora / Google, są mizerne. Na szczęście w otwartym kodzie i społeczności tkwi siła, więc dzisiaj opiszę dziesięć różnic pomiędzy “zwykłym” AFL a AFL++, czyli forku projektu, z sukcesem kontynuującego najlepsze tradycje pierwowzoru.

#1 afl++ “zjadł” kilka projektów bazujących na klasycznym afl

Nazwa forka zobowiązuje: dwa plusy można odczytać jako ficzery dostarczane pierwotnie za pomocą projektów AFLfast i afl-unicorn. W dużym skrócie, pierwszy dostarcza efektywniejszy wybór ścieżek w kodzie oparty o metody statystyczne. Drugi umożliwia fuzzowanie wszystkiego – spektakularnym przykładem jest fuzzing odbiornika fal radiowych.

#2 Nowy projekt ma całkiem zmieniony sposób instrumentacji kodu

Pierwowzór przecierał szlaki dla coverage-guided fuzzingu, lecz od tamtego czasu powstały dużo efektywniejsze sposoby instrumentacji kodu specjalizowane pod kątem testów automatycznych. afl++ implementuje InsTrim, czyli opracowaną przez Tajwańczyków lekką instrumentację kodu.

#3 Fuzzing blackbox’owych binarek napędzany jest przez nowe QEMU

Binarki bez instrumentacji dodawanej przez kompilator, moim zdaniem, przez większość czasu rozwoju AFL był traktowany jako mocno eksperymentalny ficzer – stosunek błędów znalezionych przy jego pomocy był promilem błędów odkrytych w sposób preferowany przez projekt. afl++ korzysta z funkcjonalności nowych wersji QEMU oraz wprowadza odczuwalne poprawki wydajnościowe w postaci włączenia prostego cache’u (około 3x).

#4 “Mieszanie” przypadków testowych jest realizowane za pomocą nowego mutatora

Do mieszania w pierwowzorze nie ma się jak przyczepić – jego praca pozwoliła znaleźć masę błędów 🙂 Porównując AFL z honggfuzz wyraźnie widać różnice, jak algorytmy mutatora dochodzą do różnych błędów. Zmiana silnika na MOpt-AFL znacząco wpłynęła na skuteczność bughuntingu.

#5 afl-tmin w końcu działa szybciej 😉

Niech pierwszy rzuci kamieniem ten, kto nigdy nie wyłączył afl-tmin w trakcie minimalizacji dużego crasha – rzadko się zdarza, aby wszystko przebiegło akceptowalnie szybko. “Pożyczony” kod z projektu TriforceAFL dodaje obsługę forkservera, co znacząco wpływa na czas minimalizacji przypadków testowych.

#6 Terminal 79×24 jest wystarczający dla status screena

Mała rzecz, a cieszy 🙂

#7 Zupełnie zmienione podejście do minimalizacji korpusu

Domyślna implementacja afl-cmin jest pomysłowa, lecz niestety technicznie lekko przeterminowana. Zawsze używałem i polecam narzędzie afl-pcmin, czyli funkcjonalnie to samo, tylko wielowątkowo. afl++ podchodzi do problemu minimalizacji w inny sposób: mniejszy zbiór przypadków testowych nad mniejsze przypadki testowe.

#8 Ulepszona obsługa plików tymczasowych generowanych przez fuzzer

W afl++ otrzymujemy możliwość wyboru dowolnej lokalizacji pliku .cur_input zawierającego aktualnie testowany plik. Ma to odczuwalny wpływ na wydajność w przypadku lokalizacji pliku na ramdysku.

#9 Wersje LLVM wyższe od 4.0 nie sprawiają już problemów podczas kompilacji

Na czas pisania posta, aktualną wersją LLVM jest 8.0.1. Wersje te dzieli dokładnie 758 dni – sporo jak na standardy branżowe. Niestety wersje późniejsze generowały błąd kompilacji, który uniemożliwiał wykorzystanie nowszego kodu i w konsekwencji brak “dobroci” trybu LLVM.

#10 afl++ rozbija warunki w kodzie na postać przyjaźniejszą dla fuzzera

Ostatni i jednocześnie bardzo ważna funkcjonalność, bezpośrednio przekładająca się na efektywniejsze odkrywanie kolejnych elementów kodu. Projekt laf-intel wymusza pominięcie optymalizacji podczas kompilacji za pomocą LLVM – powoduje to “uproszczenie” dla fuzzera podczas odkrywania nowych przypadków testowych, gdyż kod nie wykorzystuje “sztuczek” i nietypowych instrukcji.

Brzmi nieźle, na prawdę niewiele zostało ze starego, dobrego afl! Daj znać w komentarzu co sądzisz o afl++ lub jakie masz z nim problemy – chętnie pomogę! 🙂