Ten wpis jest częścią cyklu “Od zera do bughuntera” – listę wszystkich postów znajdziesz tutaj.
Mozilla rzadko (albo prawie wcale!) nie chwali się swoim działem bezpieczeństwa, w mojej opinii bardzo niesłusznie. GitHubowe repozytoria zespołu MozillaSecurity są bardzo często uaktualniane i można znaleźć w nich złoto – w tym wpisie o jednym z ciekawszych narzędzi o niepozornej nazwie FuzzManager. Swego czasu napisałem (mówiłem o nim na Confidence 2018) do własnego wykorzystania podobne narzędzie, lecz gdybym wiedział o istnieniu tego projektu to oszczędziłbym masę czasu i od razu cieszyłbym się z integracji z mechanizmami badania pokrycia kodu. W tym wpisie przeprowadzę Ciebie drogi Czytelniku przez proces prostej integracji z najpopularniejszymi fuzzerami, czyli AFL oraz Honggfuzz.
Pierwsze kroki w “łapaniu” crashy i ich monitoring
Proces instalacji projektu i początkowej konfiguracji pominę, gdyż jest dobrze udokumentowany w repozytorium. Kompilacja fuzzowanego projektu z dowolonym z rodziny Saintizerów (Address, Memory…) znacząco ułatwi pracę, lecz również przygotujemy się na wykorzystanie Valgrinda w mniej dogodnych konfiguracjach. Punktem wyjścia będzie wrapper w Pythonie, wykorzystujący klasę Collector. Bogatowano komentowany kod jest przystosowany pod obydwa projekty fuzzerów (wystarczy podać odpowiednie ścieżki do folderów):
import subprocess import os import hashlib import time from Collector.Collector import Collector from FTB.ProgramConfiguration import ProgramConfiguration from FTB.Signatures.CrashInfo import CrashInfo # sciezka i parametry fuzzowanej binarki (zakladam, ze ostatni element to sciezka do inputu - w innym razie wymagana jest modyfikacja listy) bin_cmd = [] # sciezka do folderu zawierajacego crashe crash_path = '' # generacja konfiguracji binarki dla FuzzManagera - pierwszy element listy bin_cmd bin_configuration = ProgramConfiguration.fromBinary(bin_cmd[0]) crash_hashes = set() # funkcja pomocnicza do pobierania pelnych sciezek do plikow w folderze def listdir_fullpath(directory): return [os.path.join(directory, f) for f in os.listdir(directory)] # odpalenie binarki i sprawdzenie pod katem *Sanitizera def run_with_sanitizer(cmd, f): p = subprocess.Popen([cmd + f], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = p.stdout.read() san_report = p.stderr.read() return CrashInfo.fromRawCrashData(stdout, san_report, bin_configuration) # odpalenie binarki i sprawdzenie raportowania Valgrinda (domyslne) def run_with_valgrind(cmd, f): p = subprocess.Popen(['valgrind' + cmd + f], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = p.stdout.read() valgrind_report = p.stderr.read() if 'Using Valgrind' in valgrind_report and 'ASan cannot proceed correctly' not in valgrind_report: # obiekt zawierajacy kontekst awarii (sparsowany raport Valgrinda) return CrashInfo.fromRawCrashData(stdout, valgrind_report, bin_configuration) # wykrywanie ASANa elif 'ASan cannot proceed correctly' in valgrind_report: return run_with_sanitizer(cmd, f) # upload kontekstu na serwer zdefiniowany w konfiguracji def submit_crash(crash_context): collector = Collector() collector.submit(crash_context) if __name__ == '__main__': while True: crashes = listdir_fullpath(crash_path) for c in crashes: # liczenie SHA1 aby nie wysylac zduplikowanych plikow na serwer c_hash = hashlib.sha1(open(c).read()).hexdigest() if c_hash not in crash_hashes: ctx = run_with_valgrind(bin_cmd, c) crash_hashes.add(c_hash) if ctx: submit_crash(ctx) time.sleep(60)
Wynik działania skryptu (błąd aktualnie w trakcie łatania – stacktrace został zamazany):
Podsumowanie
Post intencjonalnie nie jest długi, aby nie zamęczać technicznymi detalami i ma na celu “kopniaka przyśpieszającego” do tworzenia własnych narzędzi w oparciu o FuzzManagera. Następna część traktować będzie o implementacji mechanizmu “crash bucketów”, czyli łączenia podobnych przypadków testowych na podstawie wzorców stacktrace’ów i badania pokrycia kodu w formie graficznej – tymczasem zachęcam Ciebie czytelniku do poprawy lub stworzenia nowego kodu rozwiązującego problemy z fuzzingiem w trochę większej skali 🙂
One thought on “FuzzManager jako wybawienie dla pogubionych wśród swoich serwerów #1”
Comments are closed.