Files
url.c/tests/FUZZING.md
T
Claude bd0a0f0c26 Add comprehensive fuzzing infrastructure for URL parser
This commit adds AFL++ (American Fuzzy Lop) fuzzing support to help find bugs,
crashes, and security vulnerabilities in the URL parser.

Changes:
- Add fuzz_afl.c: AFL++ fuzz target that tests all parser functions
  - url_parse() with different flag combinations
  - url_parse_ipv4() and url_parse_ipv6()
  - url_serialize(), url_percent_decode(), url_remove_white_space()

- Add build_afl.sh: Build script with AFL++ compiler detection
- Add run_afl.sh: Automated fuzzing script with result reporting
- Add url.dict: Dictionary file to guide AFL++ mutations

- Add corpus/: Seed inputs covering various URL patterns
  - Basic URLs, IPv4/IPv6, percent-encoding, relative paths
  - Edge cases and special schemes (file://, mailto:, etc.)

- Add FUZZING.md: Comprehensive documentation
  - Installation instructions
  - Quick start guide
  - Advanced usage (parallel fuzzing, sanitizers)
  - Troubleshooting tips

- Add fuzz.c: Standalone mutation-based fuzzer (no AFL++ required)
  - Useful for quick testing without installing AFL++
  - Implements various mutation strategies
2025-12-06 15:23:32 +00:00

5.2 KiB

Fuzzing the URL Parser

This directory contains fuzzing infrastructure for the URL parser using AFL++ (American Fuzzy Lop).

What is Fuzzing?

Fuzzing is an automated testing technique that feeds malformed, unexpected, or random data to a program to find bugs, crashes, and security vulnerabilities. AFL++ is a coverage-guided fuzzer that intelligently mutates inputs to maximize code coverage.

Prerequisites

Install AFL++

Ubuntu/Debian:

sudo apt-get update
sudo apt-get install afl++

From source:

git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus
make
sudo make install

Quick Start

  1. Build the fuzz target:

    cd tests/
    ./build_afl.sh
    
  2. Run fuzzing:

    ./run_afl.sh
    

    Or run for a specific duration:

    ./run_afl.sh 60  # Run for 60 minutes
    
  3. View results:

    • Crashes: findings/default/crashes/
    • Hangs: findings/default/hangs/
    • Interesting inputs: findings/default/queue/

Directory Structure

tests/
├── fuzz_afl.c          # AFL++ fuzz target
├── build_afl.sh        # Build script
├── run_afl.sh          # Run script
├── corpus/             # Seed inputs
│   ├── basic.txt
│   ├── complex.txt
│   ├── ipv4.txt
│   ├── ipv6.txt
│   └── ...
└── findings/           # AFL++ output (created when running)
    └── default/
        ├── crashes/    # Inputs that caused crashes
        ├── hangs/      # Inputs that caused timeouts
        └── queue/      # All interesting inputs found

What Gets Tested

The fuzz target tests multiple parser functions:

  • url_parse() - Main URL parser (with different flag combinations)
  • url_parse_ipv4() - IPv4 address parser
  • url_parse_ipv6() - IPv6 address parser
  • url_serialize() - URL serialization
  • url_percent_decode() - Percent-decoding
  • url_remove_white_space() - Whitespace removal

Analyzing Results

Reproducing Crashes

If AFL++ finds a crash, you can reproduce it:

./fuzz_afl < findings/default/crashes/id:000000,*

Or use a debugger:

gdb ./fuzz_afl
(gdb) run < findings/default/crashes/id:000000,*

Minimizing Crash Inputs

AFL++ can minimize crash inputs to their smallest form:

afl-tmin -i findings/default/crashes/id:000000,* -o minimized.txt -- ./fuzz_afl

Viewing Statistics

While fuzzing is running, AFL++ displays real-time statistics:

  • Cycles done: Number of times the fuzzer went through the queue
  • Corpus count: Number of interesting test cases found
  • Crashes: Number of unique crashes found
  • Exec speed: Fuzzing throughput (executions per second)

Advanced Usage

Parallel Fuzzing

Run multiple AFL++ instances in parallel for better coverage:

# Terminal 1 (master)
afl-fuzz -i corpus/ -o findings/ -M fuzzer1 -- ./fuzz_afl

# Terminal 2 (secondary)
afl-fuzz -i corpus/ -o findings/ -S fuzzer2 -- ./fuzz_afl

# Terminal 3 (secondary)
afl-fuzz -i corpus/ -o findings/ -S fuzzer3 -- ./fuzz_afl

Using Different Modes

AFL++ supports various mutation modes:

# Explore mode (default)
afl-fuzz -i corpus/ -o findings/ -- ./fuzz_afl

# Exploitation mode (focus on found crashes)
afl-fuzz -i corpus/ -o findings/ -p exploit -- ./fuzz_afl

# COE (Continue on Error) mode
afl-fuzz -i corpus/ -o findings/ -c -- ./fuzz_afl

With AddressSanitizer (ASAN)

For better bug detection, rebuild with AddressSanitizer:

AFL_USE_ASAN=1 ./build_afl.sh
./run_afl.sh

Note: ASAN significantly slows down fuzzing but can detect memory issues that wouldn't cause crashes.

With UndefinedBehaviorSanitizer (UBSAN)

To detect undefined behavior:

AFL_USE_UBSAN=1 ./build_afl.sh
./run_afl.sh

Performance Tips

  1. Disable CPU frequency scaling:

    echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
    
  2. Increase system limits:

    sudo sysctl -w kernel.core_pattern=core
    sudo sysctl -w kernel.sched_child_runs_first=1
    
  3. Use persistent mode (requires code changes to fuzz target)

  4. Use dictionary files for better mutations:

    afl-fuzz -i corpus/ -o findings/ -x url.dict -- ./fuzz_afl
    

Continuous Fuzzing

For long-term fuzzing campaigns:

# Run in screen/tmux
screen -S fuzzing
./run_afl.sh

# Detach: Ctrl+A, D
# Reattach: screen -r fuzzing

Or use a systemd service for continuous fuzzing.

Troubleshooting

"No instrumentation detected"

Make sure you built with an AFL++ compiler (afl-gcc, afl-clang-fast, etc.)

"Suboptimal CPU scaling governor"

Run as suggested by AFL++ or set AFL_SKIP_CPUFREQ=1

Low execution speed

  • Close other programs
  • Use afl-clang-fast instead of afl-gcc
  • Consider using QEMU mode for uninstrumented binaries

No new paths found

  • Add more diverse seed inputs to corpus/
  • Try different mutation strategies
  • Consider parallel fuzzing

References