6 typów fuzzerów – który jest dla Ciebie najlepszy?

Kiedyś (okolice 2014 roku) było całkiem prosto. Na “rynku” były fuzzery “mądre” i fuzzery, delikatnie mówiąc, nie grzeszące rozumem. Wybór był oczywisty – chciałeś przetestować swój projekt, wybierałeś AFL i nie czekałeś długo a kolejka błędów rosła i rosła… Teraz za to jest fajniej: rozwiązania specjalizowane pod konkretne zastosowania, tuningowane fuzzery i sprytne sposoby poszukiwania nowych ścieżek. A oto dwanaście punktów, które zwiększą Twoją skuteczność bughuntingu:

1. Dumb fuzzery mają się całkiem dobrze!

Zbyt szybko researcherzy postawili kreskę na klasycznych rozwiązaniach. Po pierwsze, generują ciekawe mutacje i szybko jesrzyteśmy w stanie wygenerować korpus testowy (i to całkiem skomplikowany!). Po drugie, nawet dzisiaj, znajdują błędy, pomijam już fakt “trywialności” wdrożenia.

2. …jednak specjalizacja = wysoka skuteczność (structured fuzzing)

Testując gramatyki (JS, Yara, C/C++) bezsensowne jest “karmienie” parsera, czymś wykraczającym poza zakres danego języka. Czasami jednak ma to szanse zadziałać i znaleźć jakiś błąd, lecz jest to zdecydowanie wyjątek niż reguła. Warto wtedy skorzystać z domato, który pozwala stworzyć własny generator gramatyki, lub zaprząc do roboty gotowca takiego jak csmith, fuzzilli  lub libprotobuf-mutator.

3. Nadajmy kolorytu fuzzingowi, czyli testowanie greybox

Nie tylko badanie pokrycia kodu i feedback z niego, czynią fuzzer “mądrym”. Można zaprogramować, go wcześniej, aby całkowicie pominąć etap nauki i na starcie korzystać ze skuteczniejszego generowania przypadków testowych. Generycznie robi to aflsmart, a bardzo fajny przykład wykorzystania tego mechanizmu pokazał CheckPoint w swoim researchu Windows Deployment Services (CVE-2018-8476).

4. Pokazanie palcem jest też sposobem na buga!

Guided fuzzing może pomóc kiedy wiemy czego chcemy i gdzie to jest. Łącząc Symbolic Execution i “moc” feedbacku z pokrycia kodu, jesteśmy w stanie i dobrym stylu doprowadzić do awarii kodu. Pomocą służą driller oraz aflgo, warto spróbować bo jest to obiecujące podejście.

5. Przerzucanie “roboty” na sprzęt jest (prawie) zawsze właściwym kierunkiem

Honggfuzz, WinAFL (tak!) i szereg innych projektów, korzystają ze sprzętowego wsparcia w zakresie pomiaru pokrycia kodu. Praktycznie wszystkie nowe procesory Intela wspierają te mechanizmy, korzystajmy przerzucając cykle CPU na fuzzing, a nie programowe metody badania code coverage.

6. Deweloperzy <3 UT, prawdopodobnie pokochają też fuzzery!

Słyszałem wiele wymówek od programistów, dlaczego nie korzystają z technik automatycznych testów bezpieczeństwa. Testy jednostkowe zdecydowanie szybciej zdobyły serca deweloperów (chociaż po sieci dalej krąży legendarny mem). DeepState pozwala na wykorzystanie mocy fuzzerów, w ten, nieco niecodzienny dla specjalistów bezpieczeństwa, sposób 😉

Daj znać w komentarzu, jaki jest najskuteczniejszy według Ciebie sposób “automatycznego” atakowania kodu – może pominąłem jakiś ciekawy?

Warsztaty “Od zera do pierwszego 0-daya!”

Moim zawodowym celem jest sprawianie aby szeroko pojęte “cyber” było bezpieczniejszym miejscem – podobnie jak P0 jestem przekonany, że “Make 0-days harder” jest właściwym kierunkiem. Robię to na kilka sposobów, a jednym z nich są szkolenia. Wspólnie z wydawnictwem PWN, organizującym konferencję Security PWNing 2019 połączyliśmy siły, aby zaproponować maksymalnie praktyczne warsztaty w kierunku automatycznego poszukiwania i analizy podatności bezpieczeństwa. Takiego tematu na polskim rynku szkoleń IT Security jeszcze nie było 😀

Jak wyglądają warsztaty i dla kogo są?

