Fuzzing cu American Fuzzy Lop – Quickstart

Codarea securizată este o practică foarte dificilă. De obicei, atunci când programatorii dezvoltă software, scopul lor este de a face software-ul să funcționeze mai degrabă decât să se strice. În acest proces, pot apărea vulnerabilități în cazurile în care a fost folosită o funcție veche în locul uneia mai sigure. În consecință, software-ul moștenit este deosebit de vulnerabil.

C este unul dintre acele limbaje care este în mod inerent foarte versatil și puternic, dar are un dezavantaj critic – securitatea software-ului bazat pe C depinde de cunoștințele programatorului. Acest lucru înseamnă că, dacă programatorul este bine informat cu privire la codarea sigură, software-ul său va fi și el sigur. Pe de altă parte, și aceasta formează cea mai mare parte, dacă programatorul nu este suficient de sofisticat, vor exista lacune în software-ul lor care vor duce în cele din urmă la o exploatare.

Pentru oameni ca mine, care cunosc programarea, dar sunt noi în industria securității, este foarte important să studieze codul vulnerabil și să înțeleagă posibilele consecințe. Acest lucru ajută la perfecționarea abilităților de codificare și la dezvoltarea unei atitudini de atacator ÎN FAZA de codificare, mai degrabă decât DUPĂ codificarea întregului software.

Cu toată onestitatea, este destul de greoi să studiezi întregul cod sursă al unei aplicații atunci când cauți vulnerabilități precum depășirile de buffer. Deși această metodă are propriile sale merite, nu este cea mai ușoară metodă de a găsi vulnerabilități simple care pot fi critice. Astfel de vulnerabilități trebuie rezolvate imediat, iar cel mai simplu mod de a le găsi este prin intermediul unei tehnici numite Fuzzing.

Fuzzing este o tehnică pentru găsirea vulnerabilităților „ușoare” în cod prin trimiterea de date generate „aleatoriu” către un executabil. În general, există trei tipuri de fuzzers:

  1. Mutație: Un tip de fuzzing „prost” în care sunt generate eșantioane de intrare malformate și furnizate executabilului. Această intrare poate fi sau nu conformă cu tipul de intrare care este așteptat de aplicație, astfel încât probabilitatea de a găsi bug-uri reale nu este mare.
  2. Generare: Un tip de fuzzing „inteligent” care necesită niște date de testare inițiale din care algoritmul fuzzer poate genera de la zero o intrare malformată. Acest tip de fuzzing este mai bun decât fuzzingul prost în multe cazuri, deoarece programul primește intrarea la care se așteaptă.
  3. Evolutiv: Acest tip de fuzzers utilizează feedback-ul de la fiecare „fuzz” pentru a învăța în timp formatul de intrare.

În această postare, ne vom uita la fuzzing cu American Fuzzy Lop (AFL). Este un tip de fuzzer evolutiv care se potrivește pentru a face fuzz la programele care primesc intrare de la STDIN sau de la un fișier.

.

Există o serie de fuzzeri în sălbăticie, inclusiv Peach și syzkaller. Deci, de ce AFL?

  1. Cazul de utilizare. Acesta este cel mai important punct de luat în considerare. Cazul meu de utilizare a fost să fac fuzz la o aplicație care primește date de intrare dintr-un fișier. Este important de reținut că AFL nu are capacitatea de a face fuzz prin rețele.
  2. Este simplu de instalat.
  3. Interfața UI a AFL conține o tonă de informații, inclusiv statistici în timp real ale procesului de fuzzing.

Configurarea AFL

Configurarea AFL este ușoară și am făcut-o mai ușoară pentru dumneavoastră prin scrierea unui script shell simplu (dar rudimentar) care îl va instala pentru dumneavoastră! Rulați scriptul cu privilegiile dvs. de utilizator și acesta va instala toate dependențele, AFL și instrumentele aferente. Scriptul shell poate fi găsit aici: https://github.com/nikhilh-20/enpm691_project/blob/master/install_afl.sh

Alegeți aplicația de fuzzat

În această postare, ne vom ocupa doar de fuzzarea acelor aplicații pentru care avem codul sursă. Acest lucru se datorează faptului că AFL instrumentează codul sursă pentru a monitoriza execuția, erorile și alte lucruri legate de performanță. De asemenea, este posibil să fuzzăm direct un executabil, dar acest lucru este experimental și nu face parte din scopul acestei postări (sfat: necesită QEMU).

Alegeți orice sistem open source de pe GitHub pentru fuzzing. Cu cât alegerea dvs. este mai cunoscută, cu atât va avea probabil un număr mai mic de vulnerabilități. Și alții caută bug-uri! O metodă simplă pe care o folosesc pentru a găsi cod vulnerabil este să folosesc GitHub Search. Iată ce fac:

  1. Căutați o funcție vulnerabilă, să zicem strcpy.
  2. Rezultatele vor fi de ordinul milioanelor. Mergeți la categoria commits a rezultatelor. Aici veți găsi acele depozite în care strcpy a fost folosit (sau poate eliminat). Aceste depozite sunt un bun punct de plecare pentru a începe fuzzing.

Instrumenting the Application

Din motive de confidențialitate, nu pot dezvălui depozitul pe care îl folosesc.

Clonează depozitul git.

nikhilh@ubuntu:~$ git clone https://github.com/vuln; cd vuln

Stabilește o variabilă de mediu, AFL_HARDEN=1. Aceasta activează anumite opțiuni de întărire a codului în AFL în timpul compilării, ceea ce facilitează detectarea bug-urilor de corupție a memoriei.

