Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
FormatFuzzer — 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. | Kitploit
Strumenti/GitHubGitHub/uds-se/formatfuzzer
FuzzingAnalisi di Binari
GitHubuds-se/formatfuzzer

FormatFuzzer

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.

Vedi RepositorySito web
4463846 mesi faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

FormatFuzzer

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.

Ottenere

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:

root@kitploit:~
git clone https://github.com/uds-se/FormatFuzzer.git

Tutte le ulteriori operazioni avvengono nella sua cartella principale:

root@kitploit:~
cd FormatFuzzer

Prerequisiti

Per eseguire FormatFuzzer, hai bisogno di:

  • Python 3
  • Un compilatore C++ con librerie GNU (in particolare getopt_long()) come clang o gcc
  • I pacchetti Python py010parser, six e intervaltree
  • Una libreria zlib (per le funzioni di compressione)
  • Una libreria boost (per le funzioni di checksum)

Se prevedi di modificare gli script di build e configurazione (file .ac e .am), avrai anche bisogno di:

  • GNU autoconf
  • GNU automake

Installazione dei requisiti su Linux (Pacchetti Debian, usando un ambiente virtuale Python)

root@kitploit:~
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

Installazione dei requisiti su MacOS (con Xcode e Homebrew)

root@kitploit:~
xcode-select --install
brew install python3 automake boost
pip3 install py010parser six intervaltree

Installazione solo dei pacchetti Python (tutti i sistemi operativi)

Su tutti i sistemi, usando pip:

root@kitploit:~
pip install py010parser
pip install six
pip install intervaltree

Compilazione

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.

Metodo 1: Usando lo script build.sh

C'è uno script build.sh che automatizza tutti i passaggi di costruzione. Semplicemente esegui

root@kitploit:~
./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.

Metodo 2: Usando Make

C'è un Makefile (sorgente in Makefile.am) che automatizza tutti i passaggi di costruzione. (Richiede GNU make.) Prima esegui

root@kitploit:~
touch configure Makefile.in

poi

root@kitploit:~
./configure

e poi

root@kitploit:~
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.

Metodo 3: Passaggi manuali

Se il metodo make sopra non funziona, o se vuoi più controllo, potresti dover procedere manualmente.

Passo 1: Compilazione dei file template binari in codice C++

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.

root@kitploit:~
./ffcompile templates/gif.bt gif.cpp

Passo 2: Compilazione del codice C++

Usa i seguenti comandi per creare un fuzzer gif-fuzzer. Prima, compila il driver generico da riga di comando:

root@kitploit:~
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:

root@kitploit:~
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.

root@kitploit:~
g++ -O3 gif.o fuzzer.o -o gif-fuzzer -lz

Esecuzione del Fuzzer

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

root@kitploit:~
./gif-fuzzer fuzz output.gif

per creare un file binario casuale output.gif, o

root@kitploit:~
./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.

Esecuzione dei Parser

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

root@kitploit:~
./gif-fuzzer parse input.gif

Vedrai messaggi di errore se input.gif non può essere analizzato con successo.

Decision Files

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:

root@kitploit:~
./gif-fuzzer parse --decisions input.dec input.gif

Qui, input.dec memorizza le decisioni prese per analizzare input.gif.

Puoi anche usare un tale decision file quando generi input. Il fuzzer prenderà allora le stesse identiche decisioni trovate durante il parsing. Il seguente comando genera un nuovo file GIF usando le decisioni determinate durante l'analisi di input.gif:

root@kitploit:~
./gif-fuzzer fuzz --decisions input.dec input2.gif

Se tutto funziona bene, entrambi i file dovrebbero essere identici:

root@kitploit:~
cmp input.gif input2.gif

Mutando un decision file (ad esempio sostituendo singoli byte), puoi creare input simili al file originale analizzato. Questo è utile per interfacciarsi con specifiche strategie di test e fuzzer come AFL, dove puoi usare gif-fuzzer e simili come traduttori da decision file a file binari e viceversa: AFL muterebbe i decision file, e il programma sotto test verrebbe eseguito sui file binari tradotti. A differenza della mutazione diretta dei file binari (come farebbe normalmente AFL), questo avrebbe il vantaggio di avere sempre input validi - e quindi di progredire molto più velocemente verso la copertura.

Integrazione con AFL++

Oltre ai fuzzer specifici per formato, come gif-fuzzer, FormatFuzzer può anche essere compilato in librerie condivise specifiche per formato, come gif.so (per farlo, esegui semplicemente ./build.sh gif o make gif.so). Queste librerie condivise possono essere caricate da fuzzer di uso generale, come AFL++.