Jeżeli chcesz “mieć” swoje CVE to trafiłeś idealnie!

Warsztat jest opracowany z myślą o wprowadzeniu uczestników w arkana najlepszych metod i narzędzi służących do automatycznego wykrywania podatności i analizy błędów w oprogramowaniu w praktyczny sposób.

Na początku skupimy się na zrozumieniu technik: analizy binarnej, wyszukiwania różnych typów podatności oraz debuggowania. “Wgryziemy” się w praktyczny fuzzing i błędy, które spędzają sen z powiek programistom za pomocą swojego niedeterministycznego występowania. Uczestnicy poznają techniki do analizy słabych stron aplikacji, pisania gramatyk oraz pozyskiwania korpusów testowych gwarantujących interesujące wyniki.

Po zrozumieniu aspektów bughuntingu nadejdzie czas na automatyzację analizy podatności i sposoby debuggowania gwarantujące szybkie znalezienie wadliwych elementów kodu.

Szkolenie skupia się na architekturze x86/x64 i atakowaniu parserów (tekstowych, sieciowych, binarnych), fuzzingu sieciowym na platformach Windows i Linux

Najwięcej ze szkolenia wyniosą osoby, które codziennie stykają się z problemami bezpieczeństwa aplikacji, a więc:

  • specjaliści ds. bezpieczeństwa IT i pentesterzy,
  • programiści i testerzy,
  • badacze bezpieczeństwa IT,
  • dostawcy rozwiązań w zakresie bezpieczeństwa IT,
  • pasjonaci bezpieczeństwa teleinformatycznego,

Ponad 50 ćwiczeń technicznych uwzględniających każdy etap procesu bughuntingu w modelach whitebox, blackbox oraz greybox oraz trochę teorii przeplatanej case-study – przede wszystkim praktyka, praktyka, praktyka!

Plan warsztatów, wybrane zagadnienia:

Dzień 1

  • Dlaczego warto szukać podatności bezpieczeństwa?
  • Dlaczego warto to robić za pomocą fuzzerów i metod automatycznych?
  • Najczęściej występujące problemy bezpieczeństwa w oprogramowaniu i mechanizmy mitygacji
    • Klasy podatności
    • Mechanizmy ochrony
  • Workflow poszukiwania podatności
    • 8 praw fuzzingu
  • Fuzzery pod maską i niejedno imię fuzzera
  • Wprowadzenie do fuzzingu na GNU/Linux
    • Jak znaleźć interesujący komponent do ataku?
    • Atakowanie whitebox
      • AFL++
        • Różnice pomiędzy AFL i AFL++
      • Honggfuzz
      • LibFuzzer
      • Fuzzery Go / .NET / Python
      • Pokrycie kodu
    • Atakowanie greybox 
      • AFLSmart
    • Atakowanie blackbox
      • AFL++ + QEMU
      • DynInst
    • Inne
      • Fuzzing z wykorzystaniem preeny
  • Szybkie wprowadzenie do sanitizerów ich możliwości w zakresie detekcji błędów (ASAN, MSAN, UBSAN, TSAN) 
  • Wprowadzenie do fuzzingu na Windows
    • Proces wyszukiwania funkcji do automatycznych testów
    • WinAFL
    • DrFuzz
  • Inne
    • Predykcja ROI za pomocą Pythia – Kiedy fuzzing przestaje się opłacać?
    • Fuzzing sieciowy
    • Fuzzing hybrydowy z Symbolic / Concolic Execution
    • Sztuczna inteligencja w służbie bughuntingu
  • Zarządzanie i tworzenie korpusów testowych
    • Ewolucja i badanie pokrycia kodu
    • Generowanie i ręczne tworzenie inputu z lepszym pokryciem kodu
  • Fuzzing w wielkiej skali
    • ClusterFuzz od Google
    • Fuzz-Driven Development
    • Integracja FuzzManagera z AFL / Honggfuzz / Python
    • Badanie pokrycia kodu na potrzeby FuzzManagera
    • Grupowanie duplikatów za pomocą sygnatur

