
Fuzzer di formati binari guidato da template che genera e analizza input di test validi ad alta velocità, con integrazione AFL++ per fuzzing guidato dalla copertura.
FormatFuzzer è un framework per la generazione e l'analisi di input binari ad alta efficienza e alta qualità.
Prende un template binario che descrive il formato di un input binario e genera un eseguibile che produce e analizza il formato binario dato.
Da un template binario per GIF, ad esempio, FormatFuzzer produce un generatore di GIF - noto anche come GIF fuzzer.
I generatori prodotti da FormatFuzzer sono estremamente efficienti, producendo migliaia di input di test validi al secondo - in netto contrasto con i fuzzer basati su mutazione, dove la stragrande maggioranza degli input non è valida. Gli input generati da FormatFuzzer sono indipendenti dal programma sotto test (o in realtà da qualsiasi programma), quindi puoi usarli anche in contesti black-box. Tuttavia, FormatFuzzer si integra anche con AFL++ per produrre input validi che mirano anche alla massima copertura. Nei nostri esperimenti, questo approccio "best of two worlds" supera tutte le altre impostazioni; consulta il nostro articolo per i dettagli.
I template binari utilizzati da FormatFuzzer provengono dall'editor 010.
Ci sono più di 170 template binari, che possono essere utilizzati direttamente per FormatFuzzer o adattati al suo uso. Pronti all'uso, FormatFuzzer produce formati come AVI, BMP, GIF, JPG, MIDI, MP3, MP4, PCAP, PNG, WAV e ZIP; e continuiamo ad ampliare questo elenco ogni settimana.
I contributi sono benvenuti! Visita la pagina del progetto FormatFuzzer per segnalare idee e problemi o aggiungere pull request. Per i dettagli su come funziona FormatFuzzer e come si confronta, leggi il nostro articolo per maggiori informazioni.
FormatFuzzer è disponibile dalla pagina del progetto FormatFuzzer. Puoi scaricare e decomprimere l'ultima release dalla pagina delle release.
Per la versione più recente e aggiornata, puoi anche clonare il suo repository git:
git clone https://github.com/uds-se/FormatFuzzer.git
Tutte le ulteriori operazioni avvengono nella sua cartella principale:
cd FormatFuzzer
Per eseguire FormatFuzzer, hai bisogno di:
getopt_long()) come clang o gccpy010parser, six e intervaltreezlib (per le funzioni di compressione)boost (per le funzioni di checksum)Se prevedi di modificare gli script di build e configurazione (file .ac e .am), avrai anche bisogno di:
sudo apt install git g++ make automake python3-full zlib1g-dev libboost-dev
python3 -m venv ~/fuzz
source ~/fuzz/bin/activate
pip3 install py010parser six intervaltree
xcode-select --install
brew install python3 automake boost
pip3 install py010parser six intervaltree
Su tutti i sistemi, usando pip:
pip install py010parser
pip install six
pip install intervaltree
Nota: tutti i comandi di compilazione richiedono di trovarsi nella stessa cartella di questo file README. La compilazione di un fuzzer al di fuori di questa cartella non è ancora supportata.
C'è uno script build.sh che automatizza tutti i passaggi di costruzione.
Semplicemente esegui
./build.sh gif
per creare un GIF fuzzer.
Funziona per tutti i formati di file forniti in templates/; se esiste un file templates/FOO.bt, allora ./build.sh FOO compilerà un fuzzer.
C'è un Makefile (sorgente in Makefile.am) che automatizza tutti i passaggi di costruzione.
(Richiede GNU make.)
Prima esegui
touch configure Makefile.in
poi
./configure
e poi
make gif-fuzzer
per creare un GIF fuzzer.
Funziona per tutti i formati di file forniti in templates/; se esiste un file templates/FOO.bt, allora make FOO-fuzzer compilerà un fuzzer.
Se il metodo make sopra non funziona, o se vuoi più controllo, potresti dover procedere manualmente.
Esegui il compilatore ffcompile per compilare il template binario in codice C++. Prende due argomenti: il template binario .bt e un file .cpp C++ da generare.
./ffcompile templates/gif.bt gif.cpp
Usa i seguenti comandi per creare un fuzzer gif-fuzzer.
Prima, compila il driver generico da riga di comando:
g++ -c -I . -std=c++17 -g -O3 -Wall fuzzer.cpp
(-I . indica la posizione del file bt.h; -std=c++17 imposta lo standard C++.)
Poi, compila il parser/compilatore binario:
g++ -c -I . -std=c++17 -g -O3 -Wall gif.cpp
Infine, collega il parser/compilatore binario con il driver da riga di comando per ottenere un eseguibile. Se usi librerie extra (come -lz), assicurati di specificarle anche qui.
g++ -O3 gif.o fuzzer.o -o gif-fuzzer -lz
FormatFuzzer può essere eseguito come parser, generatore o mutatore standalone di formati specifici. Inoltre, può essere chiamato da fuzzer di uso generale come AFL++ per integrare queste capacità specifiche del formato nel processo di fuzzing (vedi la sezione sotto sull'integrazione con AFL++).
Il fuzzer generato prende un comando come primo argomento, seguito da opzioni e argomenti per quel comando.
Il comando più importante è fuzz, per produrre output. I suoi argomenti sono i file da generare nel formato appropriato.
Esegui il generatore come
./gif-fuzzer fuzz output.gif
per creare un file binario casuale output.gif, o
./gif-fuzzer fuzz out1.gif out2.gif out3.gif
per creare tre file GIF out1.gif, out2.gif e out3.gif.
Nota che il template gif.bt che forniamo è stato arricchito con funzioni speciali per facilitare la generazione di file validi. Se usi file template .bt originali senza adattamenti, potresti ottenere avvisi durante la generazione e creare file non validi.
Puoi anche eseguire il fuzzer come parser per file binari, usando il comando parse. Questo è utile se vuoi testare l'accuratezza del template binario, o se vuoi mutare un input (vedi 'Decision Files', sotto).
Per eseguire il parser, usa
./gif-fuzzer parse input.gif
Vedrai messaggi di errore se input.gif non può essere analizzato con successo.
Durante l'analisi, puoi anche memorizzare tutte le decisioni di parsing (cioè quali alternative di parsing sono state prese) in un decision file. Si tratta di una sequenza di byte che enumera le decisioni prese.
Ogni byte rappresenta una singola decisione di parsing. Un valore di byte 0 significa che è stata presa la prima alternativa, un valore di byte 1 significa che è stata presa la seconda alternativa, e così via.
Puoi generare un tale decision file quando analizzi un input:
./gif-fuzzer parse --decisions input.dec input.gif
Qui, input.dec memorizza le decisioni prese per analizzare input.gif.