nikhilh@ubuntu:~/vuln$ export AFL_HARDEN=1

Setați anumiți indicatori ai compilatorului, astfel încât aplicația să fie compilată într-un mod care să ne faciliteze găsirea (și exploatarea) vulnerabilităților. Ideal ar fi să folosim variabilele de mediu pentru a seta ceea ce avem nevoie, dar există destul de multă personalizare. așa că vom edita direct fișierul Makefile.

Asigurați-vă că compilatorul folosit este afl-gcc sau afl-clang în loc de gcc și respectiv clang. Acest lucru este ceea ce permite AFL să instrumenteze codul sursă.

Adaugați stegulețe de compilator:

-fno-stack-protector dezactivează stack protector, ceea ce ne va permite să exploatăm buffer overflows.

-m32 este necesar doar dacă folosiți o mașină pe 32 de biți, altfel nu.

După ce ați terminat cu aceste modificări, este timpul să compilați aplicația. Rulați make. Când o faceți, TREBUIE să vedeți declarații ca acestea în jurnal:

Instrumented 123 locations (32-bit, hardened-mode, ratio 100%).

Dacă nu vedeți astfel de declarații, înseamnă că AFL nu a activat codul aplicației pentru fuzzing. Cu alte cuvinte, nu a instrumentat cu succes codul sursă.

Eșantioane de testare

AFL este un tip evolutiv de fuzzer. Aceasta înseamnă că, la fel ca și fuzzerele bazate pe generație, are nevoie de date de testare inițiale pentru a înțelege ce fel de date așteaptă aplicația țintă. Atunci când se vizează sisteme open source, acest lucru este ușor de găsit. Trebuie doar să vă uitați în directorul lor de test și veți găsi toate datele de test de care aveți nevoie.

nikhilh@ubuntu:~/vuln$ mkdir afl_in afl_out

nikhilh@ubuntu:~/vuln$ cp test/* afl_in/

Fuzzing Begins

Acum că avem mostrele noastre de test, suntem gata să facem fuzz!

Oh, așteptați… trebuie să schimbăm și locul unde merg notificările de accident ale aplicației. By default, when an application crashes, the core dump (basically, the contents of RAM are stored in a file to help in debugging) notification is sent to the system’s core handler. We don’t want this. Why? By the time this notification reaches AFL, it’ll be classified as a timeout rather than a crash.

nikhilh@ubuntu:~/vuln$ sudo su

password for nikhilh:

root@ubuntu:/home/nikhilh/vuln# echo core > /proc/sys/kernel/core_pattern

root@ubuntu:/home/nikhilh/vuln# exit

NOW, we are ready to fuzz!

nikhilh@ubuntu:~/vuln$ afl-fuzz -i afl_in -o afl_out -S slaveX — ./vuln @@

Command line flags used:

  1. -i — This marks the test input directory. Aici am stocat datele inițiale de testare.
  2. -o- Acesta este directorul în care AFL scrie informații utile cu privire la accidentări, blocaje, etc.
  3. -S – Acesta este modul Slave. Practic, AFL va modifica la întâmplare datele de intrare, cauzând fuzzing nedeterminist.
  4. Opțiunea -M este modul Master, care este fuzzing determinist, ceea ce înseamnă, în esență, că fiecare bit de intrare este modificat într-un fel. (Acest lucru este lent! … Evident.)
  5. @@ – Aceasta este poziția în care se va afla fișierul de test de intrare. AFL înlocuiește acest lucru pentru dvs. în mod automat. Dacă executabilul dvs. primește intrare de la STDIN, atunci acest lucru nu este necesar.

Fuzzing Results

Aceasta va dura ceva timp pentru a se afișa. De multe ori, oamenii fac fuzz pentru mai mult de 24 de ore (și s-ar putea să se termine cu nimic). În cazul meu, cred că aplicația a fost un pic prea vulnerabilă, așa că am avut 516 crash-uri unice în decurs de o oră. Totuși, asta nu înseamnă că există 516 vulnerabilități!

Puteți ieși din sesiunea de fuzzing cu un Ctrl-C.

Analysis Phase

Now that we have results, we need to analyze them to see which ones are exploitable. To this end, we will use one of AFL’s utilities called afl-collect. This will have been installed through the installation script as well.

nikhilh@ubuntu:~/afl-utils$ afl-collect -d crashes.db -e gdb_script -r -rr ~/vuln/afl_out/slaveX ./output_dir — ~/vuln/vuln

To understand what each command line flag does, refer to its help section.

nikhilh@ubuntu:~/afl-utils$ afl-collect — help

If you see lines such as these in the output, celebrate! You’ve found something interesting to try and exploit.

*** GDB+EXPLOITABLE SCRIPT OUTPUT ***

slaveX:id:000000,sig:11,src:000000,op:havoc,rep:2……………:EXPLOITABLE

slaveX:id:000046,sig:11,src:000004,op:havoc,rep:4……………:EXPLOITABLE

AFL vă va arăta ce intrare a cauzat blocarea aplicației. În acest caz, fișierul: id:000046,sig:11,src:000004,op:havoc,rep:4 a cauzat un StackBufferOverflow în aplicație. Astfel de fișiere pot fi găsite în ../afl_out-slaveX/crashes/

Done!

Asta este tot pentru un început rapid în fuzzing! Procesul este foarte simplu și foarte convenabil, deoarece totul este automatizat. Următorul pas ar fi să analizăm de ce intrarea a cauzat un Buffer Overflow și să căutăm o modalitate de a-l exploata. Nu uitați că nu toate vulnerabilitățile pot duce la o exploatare.

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.