Per eseguire AFL++ con FormatFuzzer, segui le istruzioni sulla nostra versione modificata di AFL++. Supportiamo diverse strategie di fuzzing, tra cui:

  • AFL+FFMut: esegue AFL++ usando FormatFuzzer per fornire mutazioni intelligenti specifiche del formato.

  • AFL+FFGen: usa FormatFuzzer come generatore specifico del formato, mentre AFL++ muta i suoi semi decisionali.

Creazione e Personalizzazione di Template Binari

Per scrivere i tuoi template binari .bt (e quindi creare un fuzzer/parser ad alta efficienza per questo formato), leggi la sezione Introduction to Templates and Scripts dal Manuale dell'Editor 010.

In molti casi, un template del formato che stai cercando (o uno simile) potrebbe già esistere. Dai un'occhiata alla collezione di template binari dell'editor 010 per vedere se c'è qualcosa che puoi usare o su cui basare il tuo formato.

Nota che i file .bt forniti nel repository sono generalmente orientati all'analisi di file. Possono essere usati anche per la generazione di file; ma spesso mancano informazioni esatte su quali parti dell'input sono obbligatorie.

In questa sezione, discutiamo alcuni dei modi in cui puoi personalizzare i file .bt per funzionare bene con FormatFuzzer.

Ad esempio, per il formato GIF, il file templates/gif-orig.bt mostra il template binario originale, che era progettato solo per l'analisi, mentre il file templates/gif.bt è una versione modificata in grado di generare GIF validi. Confrontando i due file, vediamo che è stato necessario un piccolo numero di modifiche per ottenere questo risultato.

Se hai creato un gif-fuzzer, eseguendo make gif-fuzzer o usando lo strumento ffcompile, hai già ottenuto un file C++ gif.cpp che contiene un'implementazione del generatore e parser GIF. Questo è utile per vedere come le modifiche apportate al template binario vengono tradotte in codice eseguibile. Maggiori dettagli sul codice C++ sono presentati nella prossima sezione.

Il template binario GIF fa uso di funzioni di lookahead ReadUByte() e ReadUShort() per guardare avanti ai valori dei prossimi byte nel file prima di analizzarli effettivamente in un campo di struct. In fase di generazione, permettiamo a queste funzioni di ricevere un argomento aggiuntivo che specifica un insieme di buoni valori conosciuti da scegliere per i byte che guardiamo avanti. Inoltre, permettiamo anche di specificare un insieme globale di buoni valori conosciuti da usare sempre quando si chiama una particolare funzione di lookahead, come ReadUByte(). Questi sono memorizzati nel vettore ReadUByteInitValues.

Per impostazione predefinita, la nostra procedura di traduzione ffcompile cerca di estrarre valori interessanti che sono stati usati in confronti contro i byte di lookahead e di usarli come insieme globale di valori conosciuti. Quando esegui

root@kitploit:~
./ffcompile templates/gif.bt gif.cpp

un messaggio stampato mostra le funzioni di lookahead identificate, così come i valori interessanti estratti:

root@kitploit:~
Finished creating cpp generator.

Lookahead functions found:

ReadUByte
ReadUShort

Mined interesting values:

GlobalColorTableFlag: ['1']
LocalColorTableFlag: ['1']
ReadUByte: ['0x3B', '0x2C']
ReadUShort: ['0xF921', '0xFE21', '0x0121', '0xFF21']
Signature: ['"GIF"']

Per la generazione di GIF, tuttavia, è meglio specificare l'insieme di buoni valori conosciuti per ReadUByte() individualmente a ogni chiamata della funzione. Quindi definiamo un array vuoto (dimensione 0)

root@kitploit:~
const local UBYTE ReadUByteInitValues[0];

per sovrascrivere l'insieme globale di ReadUByteInitValues e per ogni chiamata a ReadUByte(), usiamo un argomento aggiuntivo per specificare l'insieme di buoni valori da usare per quella particolare posizione. Il linguaggio del template binario è anche abbastanza potente da permettere che questa scelta sia fatta in base a condizioni runtime. Ad esempio, nel codice seguente mostriamo come la scelta di valori appropriati per una chiamata a ReadUByte() può dipendere dalla versione GIF corrente che stiamo generando. Una versione GIF 89a permette un valore extra possibile per il byte (0x21).

root@kitploit:~
	if(GifHeader.Version == "89a")
		local UBYTE values[] = { 0x3B, 0x2C, 0x21 };
	else
		local UBYTE values[] = { 0x3B, 0x2C };

	while (ReadUByte(FTell(), values) != 0x3B) {
		...
	}

