Honggfuzz – Fast Track

Słowo wstępu

Nie będę ukrywał, że honggfuzz był długo przeze mnie ignorowanyAFL 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 😉

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.