Aprende › Vulnerabilidades web

Fuzzing moderno: AFL++, libFuzzer, honggfuzz y coverage-guided

· 9 min de lectura

El fuzzing coverage-guided ha transformado el descubrimiento de bugs: miles de CVEs al año atribuibles a AFL++, libFuzzer, honggfuzz, OSS-Fuzz. Aprende las técnicas modernas, harness design, grammar-based fuzzing, structure-aware mutations y cómo integrar fuzzing en CI/CD moderno.

El fuzzing (feed random/mutated inputs to find bugs) ha evolucionado desde dumb fuzzing de los años 90 hasta sofisticados coverage-guided fuzzers modernos que han descubierto miles de CVEs solo en 2020-2026. Herramientas como AFL++, libFuzzer, honggfuzz, combinadas con platforms como OSS-Fuzz (Google) manteniendo continuous fuzzing en critical open-source infrastructure, han transformado software security. Google reports attribution 30%+ Chrome bugs y Linux kernel bugs encontrados vía fuzzing. Para security researchers y product security teams, fuzzing es ahora essential en workflow, no optional.

Esta lección cubre fundamentos del coverage-guided fuzzing, herramientas principales (AFL++, libFuzzer, honggfuzz), harness design, grammar-based y structure-aware fuzzing, integration CI/CD (CIFuzz, OSS-Fuzz para open source), y effective workflows. Es la cuarta lección de la Tanda 7.

Fuzzing on own software or open source con proper responsible disclosure. Fuzzing commercial production sin authorization puede violate ToS.

Dumb vs coverage-guided#

Dumb fuzzing: pure random inputs vs Coverage-guided: feedback loop based en execution paths
Dumb fuzzing: pure random inputs vs Coverage-guided: feedback loop based en execution paths

Dumb fuzzing (1990s):

  • Send random/malformed inputs.
  • Observe crashes.
  • Limited insight into program state.

Simple, pero ineffective en modern programs. Most inputs rejected early en parsing, never reach deeper logic.

Coverage-guided fuzzing (AFL 2013+):

  • Instrument binary to track code paths executed.
  • Each input scored: does it reach new code?
  • Mutate inputs reaching new coverage.
  • Prioritize interesting inputs.

Result: fuzzer guided toward bug-prone deep code. Orders of magnitude more effective.

Michał Zalewski's AFL (2013) introduced technique, revolutionized field.

AFL++#

AFL++ community fork desde 2019, actively maintained. Standard coverage-guided fuzzer.

# Install
git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus && make distrib && sudo make install

# Compile target with AFL++ instrumentation
export CC=afl-clang-fast
export CXX=afl-clang-fast++
./configure && make

# Run
afl-fuzz -i inputs/ -o findings/ -- ./target @@

Workflow:

  • Instrument target durante compilation.
  • Provide initial seed inputs.
  • Fuzzer mutates + executes.
  • Tracks new coverage, saves inputs triggering.
  • Logs crashes + hangs.

Years of tuning: deterministic mutations, havoc mode, dictionary support, CMPLog (compare instructions guidance), REDQUEEN (input-to-state correspondence).

libFuzzer#

libFuzzer (LLVM project) in-process fuzzer. Links directly to target, runs mutation loop within same process. Faster que AFL++ for small units.

// Harness: libfuzzer-compatible
#include <stdint.h>
#include <stddef.h>

extern int target_function(const uint8_t *data, size_t size);

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    target_function(data, size);
    return 0;
}

Compile + run:

clang -fsanitize=fuzzer,address -g harness.c target.c -o fuzzer
./fuzzer -max_total_time=3600

Required for OSS-Fuzz. Standard for unit-level fuzzing.

honggfuzz#

honggfuzz (Google) alternative, different techniques:

  • Hardware-based coverage (Intel PT).
  • Persistent fuzzing mode.
  • Sanitizer integration.

Used internally Google. Less community adoption than AFL++ but effective.

OSS-Fuzz: continuous fuzzing#

OSS-Fuzz (Google 2016) runs fuzzers continuously against hundreds of open-source projects. Free service for qualifying OSS. Found 30,000+ bugs total.

Setup:

  • Write Dockerfile + build.sh + fuzzer harness.
  • Submit PR to OSS-Fuzz repo.
  • Google runs continuous fuzzing on their infrastructure.
  • Bugs reported to maintainers via private tracker.
  • Bug bounty program rewards critical findings.

For OSS projects: free security benefit.

Harness design#

Harness = adapter from fuzzer input to target function. Critical para effectiveness.

Simple harness#

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size < 10) return 0;  // Minimum size check
    MyParser parser;
    parser.parse(data, size);
    return 0;
}

Stateful target harness#

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Setup
    Connection conn = create_connection();
    
    // Split input into operations
    size_t offset = 0;
    while (offset < size - 2) {
        uint8_t op = data[offset++];
        uint8_t len = data[offset++];
        if (offset + len > size) break;
        
        switch (op & 0xF) {
            case 0: conn.send(data + offset, len); break;
            case 1: conn.recv(data + offset, len); break;
            // ...
        }
        offset += len;
    }
    
    conn.close();
    return 0;
}

Harness design is art. Target too narrow → shallow coverage. Too broad → inefficient.

Sanitizers#

Sanitizers: ASan, MSan, UBSan, TSan catch different bug classes
Sanitizers: ASan, MSan, UBSan, TSan catch different bug classes

Fuzzing without sanitizers misses silent bugs. Sanitizers (compile-time instrumentation) detect:

  • AddressSanitizer (ASan): out-of-bounds, use-after-free, memory leaks.
  • MemorySanitizer (MSan): uninitialized reads.
  • UndefinedBehaviorSanitizer (UBSan): integer overflow, null deref, misalignment.
  • ThreadSanitizer (TSan): data races.

Compile con -fsanitize=address,undefined. Sanitizer crash → bug found. Essential para fuzzing.

Structure-aware fuzzing#

Random mutation struggles con structured inputs (PDF, PNG, JSON, protobuf). Structure-aware fuzzing uses grammar/schema:

libprotobuf-mutator#

Fuzzer mutates protobuf messages maintaining schema validity:

DEFINE_PROTO_FUZZER(const MyMessage& msg) {
    target_function(msg);
}

Mutations respect message structure, finds deep bugs.

Grammar-based fuzzers#

  • Nautilus: context-free grammar input.
  • FormatFuzzer: 010 Editor templates as grammar.
  • Gramatron: automaton-based grammar fuzzing.

Essential para language processors, protocol parsers, etc.

Kernel fuzzing: syzkaller#

syzkaller (covered en kernel lesson) applies principles to kernel. Specialized because:

  • Kernel crashes = system reboot.
  • Need VM-based testing.
  • Syscall grammar description.

Dominant Linux kernel bug discovery tool 2017+.

Protocol fuzzing#

Network protocol parsers vulnerable. Specialized tools:

  • Boofuzz: generation-based protocol fuzzer.
  • AFLnet: AFL adapted para stateful protocols.
  • Peach Fuzzer: commercial, enterprise-focused.

For custom protocols, often harness design matters more than tool choice.

CI/CD integration#

CIFuzz (OSS-Fuzz): run fuzzer briefly en each PR. Catches regression quickly.

GitHub Actions template:

- name: Build Fuzzers
  uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
  with:
    oss-fuzz-project-name: 'myproject'
- name: Run Fuzzers
  uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
  with:
    oss-fuzz-project-name: 'myproject'
    fuzz-seconds: 600

Para private projects, self-hosted options include Mayhem (comercial, Forrester-backed).

Common patterns#

Corpus minimization#

Large corpus slow fuzzing. Minimize while preserving coverage:

afl-cmin -i corpus_large/ -o corpus_min/ -- ./target @@

Dictionary#

AFL supports token dictionaries (magic bytes, keywords). Improves coverage:

# JPEG dictionary
"\xff\xd8\xff"
"EXIF"
"JFIF"

Parallel fuzzing#

Multiple cores running different strategies:

afl-fuzz -M main -i inputs/ -o out/ -- ./target @@
afl-fuzz -S secondary1 -i inputs/ -o out/ -- ./target @@
# etc

Common findings#

Typical bugs found via fuzzing:

  • Memory corruption: OOB, UAF, double-free.
  • Integer overflows: size calculations.
  • Infinite loops / DoS.
  • Divide by zero.
  • Null pointer derefs.
  • Format strings.
  • Logic bugs (with careful harness).

Case studies#

  • FFmpeg: thousands of CVEs found via fuzzing durante años.
  • SQLite: comprehensive fuzzing part de development.
  • LibreOffice: continuous fuzzing catches document parser bugs.
  • OpenSSL: fuzzing post-Heartbleed intensified.
  • Linux kernel: syzkaller + fuzzer competitions find hundreds annually.

Workflow práctico#

Para fuzz targeted codebase, flujo canónico:

Day 1-3: setup:

  • Identify attack surface (parsers, deserialization, network handlers).
  • Write minimal harness cada target.
  • Build con instrumentation + sanitizers.
  • Prepare initial corpus (sample valid inputs).

Day 4-7: initial fuzzing:

  • Run AFL++ o libFuzzer.
  • Monitor coverage growth.
  • Debug harness issues (crashes en setup, not target).
  • Iterate harness.

Week 2+: sustained fuzzing:

  • 24x7 execution.
  • Monitor stats: execs/sec, coverage, corpus size.
  • Investigate crashes: dedup, triage severity.
  • Expand corpus from interesting findings.

Ongoing: integration:

  • CI/CD short runs per PR.
  • Nightly extended runs.
  • Dedicated fuzzing infrastructure if scale warrants.

Benefits compound: initial bugs discovered first weeks. Long-term fuzzing finds subtle bugs regular review misses.

Industry adoption#

Major organizations invest heavily:

  • Google: OSS-Fuzz plus internal fuzzing infrastructure.
  • Microsoft: OneFuzz platform (deprecated 2023, moved internal).
  • Mozilla: Firefox fuzzing continuously.
  • Apple: iOS fuzzing significant although less public.
  • Government agencies: NSA Ghidra integrates, DARPA CGC pioneered.

For smaller orgs: use CIFuzz free tier, dedicate week quarterly for focused fuzzing campaigns. ROI typically positive.

Preguntas frecuentes#

¿Fuzzing vs symbolic execution?#

Complementary. Fuzzing fast, broad coverage. Symbolic (angr, Mayhem) precise but slower. Hybrid approaches combine: Driller, SAGE.

¿Vale la pena para webapps?#

Partial. REST fuzzers (RESTler), GraphQL fuzzers (EvoMaster) exist. Less mature que binary fuzzing but growing.

¿Cuánto tiempo ejecutar?#

Minimum hours per harness. Continuous (OSS-Fuzz) ideal. Returns diminish log(time) typically.

¿Reporting bugs found?#

Follow responsible disclosure. Vendor security program, Linux distros mailing list, embargo 90 days típicamente.

¿Cuánto paga bug bounty for fuzzer-found bugs?#

Same as manually discovered typically. Google bugSWAT program specifically rewards fuzzing contributions.

¿Dónde practico?#

El laboratorio red-hat de whoami-labs incluye intentional vulnerable binaries para fuzzer practice: parser bugs, memory corruption, infinite loops. Build harnesses + run AFL++/libFuzzer y find bugs.

¿AI-based fuzzing futuro?#

Research activo. ML-guided mutation, LLM generating harnesses, neural network coverage prediction. Promising pero traditional coverage-guided sigue dominant 2026.

¿Vale carrera en fuzzing?#

Yes. Combination research + engineering. Vendors contratan fuzzing engineers. Bug bounty specialists usan fuzzing complement to manual analysis.

¿Hardware fuzzing para IoT?#

Emerging. Firmware fuzzing con QEMU emulation. Specialized tools (Avatar, FirmFuzz). Harder than user-space debido hardware dependencies.

¿Cómo evitar duplicate findings?#

Stacktrace-based dedup. ASan reports clustering. Minimization: find smallest input reproducing. Essential for triage efficiency.

¿Mayhem (commercial) vs OSS-Fuzz?#