Dzień 2

  • Pisanie własnego fuzzera opartego o LibFuzzer
    • Analiza metod integracji z OSS-Fuzz
    • Poprawianie osiągów fuzzera
  • Statyczna analiza kodu
    • Mamy 2019 rok, czy dalej warto?
    • cppcheck vs. Clang Static Analyzer
    • Weryfikacja znalezisk za pomocą fuzzera
    • Statyczna analiza jako pierwszy krok do ręcznego przeglądu kodu? 
  • Make vulnerability reporting great again!
    • Analiza błędów
      • Sanitizery (ASAN, MSAN, UBSAN, TSAN)
      • Valgrind
      • DrMemory
    • Co powinien zawierać rzetelny raport o podatności?
    • O co chodzi z CVE?
  • Podstawy selekcji interesujących przypadków błędów
    • Określanie krytyczności awarii
      • exploitability / crashwalk
  • Praca z niedeterministycznymi awariami kodu
    • Debuggowanie za pomocą RR
    • Narzędzia analizy binarnej w GNU\Linux
  • Co dalej?
    • Rode0day

Data, lokalizacja, cena?

Warsztaty odbędą się przed konferencją tj. 12-13.11.19 w Golden Floor Plaza (Warszawa, Aleje Jerozolimskie 123a). Cena wynosi 3499 PLN netto (brutto: 4303.77 PLN).

UWAGA!!! Aby wynieść jak najwięcej wiedzy ze szkolenia ograniczamy liczbę osób, które mogą brać udział w szkoleniu – im szybciej się zapiszesz, tym lepiej 🙂

Pełen opis i formularz zgłoszeniowy znajdziesz na dedykowanej stronie warsztatu – bughunting.pl

14 prezentacji, które warto znać z BlackHat USA 2019 & DEFCON27

Niedawno zakończyły się dwie najważniejsze konferencje z “branży”, chodzi oczywiście o BHUSA oraz DEFCON. Reporterskim obowiązkem przedstawiam poniżej krótki i subiektywny wybór najlepszych sesji dt. bughuntingu i exploitacji (kolejność losowa):

Zachęcam do zapoznania się 🙂

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ę! 🙂

Jak psuć aby zepsuć? Concolic & symbolic execution w służbie fuzzerom

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

W listopadzie miną dwa lata od ostatniej aktualizacji pierwszego fuzzera opartego o badanie pokrycia kodu czyli AFL. W międzyczasie cały ekosystem skupiony wokół projektu rozrósł się do sporych rozmiarów, aczkolwiek rozwiązań dodających metody znacząco poprawiające pokrycie kodu jest niewiele. Takim rozwiązaniem jest QSYM, który umożliwia hybrydowy fuzzing: klasyczne podejście AFL oraz “drążenie” ścieżek w kodzie za pomocą symbolic execution.

WTF! Concolic? Symbolic?

Na początku warto stworzyć pewne “szufladki” ku owocnej pracy z artykułem i jednocześnie wprowadzić w temat mniej zaawansowanych Czytelników.

Zacznijmy od fuzzingu wykorzystującego concolic execution: ten rodzaj wykonania oparty jest o śledzenie ścieżki w kodzie uruchomionego przypadku testowego oraz gromadzenie informacji o rozgałęzieniach warunkowych w formie relacji symboli (ale nie tych osadzonych w binarce, dzięki którym możemy znaleźć nazwy funkcji 😉 ). Działanie w ten sposób umożliwia reprodukowalne przejście po ścieżce w kodzie, bo znamy wszystkie niezbędne warunki oraz wartości których należy unikać (podstawowe), aby wspomóc pokrycie kodu.

Symbolic execution nie wymaga nic na start, jest w stanie działać bez dostarczonego pliku (aczkolwiek mało efektywnie) a przede wszystkim “dzieje się statycznie” – binarka nie jest uruchamiana w środowisku systemowym, lecz na swój sposób silnik “tłumaczy” jej wykonanie na równania matematyczne, przy okazji je rozwiązując. Pomaga to przy dochodzeniu do nowych ścieżek w kodzie, znajdując wartości warunków jego rozgałęzień.

Łącząc obydwa podejścia wraz z AFL możemy zapewnić sobie lepsze code coverage a w konsekwencji jeszcze więcej znalezionych błędów!

Teoria, teorią… Czas na praktykę hybrid fuzzingu!

Niedługie (lekko ponad 20 minut) wprowadzenie do fuzzingu hybrydowego od twórców projektu QSYM w formie wideo (a dla entuzjastów czytania dokument):

Myślę, że po obejrzeniu Czytelniku rozumiesz dokładnie charakterystykę działania projektu i jego zalety, przejdźmy zatem do implementacji fuzzingu projektu Yara z jego udziałem 🙂

Kompilacja wygląda nieco inaczej niż w przypadku “czystego” AFL, wymagane jest odpalenie skryptu budującego całe środowisko (dla czytelności listingu pominąłem nieistotny output skryptów):