Le rimanenti modifiche necessarie per il template binario GIF sono simili. Ad esempio, per ogni campo di struct puoi anche specificare un insieme di buoni valori conosciuti. Ad esempio questo specifica i valori corretti per il campo Version: 87a e 89a.

root@kitploit:~
	char	Version[3] = { {"87a"}, {"89a"} };

Comprensione del Codice C++ Generato

Per scopi di debug, così come per capire come apportare modifiche appropriate per migliorare i tuoi generatori e parser, può essere utile comprendere alcuni meccanismi interni del codice C++ generato. Idealmente, dovresti essere in grado di modificare i file template binari finché non possono essere usati per generare file validi con alta probabilità, quindi non dovresti dover modificare il codice C++ generato.

Il codice C++ crea una classe per ogni struct e union definiti nel template binario, così come per i tipi nativi, come int.

Al momento della costruzione, quando si inizializza una variabile, possiamo definire un insieme di buoni valori conosciuti che questa variabile può assumere. Ad esempio, la chiamata al costruttore

root@kitploit:~
char_array_class cname(cname_element, { "IHDR", "tEXt", "PLTE", "cHRM", "sRGB", "iEXt", "zEXt", "tIME", "pHYs", "bKGD", "sBIT", "sPLT", "acTL", "fcTL", "fdAT", "IHDR", "IEND" });

specificherebbe 17 buoni valori da usare per la variabile cname. Ma spesso questo non è sufficiente, poiché la scelta dei tipi di chunk appropriati è sensibile al contesto. Quindi permettiamo anche di specificare un insieme di buoni valori al momento della generazione quando si genera un nuovo chunk. Ad esempio, questa chiamata potrebbe essere usata per generare un'istanza di chunk per il primo chunk, che deve essere di tipo IHDR.

root@kitploit:~
GENERATE(chunk, ::g->chunk.generate({ "IHDR" }, false));

Quando si genera il secondo chunk, potremmo usare questa lunga lista di possibili chunk che possono trovarsi tra il chunk IHDR e il chunk PLTE:

root@kitploit:~
GENERATE(chunk, ::g->chunk.generate({ "iCCP", "sRGB", "sBIT", "gAMA", "cHRM", "pHYs", "sPLT", "tIME", "zTXt", "tEXt", "iTXt", "eXIf", "oFFs", "pCAL", "sCAL", "acTL", "fcTL", "fdAT", "fRAc", "gIFg", "gIFt", "gIFx", "sTER" }, true));

Il generatore sceglierà quindi uniformemente uno dei buoni valori conosciuti da usare per la nuova istanza. Permettiamo anche la scelta di un valore malvagio che non è uno dei buoni valori conosciuti con una piccola probabilità di 1/128. Questa funzionalità può essere abilitata o disabilitata in qualsiasi momento usando il metodo set_evil_bit.

Tutte le scelte casuali effettuate dal generatore sono fatte chiamando il metodo rand_int().

root@kitploit:~
long long rand_int(unsigned long long x, std::function<long long (unsigned char*)> parse);

Quando il programma viene eseguito come generatore, questo metodo campiona un intero da 0 a x-1 leggendo byte dal buffer casuale. Quando il programma viene eseguito come parser, questo metodo usa la funzione parse() per scoprire quali byte casuali devono essere presenti nel buffer casuale per generare il file di destinazione, e poi scrive quei byte nel buffer casuale. La funzione parse riceve come argomento il buffer alla posizione corrente del file e deve poi restituire quale valore dovrebbe essere restituito dalla chiamata corrente a rand_int() per generare questa esatta configurazione del file.

Autori

FormatFuzzer è stato progettato e scritto da Rafael Dutra <[email protected]>.

Il concetto di un compilatore di fuzzer è stato introdotto da Rahul Gopinath <[email protected]> e Andreas Zeller <[email protected]>.

Copyright e Licenze

FormatFuzzer è Copyright © 2020, 2021 da CISPA Helmholtz Center for Information Security. Si applicano le seguenti licenze:

  • Il codice di FormatFuzzer (in particolare, tutto il codice C++ e il codice relativo alla sua generazione) è soggetto alla GNU GENERAL PUBLIC LICENSE, come indicato in COPYING.

  • In deroga a quanto sopra, il codice C++ generato da FormatFuzzer (cioè, fuzzer e parser per formati specifici) è di pubblico dominio.

  • Il codice pfp originale, su cui si basa FormatFuzzer, è soggetto a una licenza MIT, come indicato in LICENSE-pfp.

Scarica lo strumento