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 🙂

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.