Fuzzing é uma técnica de teste que envia automaticamente entradas inesperadas a um software para encontrar falhas. Esta página explica como ela funciona e como começar com o seu próprio código (não aborda o teste de sistemas de terceiros).
O que é fuzzing
A OWASP descreve o fuzzing como uma técnica de teste de software voltada a identificar bugs, vulnerabilidades ou comportamentos inesperados. Ela fornece automaticamente entradas inválidas, inesperadas ou parcialmente inválidas e observa se o programa se comporta mal. O glossário do NIST (citando o NIST SP 800-95) também descreve o fuzz testing como ferramentas chamadas fuzzers que submetem combinações de entradas a um alvo de teste para revelar como ele responde.
Sua força está em fazer poucas suposições sobre como o sistema deveria se comportar. Testes escritos manualmente cobrem apenas os casos que alguém imaginou. Um fuzzer pode encontrar pontos que quebram com entradas que ninguém imaginou.
Como funciona
A maioria dos fuzzers modernos é guiada por cobertura. Eles medem quais trechos de código foram executados, mantêm as entradas que alcançaram código novo e as modificam para criar as próximas. Isso chega mais fundo no programa do que entradas aleatórias sozinhas. O libFuzzer, do LLVM, é documentado como um motor de fuzzing evolutivo, guiado por cobertura e executado no próprio processo, vinculado à biblioteca em teste.
Ferramentas comuns
| Ferramenta | Alvos principais | Observações |
|---|---|---|
| libFuzzer | C/C++ e outras (LLVM) | Vinculado ao alvo. Segundo sua documentação, os autores originais passaram para o motor Centipede e ele agora recebe apenas correções de bugs importantes |
| AFL++ | C/C++ e outras | Um fuzzer guiado por cobertura muito usado |
| Fuzzing integrado do Go | Go (1.18 ou superior) | Execute com go test -fuzz. As entradas que falharam são salvas em testdata e reexecutadas pelos testes normais |
| OSS-Fuzz | Software de código aberto | Serviço gratuito e contínuo de fuzzing do Google, usando vários motores e sanitizers |
Um fuzz target do libFuzzer é uma função (LLVMFuzzerTestOneInput) que recebe os bytes da entrada e seu tamanho. Em Go, você escreve uma função de teste chamada FuzzXxx que recebe um *testing.F e adiciona entradas iniciais com f.Add.
Como começar no seu próprio software
- Escolha uma função que faça o parsing de entradas (um parser de formato de arquivo, um carregador de configuração, um manipulador de protocolo)
- Escreva um fuzz target pequeno que apenas passe a entrada para ela. Mantenha-o rápido e determinístico, sem estado carregado entre chamadas
- Adicione algumas entradas válidas típicas como seeds
- Ative um sanitizer, como o AddressSanitizer, e execute por um tempo definido (em Go,
-fuzztimedefine a duração) - Transforme cada entrada que falhou em um teste reproduzível e mantenha-o como teste de regressão após a correção
- Para continuar, execute sessões curtas no CI ou, para código aberto, considere participar do OSS-Fuzz
O fuzzing em Go tem um limite de 1 segundo por execução, e a orientação por cobertura funciona em AMD64 e ARM64. Consulte a documentação oficial para conhecer os limites do seu ambiente.
Faça fuzzing apenas em software que você gerencia
O fuzzing envia continuamente grandes volumes de entradas malformadas. Fazer isso em um serviço ou servidor para o qual você não tem permissão de teste pode ser considerado acesso não autorizado ou interrupção de serviço. Limite-o a software que você desenvolve ou gerencia, em ambiente próprio.
O que ele pode e não pode fazer
A OWASP afirma que o fuzzing complementa, e não substitui, a revisão manual de código e a depuração. Também observa que os fuzzers tendem a encontrar bugs simples e que, com o teste de caixa-preta, é mais difícil avaliar o impacto de um achado.
Assim, o fuzzing é forte em "deixar uma máquina procurar formas de o código quebrar" e fraco em problemas de design, como a falta de autorização. Para esses casos, como o IDOR, conte com testes que verifiquem as regras pretendidas.
Visão deste site: encontrar a entrada é metade do trabalho; mantenha-a como teste de regressão
O que importa não é apenas rodar um fuzzer, mas salvar o que ele encontra como teste de regressão. O fuzzing integrado do Go, que armazena uma entrada que falhou em testdata e a reexecuta nos testes normais, segue essa ideia. Ele evita que um bug corrigido volte em uma alteração posterior. Se você é responsável por código que faz o parsing de entradas, um primeiro passo realista é fazer fuzzing de uma única função.
Fontes (primárias)
- OWASP Community, "Fuzzing" — owasp.org (definição, características, limites)
- NIST CSRC Glossary, "fuzz testing" — csrc.nist.gov (fonte: NIST SP 800-95)
- LLVM, "libFuzzer" — llvm.org (funcionamento, fuzz target, status de manutenção)
- Go, "Fuzzing" — go.dev (Go 1.18 ou superior, como executar, limites)
- Google, "OSS-Fuzz" — google.github.io (visão geral, motores suportados). Os números de bugs mudam com o tempo, por isso nenhum é citado aqui. Para o AFL++, consulte a documentação oficial para o uso atual