git clone https://github.com/sslab-gatech/qsym
cd qsym/
echo 0|sudo tee /proc/sys/kernel/yama/ptrace_scope
./setup.sh
# Instalacja biblioteki python
virtualenv venv
source venv/bin/activate
pip install .

Szczerze mówiąc to połowa “narzutu” wdrożenia QSYM już za nami, czas na standardową kompilację Yary:

git clone https://github.com/VirusTotal/yara
cd yara/
./bootstrap.sh
# afl-clang-fast ze zbudowanego wcześniej QSYMa
env CC='afl-clang-fast' CXX='afl-clang-fast++' ./configure
make -j
sudo make install

Fuzzery uruchamiamy jak normalnego AFL, z tą różnicą, że po slave’ach wymagane jest odpalenie implementacji QSYM w pythonie:

# Pobranie mojego korpusu reguł Yara i lekkie porządki w folderze
git clone https://github.com/fumfel/yara-fuzzing-corpus
cd yara-fuzzing-corpus
unzip yara_corpus_100616.zip
rm yara_corpus_100616.zip 
rm README.md 
mv crashes/* .
rm -rf crashes/
# Odpalenie fuzzera "master"
afl-fuzz -M f01 -i yara-fuzzing-corpus/ -o yara_qsym_out -m none -- yara @@ /usr/bin/strings
# Odpalenie fuzzera "slave"
afl-fuzz -S f02 -i yara-fuzzing-corpus/ -o yara_qsym_out -m none -- yara @@ /usr/bin/strings
# Odpalenie QSYM
./qsym/bin/run_qsym_afl.py -a ./yara_qsym_out/f02 -o yara_qsym_out -n qsym -- yara @@ /usr/bin/strings

Tyle! QSYM działa sobie w tle i czasami “szturcha” AFL nowymi przypadkami testowymi. Jak widać nie było to nic skomplikowanego 🙂

FuzzManager jako wybawienie dla pogubionych wśród swoich serwerów #2

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

W poprzedniej części omówiłem prostą integrację fuzzerów AFL / HonggFuzz za pomocą tytułowego projektu. Na chwilę obecną jesteśmy w stanie automatycznie parsować raporty z awarii oraz prosto uploadować je na serwer zarządzający. W tej części zajmiejmy się badaniem pokrycia kodu oraz wbudowanym mechanizmem rozpoznawania duplikowanych crashy i ich agregacji w logiczne “kontenerki” w nomenklaturze projektu zwane “crash buckets”.

Pokrycie kodu a FuzzManager

Tym razem nie musimy pisać linijki kodu, lecz musimy dostosować się do wymagań stawianych przez FuzzManagera – dodanie źródeł testowanego projektu i jego kompilacja z przełącznikiem “–coverage” oraz wygenerowanie JSONa zawierającego dane o pokryciu za pomocą grcov. W moim przypadku komendy wyglądały w następujący sposób (przełącznik “-t coveralls+” jest kluczowy do poprawnego formatu wejściowego do FuzzManagera).

# dodanie informacji o zrodle do serwera
python3 FuzzManager/server/manage.py setup_repository ghostpdl GITSourceCodeProvider /home/kamil/ghostpdl
# przełącznik "-t coveralls+" jest kluczowy do poprawnego formatu wejściowego do FuzzManagera
grcov ghostpdl/ -t coveralls+ --commit-sha $(cd ghostpdl &amp;amp;&amp;amp; git rev-parse HEAD) --token NONE -p `pwd`/ghostpdl/ &amp;gt; cc.json
# upload JSONa z pokryciem kodu na serwer "zarzadzajacy" za pomocą modulu CovReporter
python3 -mCovReporter --repository ghostpdl --description "Lorem ipsum..." --submit cc.json

Jeżeli wszystko poszło po naszej myśli, nasz panel webowy pokaże informacje o badaniu danej wersji projektu (trzeba ręcznie dopisać “coverage” do URL – niestety nie ma przycisku w panelu webowym):

Pełna struktura katalogów, wraz z sumarycznym pokryciem każdego folderu:

Szczegółowy widok linii w pliku, które są w naszej “garści” – kolumna po numerze linii to liczba “przejść” przez dany kod:

Z mojej strony mały tip: warto przed każdą (ew. co drugą iteracją fuzzingu) badać pokrycie, wraz z przypadkami testowymi, które zostały znalezione przez fuzzer w poprzedniej iteracji. Oczywiście tyczy się to również uzupełniania lub wzbogacania korpusu o pliki pozyskane z innych źródeł. Pozwoli to śledzić ewolucję korpusu i dowiedzieć się, które aspekty wymagają poprawy. Interesująca może być również zmiana pokrycia jako funkcji korpusu i dodawanych ficzerów / bugfixów do projektu 🙂

Awarie, odmiennie niż jajka, wszystkie wpadają do jednego koszyka

Śródtytuł mocno osobliwy, jednak adekwatny: podczas fuzzingu znajdowane są setki jak nie tysiące awarii, które mają tą samą przyczynę a Crash Buckets jest mechanizmem, który potrafi nad tym zapanować. Klasyfikacja odbywa się za pomocą raportów o awarii ASAN \ Valgrind lub gdb. Następnie do nich aplikowane są warunki deklarowane w panelu webowym np. adres crasha mniejszy od 0xDEADBEEF, nazwa funkcji do_evil() lub charakterystyczna wartość stderr.

Podstawowym elementem bucketa jest wzorzec, którego dopasowanie scala wszystko w jedną całość – operuje on na wcześniej opisanych warunkach, które podczas tworzenia podpowiada sam FuzzManager (sekcja Signature):

Bardzo prosta sprawa, aczkolwiek musi paść słowo wyjaśnienia odnośnie typów bucketów, opisanych w dolnych checkbox’ach – na obecnym etapie rozwoju FuzzManagera pełnią jedynie funkcję dekoracyjną i nie mają żadnego wpływu na funkcjonalność (co potwierdza repozytorium na GH). Poniżej widok awarii, która została przyporządkowana do naszego pierwszego “koszyka”:

 Podsumowanie

Tak jak poprzednio post nie jest długi, ma to na celu przeniesienie “ciężkości” na praktykę a nie czytanie. Mam nadzieję, że uważniejsi czytelnicy dostrzegli brak cenzury stacktrace’a błędu w Ghostscripcie, który został już załatany 🙂

Przedsmak SECURE czyli SECURE Early Bird 2019

Już drugi rok z rzędu, mój zespół, organizuje konferencję bedącą zwiastunem “dużego” SECURE’a, który odbywa się w październiku. W tej edycji również miałem przyjemność poprowadzić prezentację, o tematyce już znanej moim czytelnikom (z PLNOG22) pod tytułem “Hakowanie AI – Czy da się zepsuć myślące maszyny i/lub ludzi?“. Dzięki świetnej pracy Mateusza i Huberta, mieliśmy profesjonalny streaming oraz nagrania na YT, dzień po konferencji – wielkie WOW! 🙂

FuzzManager jako wybawienie dla pogubionych wśród swoich serwerów #1

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 🙂

“Od zera do bughuntera” – czyli o cyklu, który nieświadomie rozpocząłem dawno temu…

Zastanawiając się nad dalszym kierunkiem bloga, wpadłem na pomysł zebrania w jedno miejsce postów o metodach bughuntingu (oraz exploitacji), które napisałem, uaktualnić je, gdzie jest to niezbędne i “spiąć” w sensowną całość. Roboczo nazwałem ten cykl “Od zera do bughuntera”, który zaplanowałem na około 15 postów (wraz z napisanymi) –  poniżej linki do opublikowanych artykułów:

Dodatkowo uchylę rąbka tajemnicy i zdradzę, że już niedługo szykuje się intensywny okres na blogu w obszarze bughuntingu. Stay tuned! 🙂

#patoredteaming – O tym co jest nie tak z branżą bezpieczeństwa na WDI 2019

Kolejny rok, kolejne wystąpienie na Warszawskich Dniach Informatyki – w agendzie pojawiam się już trzeci rok i bardzo sobie to chwalę 🙂 W tym roku wystąpiłem z mocną ekipą (@_psrok1, @icedevml) i prowokacyjnym hasztagiem w tytule, aby zwrócić uwagę na pewne zjawisko, które od dłuższego czasu (około 1,5 roku) obserwuję.

Chodzi o, delikatnie mówiąc, mało odpowiedzialne zachowania podczas tworzenia narzędzi lub przeprowadzania testów bezpieczeństwa i udawanie, że nic się nie stało (wymówki w stylu: projekt akademicki, nie wolno używać do złośliwych celów, wyśmiewanie osób broniących rozwiązania i przystosowanie projektów do obchodzenia tych mitygacji). Niestety nie mogę podzielić się pełną prezentacją, natomiast udostępniam zrzut ekranu slajdu definiującego nasz autorski hasztag: