Fuzzing Tools and Techniques
Fuzzing (fuzz testing) automatically generates and injects malformed or unexpected inputs to find bugs, crashes, and security vulnerabilities.
Overview
Fuzzing is an automated software testing technique that provides invalid, unexpected, or random data as inputs to a program.
Goals:
- Find crashes and hangs
- Discover memory corruption bugs
- Identify security vulnerabilities
- Test error handling
- Improve code coverage
Types of Fuzzing
1. Black-Box Fuzzing
No knowledge of internal structure.
1Input → [Program] → Monitor for crashes
Tools: Radamsa, zzuf, Peach Fuzzer
2. White-Box Fuzzing
Uses program analysis and symbolic execution.
1Input → [Analyze Code] → Generate targeted inputs → Test
Tools: KLEE, Driller, Mayhem
3. Grey-Box Fuzzing
Uses lightweight instrumentation for feedback.
1Input → [Instrumented Program] → Coverage feedback → Mutate input
Tools: AFL, AFL++, LibFuzzer, Honggfuzz
AFL (American Fuzzy Lop)
Most popular coverage-guided fuzzer.
Installation
1# Install AFL++
2git clone https://github.com/AFLplusplus/AFLplusplus
3cd AFLplusplus
4make
5sudo make install
6
7# Or via package manager
8sudo apt-get install afl++ # Debian/Ubuntu
9brew install afl++ # macOS
Basic Usage
1# 1. Compile target with AFL instrumentation
2afl-gcc -o target target.c
3# Or for C++
4afl-g++ -o target target.cpp
5
6# 2. Create input directory with seed files
7mkdir input
8echo "test" > input/seed1.txt
9echo "hello" > input/seed2.txt
10
11# 3. Create output directory
12mkdir output
13
14# 4. Run fuzzer
15afl-fuzz -i input -o output -- ./target @@
16# @@ is replaced with input filename
17
18# 5. Monitor results
19# AFL shows real-time stats in terminal
20# Crashes saved in output/crashes/
21# Hangs saved in output/hangs/
Example Target Program
1// vulnerable.c
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5
6void process_input(char *data) {
7 char buffer[16];
8
9 // Vulnerability: no bounds checking
10 if (data[0] == 'A' && data[1] == 'B') {
11 strcpy(buffer, data); // Buffer overflow!
12 }
13
14 // Another bug: integer overflow
15 int len = strlen(data);
16 if (len > 0) {
17 char *ptr = malloc(len - 1); // Can underflow!
18 free(ptr);
19 }
20}
21
22int main(int argc, char **argv) {
23 if (argc != 2) {
24 fprintf(stderr, "Usage: %s <input_file>\n", argv[0]);
25 return 1;
26 }
27
28 FILE *fp = fopen(argv[1], "r");
29 if (!fp) {
30 perror("fopen");
31 return 1;
32 }
33
34 char data[1024];
35 size_t len = fread(data, 1, sizeof(data) - 1, fp);
36 data[len] = '\0';
37 fclose(fp);
38
39 process_input(data);
40
41 return 0;
42}
1# Compile with AFL
2afl-gcc -o vulnerable vulnerable.c
3
4# Fuzz
5mkdir in out
6echo "test" > in/seed
7afl-fuzz -i in -o out -- ./vulnerable @@
8
9# AFL will find the buffer overflow when input starts with "AB"
Advanced AFL Options
1# Multiple cores (parallel fuzzing)
2afl-fuzz -i in -o out -M fuzzer1 -- ./target @@ # Master
3afl-fuzz -i in -o out -S fuzzer2 -- ./target @@ # Slave
4afl-fuzz -i in -o out -S fuzzer3 -- ./target @@ # Slave
5
6# With dictionary (for structured formats)
7afl-fuzz -i in -o out -x dict.txt -- ./target @@
8
9# Dictionary example (dict.txt)
10# keyword_http="GET"
11# keyword_http="POST"
12# keyword_http="HTTP/1.1"
13
14# Persistent mode (faster)
15# Requires modifying target to use __AFL_LOOP
16afl-fuzz -i in -o out -- ./target_persistent
17
18# QEMU mode (no source code needed)
19afl-fuzz -Q -i in -o out -- ./binary @@
Analyzing Crashes
1# Reproduce crash
2./target output/crashes/id:000000,sig:11,src:000000,op:havoc,rep:2
3
4# With Address Sanitizer for better diagnostics
5afl-gcc -fsanitize=address -o target_asan target.c
6./target_asan output/crashes/id:000000*
7
8# Minimize crashing input
9afl-tmin -i crash_input -o minimized -- ./target @@
10
11# Get crash statistics
12afl-whatsup output/
LibFuzzer
LLVM's in-process, coverage-guided fuzzer.
Basic Example
1// fuzz_target.cpp
2#include <stdint.h>
3#include <stddef.h>
4#include <string.h>
5
6// Vulnerable function
7void process_data(const uint8_t *data, size_t size) {
8 if (size >= 4) {
9 if (data[0] == 'F' &&
10 data[1] == 'U' &&
11 data[2] == 'Z' &&
12 data[3] == 'Z') {
13 // Trigger crash
14 char *ptr = nullptr;
15 *ptr = 0; // Null pointer dereference
16 }
17 }
18}
19
20// LibFuzzer entry point
21extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
22 process_data(data, size);
23 return 0;
24}
1# Compile with LibFuzzer
2clang++ -g -fsanitize=fuzzer,address fuzz_target.cpp -o fuzz_target
3
4# Run fuzzer
5./fuzz_target
6
7# With corpus directory
8mkdir corpus
9./fuzz_target corpus/
10
11# With options
12./fuzz_target -max_len=1024 -timeout=10 corpus/
13
14# Reproduce crash
15./fuzz_target crash-file
Advanced LibFuzzer
1// Custom mutator
2extern "C" size_t LLVMFuzzerCustomMutator(
3 uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) {
4 // Custom mutation logic
5 return Size;
6}
7
8// Custom crossover
9extern "C" size_t LLVMFuzzerCustomCrossOver(
10 const uint8_t *Data1, size_t Size1,
11 const uint8_t *Data2, size_t Size2,
12 uint8_t *Out, size_t MaxOutSize, unsigned int Seed) {
13 // Custom crossover logic
14 return 0;
15}
16
17// Initialize (runs once)
18extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
19 // Setup code
20 return 0;
21}
Honggfuzz
Security-oriented fuzzer with hardware-assisted feedback.
Installation
1# Install
2git clone https://github.com/google/honggfuzz
3cd honggfuzz
4make
5sudo make install
Usage
1# Compile target
2hfuzz-gcc target.c -o target
3# Or
4hfuzz-clang target.c -o target
5
6# Fuzz
7honggfuzz -i input_corpus -o output -- ./target ___FILE___
8
9# With sanitizers
10hfuzz-clang -fsanitize=address target.c -o target
11honggfuzz -i input -o output -- ./target ___FILE___
12
13# Persistent mode
14honggfuzz -i input -o output -P -- ./target
Protocol Fuzzing
HTTP Fuzzing with Wfuzz
1# Install
2pip install wfuzz
3
4# Fuzz URL parameters
5wfuzz -z file,wordlist.txt http://target.com/page?param=FUZZ
6
7# Fuzz POST data
8wfuzz -z file,payloads.txt -d "username=admin&password=FUZZ" \
9 http://target.com/login
10
11# Fuzz headers
12wfuzz -z file,xss.txt -H "User-Agent: FUZZ" http://target.com/
13
14# Multiple injection points
15wfuzz -z file,users.txt -z file,passes.txt \
16 -d "user=FUZZ&pass=FUZ2Z" http://target.com/login
17
18# Filter responses
19wfuzz -z range,1-1000 --hc 404 http://target.com/page?id=FUZZ
20
21# Common options:
22# --hc: Hide responses with code
23# --hl: Hide responses with lines
24# --hw: Hide responses with words
25# --hh: Hide responses with chars
Ffuf (Fast Web Fuzzer)
1# Install
2go install github.com/ffuf/ffuf@latest
3
4# Directory fuzzing
5ffuf -w wordlist.txt -u http://target.com/FUZZ
6
7# Virtual host fuzzing
8ffuf -w vhosts.txt -u http://target.com -H "Host: FUZZ.target.com"
9
10# POST data fuzzing
11ffuf -w wordlist.txt -X POST -d "username=admin&password=FUZZ" \
12 -u http://target.com/login
13
14# Recursive fuzzing
15ffuf -w wordlist.txt -u http://target.com/FUZZ -recursion
16
17# Match/filter responses
18ffuf -w wordlist.txt -u http://target.com/FUZZ \
19 -mc 200,301,302 \
20 -fs 1234 # Filter by size
21
22# Rate limiting
23ffuf -w wordlist.txt -u http://target.com/FUZZ -rate 100
Boofuzz (Network Protocol Fuzzing)
1# Install
2pip install boofuzz
3
4# Example: Fuzz HTTP server
5from boofuzz import *
6
7def main():
8 session = Session(
9 target=Target(
10 connection=TCPSocketConnection("127.0.0.1", 80)
11 ),
12 )
13
14 # Define HTTP request
15 s_initialize("http_get")
16 s_string("GET", fuzzable=False)
17 s_delim(" ", fuzzable=False)
18 s_string("/", fuzzable=True)
19 s_delim(" ", fuzzable=False)
20 s_string("HTTP/1.1", fuzzable=False)
21 s_static("\r\n")
22 s_string("Host:", fuzzable=False)
23 s_delim(" ", fuzzable=False)
24 s_string("localhost", fuzzable=True)
25 s_static("\r\n\r\n")
26
27 session.connect(s_get("http_get"))
28 session.fuzz()
29
30if __name__ == "__main__":
31 main()
Radamsa (General-Purpose Fuzzer)
1# Install
2git clone https://gitlab.com/akihe/radamsa.git
3cd radamsa
4make
5sudo make install
6
7# Generate fuzzed inputs
8echo "GET / HTTP/1.1" | radamsa
9
10# Generate multiple
11echo "test input" | radamsa -n 100 -o fuzz-%n.txt
12
13# Fuzz file
14radamsa input.txt -o output-%n.txt -n 1000
15
16# Use in pipeline
17cat valid_request.txt | radamsa | nc target.com 80
Structure-Aware Fuzzing
Protobuf Fuzzing
1// proto_fuzzer.cpp
2#include <libprotobuf-mutator/libfuzzer/libfuzzer_macro.h>
3#include "message.pb.h"
4
5DEFINE_PROTO_FUZZER(const MyMessage& message) {
6 // Process protobuf message
7 ProcessMessage(message);
8}
1# Compile
2clang++ -fsanitize=fuzzer,address proto_fuzzer.cpp \
3 message.pb.cc -lprotobuf -o proto_fuzzer
4
5# Run
6./proto_fuzzer
JSON Fuzzing
1# json_fuzzer.py
2import json
3import atheris
4import sys
5
6@atheris.instrument_func
7def test_json_parser(data):
8 try:
9 parsed = json.loads(data)
10 # Process parsed JSON
11 process_json(parsed)
12 except (json.JSONDecodeError, UnicodeDecodeError):
13 pass
14
15def main():
16 atheris.Setup(sys.argv, test_json_parser)
17 atheris.Fuzz()
18
19if __name__ == "__main__":
20 main()
Fuzzing Best Practices
1. Seed Corpus
1# Good seed corpus:
2# - Valid inputs that exercise different code paths
3# - Minimal but diverse
4# - Cover edge cases
5
6# Example for HTTP fuzzer
7mkdir corpus
8echo "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" > corpus/get.txt
9echo "POST / HTTP/1.1\r\nContent-Length: 0\r\n\r\n" > corpus/post.txt
10echo "OPTIONS / HTTP/1.1\r\n\r\n" > corpus/options.txt
2. Sanitizers
1# Address Sanitizer (memory errors)
2clang -fsanitize=address -g target.c -o target
3
4# Undefined Behavior Sanitizer
5clang -fsanitize=undefined -g target.c -o target
6
7# Memory Sanitizer (uninitialized memory)
8clang -fsanitize=memory -g target.c -o target
9
10# Thread Sanitizer (data races)
11clang -fsanitize=thread -g target.c -o target
12
13# Combine multiple
14clang -fsanitize=address,undefined -g target.c -o target
3. Coverage Analysis
1# Generate coverage report with AFL
2afl-cov -d output/ --live --coverage-cmd \
3 "cat AFL_FILE | ./target" \
4 --code-dir .
5
6# With LLVM coverage
7clang -fprofile-instr-generate -fcoverage-mapping target.c -o target
8LLVM_PROFILE_FILE="target.profraw" ./target input
9llvm-profdata merge -sparse target.profraw -o target.profdata
10llvm-cov show ./target -instr-profile=target.profdata
4. Continuous Fuzzing
1# .github/workflows/fuzzing.yml
2name: Continuous Fuzzing
3
4on:
5 push:
6 branches: [ main ]
7 schedule:
8 - cron: '0 0 * * *' # Daily
9
10jobs:
11 fuzz:
12 runs-on: ubuntu-latest
13 steps:
14 - uses: actions/checkout@v2
15
16 - name: Install AFL++
17 run: |
18 sudo apt-get update
19 sudo apt-get install -y afl++
20
21 - name: Build
22 run: |
23 afl-gcc -o target target.c
24
25 - name: Fuzz
26 run: |
27 mkdir -p in out
28 echo "seed" > in/seed
29 timeout 3600 afl-fuzz -i in -o out -- ./target @@
30
31 - name: Upload crashes
32 if: always()
33 uses: actions/upload-artifact@v2
34 with:
35 name: crashes
36 path: out/crashes/
Fuzzing Frameworks Comparison
| Tool | Type | Speed | Learning Curve | Best For |
|---|---|---|---|---|
| AFL++ | Grey-box | Fast | Medium | C/C++ programs |
| LibFuzzer | Grey-box | Very Fast | Low | In-process fuzzing |
| Honggfuzz | Grey-box | Fast | Medium | Security research |
| Boofuzz | Black-box | Slow | Low | Network protocols |
| Radamsa | Black-box | Fast | Very Low | Quick tests |
| OSS-Fuzz | Platform | N/A | High | Open source projects |
Common Vulnerabilities Found
Buffer Overflows
1// AFL will find this
2void vulnerable(char *input) {
3 char buf[16];
4 strcpy(buf, input); // No bounds check
5}
Integer Overflows
1// Fuzzer can trigger with large values
2void allocate(size_t size) {
3 if (size > 0) {
4 char *buf = malloc(size - 1); // Underflow!
5 }
6}
Format String Bugs
1// Fuzzer finds with %n%n%n...
2void log_message(char *msg) {
3 printf(msg); // Should be printf("%s", msg)
4}
Use-After-Free
1// Fuzzer triggers with specific input sequence
2void process(char *input) {
3 char *ptr = malloc(100);
4 free(ptr);
5 if (input[0] == 'X') {
6 strcpy(ptr, input); // Use after free!
7 }
8}
Further Reading
Related Snippets
- Vulnerability Scanning Tools
Tools and techniques for scanning web services and applications for security …