
Fuzzer de formato binário orientado por template que gera e analisa entradas de teste válidas em alta velocidade, com integração AFL++ para fuzzing guiado por cobertura.
FormatFuzzer é uma estrutura para geração e análise de alta eficiência e alta qualidade de entradas binárias.
Ela recebe um template binário que descreve o formato de uma entrada binária e gera um executável que produz e analisa o formato binário fornecido.
A partir de um template binário para GIF, por exemplo, FormatFuzzer produz um gerador de GIF - também conhecido como fuzzer de GIF.
Os geradores produzidos pelo FormatFuzzer são altamente eficientes, produzindo milhares de entradas de teste válidas por segundo - em forte contraste com fuzzers baseados em mutação, onde a grande maioria das entradas é inválida. As entradas geradas pelo FormatFuzzer são independentes do programa sob teste (ou na verdade, de qualquer programa), então você também pode usá-las em configurações de caixa-preta. No entanto, o FormatFuzzer também se integra com o AFL++ para produzir entradas válidas que também visam a cobertura máxima. Em nossos experimentos, essa abordagem "melhor dos dois mundos" supera todas as outras configurações; veja nosso artigo para detalhes.
Os templates binários usados pelo FormatFuzzer vêm do editor 010.
Existem mais de 170 templates binários, que podem ser usados diretamente para o FormatFuzzer ou adaptados para seu uso. Prontos para uso, o FormatFuzzer produz formatos como AVI, BMP, GIF, JPG, MIDI, MP3, MP4, PCAP, PNG, WAV e ZIP; e continuamos estendendo esta lista toda semana.
Contribuições são bem-vindas! Visite a página do projeto FormatFuzzer para registrar ideias e problemas, ou adicionar pull requests. Para detalhes sobre como o FormatFuzzer funciona e como ele se compara, leia nosso artigo para mais informações.
O FormatFuzzer está disponível na página do projeto FormatFuzzer. Você pode baixar e extrair a versão mais recente na página de releases.
Para o mais recente e melhor, você também pode clonar seu repositório git:
git clone https://github.com/uds-se/FormatFuzzer.git
Todas as ações subsequentes ocorrem na sua pasta principal:
cd FormatFuzzer
Para executar o FormatFuzzer, você precisa do seguinte:
getopt_long()) como clang ou gccpy010parser, six e intervaltreezlib (para funções de compressão)boost (para funções de checksum)Se você planeja editar os scripts de construção e configuração (arquivos .ac e .am), você também precisará de
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
Em todos os sistemas, usando pip:
pip install py010parser
pip install six
pip install intervaltree
Nota: todos os comandos de construção exigem que você esteja na mesma pasta que este arquivo README. A construção de um fuzzer fora desta pasta ainda não é suportada.
Existe um script build.sh que automatiza todas as etapas de construção.
Basta executar
./build.sh gif
para criar um fuzzer de GIF.
Isso funciona para todos os formatos de arquivo fornecidos em templates/; se houver um arquivo templates/FOO.bt, então ./build.sh FOO construirá um fuzzer.
Existe um Makefile (fonte em Makefile.am) que automatiza todas as etapas de construção.
(Requer GNU make.)
Primeiro faça
touch configure Makefile.in
depois
./configure
e então
make gif-fuzzer
para criar um fuzzer de GIF.
Isso funciona para todos os formatos de arquivo fornecidos em templates/; se houver um arquivo templates/FOO.bt, então make FOO-fuzzer construirá um fuzzer.
Se o método make acima não funcionar, ou se você quiser mais controle, pode ser necessário prosseguir manualmente.
Execute o compilador ffcompile para compilar o template binário em código C++. Ele recebe dois argumentos: o template binário .bt e um arquivo C++ .cpp a ser gerado.
./ffcompile templates/gif.bt gif.cpp
Use os comandos a seguir para criar um fuzzer gif-fuzzer.
Primeiro, compile o driver de linha de comando genérico:
g++ -c -I . -std=c++17 -g -O3 -Wall fuzzer.cpp
(-I . denota a localização do arquivo bt.h; -std=c++17 define o padrão C++.)
Em seguida, compile o analisador/gerador binário:
g++ -c -I . -std=c++17 -g -O3 -Wall gif.cpp
Finalmente, vincule o analisador/gerador binário com o driver de linha de comando para obter um executável. Se você usar bibliotecas extras (como -lz), certifique-se de especificá-las aqui também.
g++ -O3 gif.o fuzzer.o -o gif-fuzzer -lz
O FormatFuzzer pode ser executado como um analisador, gerador ou mutador autônomo de formatos específicos. Além disso, ele pode ser chamado por fuzzers de propósito geral como AFL++ para integrar essas capacidades específicas de formato no processo de fuzzing (veja a seção abaixo sobre integração com AFL++).
O fuzzer gerado recebe um comando como primeiro argumento, seguido por opções e argumentos para esse comando.
O comando mais importante é fuzz, para produzir saídas. Seus argumentos são arquivos a serem gerados no formato apropriado.
Execute o gerador como
./gif-fuzzer fuzz output.gif
para criar um arquivo binário aleatório output.gif, ou
./gif-fuzzer fuzz out1.gif out2.gif out3.gif
para criar três arquivos GIF out1.gif, out2.gif e out3.gif.
Observe que o template gif.bt que fornecemos foi aumentado com funções especiais para facilitar a geração de arquivos válidos. Se você usar arquivos de template .bt originais sem adaptações, pode receber avisos durante a geração e criar arquivos inválidos.
Você também pode executar o fuzzer como um analisador para arquivos binários, usando o comando parse. Isso é útil se você quiser testar a precisão do template binário, ou se quiser mutar uma entrada (veja 'Arquivos de Decisão', abaixo).
Para executar o analisador, use
./gif-fuzzer parse input.gif
Você verá mensagens de erro se input.gif não puder ser analisado com sucesso.
Ao analisar, você também pode armazenar todas as decisões de análise (ou seja, quais alternativas de análise foram tomadas) em um arquivo de decisão. Esta é uma sequência de bytes enumerando as decisões tomadas.
Cada byte representa uma única decisão de análise. Um valor de byte 0 significa que a primeira alternativa foi tomada, um valor de byte 1 significa que a segunda alternativa foi tomada, e assim por diante.
Você pode gerar esse arquivo de decisão ao analisar uma entrada:
./gif-fuzzer parse --decisions input.dec input.gif
Aqui, input.dec armazena as decisões tomadas para analisar input.gif.