Ten wpis jest częścią cyklu “Od zera do bughuntera” – listę wszystkich postów znajdziesz tutaj.
Słowo wstępu
Nie będę ukrywał, że honggfuzz był długo przeze mnie ignorowany – AFL działał dobrze, a tam gdzie nie domagał, korzystałem z LibFuzzera (tutaj część pierwsza i druga jego fast tracka). Nawet nie pomagały błędy, które za jego pomocą zostały odkryte – na przykład jedyny do tej pory krytyczny błąd w OpenSSL. Dopiero zachęcony przez Kamila Rytarowskiego, który w ramach GSOC 18 integrował różnej maści fuzzery z NetBSD, postanowiłem dać mu szansę.
Efekt? Po niecałych 20 godzinach fuzzingu radare2, honggfuzz znalazł 893 awaryjne przypadki testowe (z czego 23 są unikalne). Testy zakończyły się lepszym wynikiem niż się spodziewałem, zwracam honor twórcy narzędzia 🙂
O co chodzi?
Honggfuzz bardzo fajnie integruje ze sobą dwa podejścia do fuzzingu, reprezentowane przez AFL oraz LibFuzzera – możemy pisać własne fuzzery (honggfuzz rozumie funkcje wykorzystywane przez LibFuzzera, a przy okazji nie pożera olbrzymich ilości pamięci RAM), jak również skompilować binarki za pomocą hfuzz-clang i korzystać z programów testowych w projekcie poddawanym badaniu (“styl” AFL).
Moją ulubioną funkcjonalnością, której nie ma żaden z wyżej opisanych fuzzerów jest wykorzystanie technologii Intel Processor Trace oraz Intel Branch Trace Store do maksymalizacji pokrycia kodu podczas fuzzingu. Efekty są bardzo fajne i nie są obarczone upierdliwymi wymaganiami. Wystarczy kompilacja biblioteki libipt oraz posiadanie względnie nowego (po 2013 roku) procesora Intel.
Oczywiście to nie jest koniec “dobrego”, poza tym honggfuzz oferuje:
- Persistent mode (podobny do AFL),
- Możliwość startu bez korpusu początkowego,
- Monitoring sygnałów za pomocą np. ptrace, co pozwala zwiększyć wykrywalność sygnału zakończenia danej iteracji fuzzingu, a przez to skuteczniej wykrywać awarie,
- Podpinanie się do danego procesu – przydatne podczas fuzzingu usług sieciowych.
Jak odpalić i zacząć fuzzing?
Bardzo prosto (Ubuntu 16.04+):
sudo apt-get install libbfd-dev libunwind-dev git clone https://github.com/google/honggfuzz cd honggfuzz make -j4 sudo make install
Kompilacja (w tym ASAN i instrumentacja) na przykładzie radare2:
git clone https://github.com/radare/radare2 cd radare2 CC=hfuzz-clang CXX=hfuzz-clang++ ./configure make -j4 sudo make install
Pozyskanie korpusu testowego (można zacząć z pominięciem tego kroku, lecz nie polecam fuzzować “na pusto”)
git clone https://github.com/radare/radare2-regressions cd radare2-regressions mkdir ~/r2_corpus mv bins/fuzzed/* ~/r2_corpus
Odpalenie fuzzera z maksymalizacją pokrycia za pomocą IPT:
mkdir ~/r2_fuzzing_output honggfuzz --linux_perf_ipt_block -W ~/r2_fuzzing_output -f ~/r2_corpus -- /usr/local/bin/r2 -A ___FILE___
Po odpaleniu naszym oczom zostanie wyświetlony całkiem przyjemny interfejs tekstowy (bardziej czytelny niż w AFL):
------------------------[ 0 days 23 hrs 03 mins 57 secs ]---------------------- Iterations : 19,517 [19.52k] Mode : [2/2] Feedback Driven Mode Target : /usr/local/bin/r2 -A ___FILE___ Threads : 1, CPUs: 1, CPU%: 100% [100%/CPU] Speed : 0/sec [avg: 0] Crashes : 1014 [unique: 23, blacklist: 0, verified: 0] Timeouts : 5,796 [10 sec] Corpus Size : 2,312, max size: 789,488 bytes, init dir: 417 files Cov Update : 0 days 00 hrs 02 mins 55 secs ago Coverage : edge: 64,269 pc: 1,570 cmp: 987,526 ---------------------------------- [ LOGS ] ------------------/ honggfuzz 1.6 /- 2018-08-11T20:52:29+0200][W][28659] subproc_checkTimeLimit():425 PID 52926 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:52:40+0200][W][28659] subproc_checkTimeLimit():425 PID 52928 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:52:50+0200][W][28659] subproc_checkTimeLimit():425 PID 52929 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:53:00+0200][W][28659] subproc_checkTimeLimit():425 PID 52930 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:53:10+0200][W][28659] subproc_checkTimeLimit():425 PID 52943 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:53:20+0200][W][28659] subproc_checkTimeLimit():425 PID 52944 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:53:30+0200][W][28659] subproc_checkTimeLimit():425 PID 52945 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:53:52+0200][W][28659] subproc_checkTimeLimit():425 PID 52952 took too much time (limit 10 s). Killing it with SIGKILL [2018-08-11T20:54:03+0200][W][28659] subproc_checkTimeLimit():425 PID 52955 took too much time (limit 10 s). Killing it with SIGKILL
Maksymalizacja efektów fuzzingu
Krótkie przypomnienie jak uczynić proces jeszcze bardziej efektywnym:
- Korpus testowy złożony z niewielkich plików (idealnie poniżej 1 kilobajta), które są różne funkcjonalnie,
- Wykorzystanie Persistent Mode,
- Budowa i użycie słowników (te z AFL również są obsługiwane przez honggfuzz),
- Wspomaganie powiększania pokrycia kodu za pomocą IPT / BTS,
- Oczywiście fuzzing tylko z ASAN / MSAN / UBSAN.
Podsumowanie
Jeżeli, drogi Czytelniku, zintegrowałeś swój projekt z LibFuzzerem to nic nie stoi na przeszkodzie aby wykorzystać go w połączeniu z honggfuzz – wystarczy jedynie zmienić kompilator podczas procesu budowania. A jeżeli nie, to wszystko przed Tobą – osobiście uważam, że ten fuzzer jako narzędzie w procesie usuwania błędów dodaje olbrzymią wartość i jest mi wstyd, że tak późno go odkryłem 😉
One thought on “Honggfuzz – Fast Track”
Comments are closed.