Mayhem: enterprise commercial, symbolic+fuzzing hybrid. OSS-Fuzz: free para OSS, Google-run infrastructure. Different markets. Both effective.

Resumen#

  • Fuzzing: feed inputs to find bugs. Modern coverage-guided revolutionized effectiveness.
  • AFL++: standard coverage-guided fuzzer. Mature, feature-rich.
  • libFuzzer: in-process LLVM fuzzer. Required for OSS-Fuzz.
  • honggfuzz: alternative con hardware-based coverage.
  • OSS-Fuzz: Google's continuous fuzzing for open source. 30k+ bugs.
  • Sanitizers (ASan, MSan, UBSan, TSan): detect silent bugs.
  • Structure-aware: grammar/schema-based for complex formats.
  • CI/CD integration: CIFuzz para GitHub Actions.

Bugs famosos descubiertos via fuzzing#

Historical highlights illustrating technique's value:

  • Heartbleed (2014): not fuzzing discovered but subsequently extensive fuzzing OpenSSL.
  • Shellshock (2014): Bash fuzzing after discovery found related bugs.
  • ImageTragick (2016): ImageMagick convert vulnerabilities fuzzing.
  • Multiple Linux kernel bugs: syzkaller finds hundreds annually.
  • FFmpeg CVEs: thousands over years, fuzzing primary source.
  • SQLite extensive bugs: Rich Hipp documented fuzzing campaign.
  • Firefox/Chrome rendering engines: constant fuzzing yields CVEs.
  • Protocol bugs (OpenSSH, Postfix): targeted fuzzing campaigns.

Each case educational. Writeups often public with harness code, demonstrating practice.

Future developments#

Trends 2026-2030:

  • AI-assisted fuzzing: LLMs generating harnesses, ML-guided mutations.
  • Distributed fuzzing: cloud-scale infrastructure.
  • Hybrid approaches: symbolic + fuzzing + static analysis combined.
  • Embedded/IoT focus: hardware emulation improving.
  • Supply chain: continuous fuzzing of dependencies.
  • Formal verification complement: proven correct fuzzed systems.

Fuzzing remains cornerstone security practice. Investment continues from major vendors, academia, government. Cualquier serious security practitioner should have working knowledge y hands-on experience en el toolkit canónico de la disciplina moderna.

Metrics y effectiveness#

Measuring fuzzing effectiveness requires understanding metrics:

  • Executions per second: throughput indicator.
  • Coverage (lines, branches, edges): breadth of exploration.
  • Unique crashes: potential bugs discovered.
  • Time to first crash: initial effectiveness.
  • Corpus size: inputs preserved for continued fuzzing.

Modern fuzzers report real-time metrics. Visualization tools (AFLplusplus-stats, libfuzzer-reports) aid interpretation. Comparing fuzzing campaigns requires normalization: same corpus, same target, same time budget.

Industry benchmarks exist for common targets. FuzzBench (Google) standardizes comparison. Independent research publishes relative effectiveness studies annually.

Cost-benefit#

For organizations deciding fuzzing investment:

  • OSS-Fuzz free for qualifying open source projects. ROI immediate.
  • Internal fuzzing infrastructure: 100k-500k USD initial setup, 50k+/year operations. Justifies for product companies.
  • Commercial platforms (Mayhem, ForAllSecure): subscription models starting ~50k USD/year.

Break-even calculation: if fuzzing finds 10 bugs annually saving 50k USD each in post-release cost → 500k USD value. Investment justified for many organizations.

La próxima lección entra en reverse engineering con Ghidra, la herramienta libre más potente para análisis estático de binaries, donde fuzzing deja huecos útiles para análisis humano profundo combinando ambas disciplinas de forma complementaria durante investigaciones técnicas serias sobre binaries complejos de software comercial opaco de vendors sin disponibilidad de source code para los researchers independientes trabajando por bug bounties o compensación directa en estudios técnicos de alta complejidad técnica técnica y relevancia industrial medible para el sector concreto específico del cliente final buscando resultados concretos de alto impacto comercial inmediato y sostenido durante años.

Fuentes y lecturas recomendadas#

Practícalo en estos laboratorios

Ver todos los laboratorios de esta categoría