Perform coverage-guided fuzzing of compiled binaries using AFL++ (American Fuzzy Lop Plus Plus) to discover memory corruption, crashes, and security vulnerabilities.
Installs into .claude/skills of the current project.
Are you the author of Re Performing Fuzzing With Aflplusplus?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/bitbytelabio-re-performing-fuzzing-with-aflplusplus)
---
name: re-performing-fuzzing-with-aflplusplus
description: Perform coverage-guided fuzzing of compiled binaries using AFL++ (American Fuzzy Lop Plus Plus) to discover memory corruption, crashes, and security vulnerabilities.
domain: re
category: exploitation
hide: true
license: Apache-2.0
metadata:
manifest_entry: src/corpus/re-performing-fuzzing-with-aflplusplus/SKILL.md
---
# Performing Fuzzing with AFL++
## Overview
AFL++ is a community-maintained fork of American Fuzzy Lop (AFL) that provides coverage-guided
fuzzing for compiled binaries. It instruments targets at compile time or via QEMU/Unicorn mode
for binary-only fuzzing, then mutates input corpora to discover new code paths. AFL++ includes
advanced scheduling (MOpt, rare), custom mutators, CMPLOG for input-to-state comparison solving,
and persistent mode for high-throughput fuzzing.
## When to Use
- When conducting security assessments that involve performing fuzzing with aflplusplus
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
## Common Misconfigurations & Verification
A campaign that runs for hours with zero crashes is usually a setup problem, not a secure target.
- **No sanitizer, so bugs go silent:** instrument with `AFL_USE_ASAN=1 afl-cc` (or `afl-clang-fast`). Without ASAN/UBSAN a heap overflow corrupts memory without crashing and AFL++ never flags it.
- **Empty or trivial seed corpus:** starting `-i` with one tiny file leaves the fuzzer unable to reach parser logic. Provide diverse valid inputs, then prune with `afl-cmin`, and shrink each with `afl-tmin`.
- **No dictionary for structured formats:** without `-x dict/` (magic bytes, keywords, tokens) AFL++ wastes cycles guessing format headers. Supply a format dictionary.
- **Single-core run wastes the box:** use `-M main` + several `-S sec1 sec2 ...` secondaries to fuzz in parallel and share finds via the sync dir.
- **Coverage stall ignored:** `map density` flat and `pending` near zero for hours means saturation — add CMPLOG (`-c`), MOpt, or new seeds rather than letting it spin.
**Verify the harness can actually find bugs:** compile a build with a planted bug (e.g. an unchecked `strcpy` on input) and confirm AFL++ surfaces it in `crashes/` within minutes and that `afl-tmin` + CASR/GDB reproduce it. If the planted bug is never found, fix instrumentation/seeds before trusting a clean run.
## Prerequisites
- AFL++ installed (`apt install afl++` or build from source)
- Target binary source code (for compile-time instrumentation) or QEMU mode for binary-only
- Initial seed corpus of valid inputs for the target format
- Linux system with /proc/sys/kernel/core_pattern configured
## Steps
1. Instrument the target binary with `afl-cc` or `afl-clang-fast`
2. Prepare seed corpus directory with minimal valid inputs
3. Minimize corpus with `afl-cmin` to remove redundant seeds
4. Run `afl-fuzz` with appropriate flags (-i input -o output)
5. Monitor fuzzing progress via afl-whatsup and UI stats
6. Triage crashes with `afl-tmin` minimization and CASR/GDB analysis
7. Report unique crashes with reproduction steps
## Crash Triage: One Root Cause = One Vulnerability
A `crashes/` directory full of files is raw material, not a findings list. Multiple crash files frequently share a single root cause — reporting each file separately inflates the count and hides real severity.
```
crash file
-> reproduce (rerun the input under the same instrumented binary; a crash that will not reproduce is noise)
-> minimize (afl-tmin / CASR to shrink the input to the smallest trigger)
-> trace (run under ASAN/UBSAN or GDB to capture the faulting instruction, sanitizer report, and stack)
-> root-cause (group every crash that hits the same fault site / sanitizer origin into ONE root cause)
-> exploitability (write violation? control of PC? allocator metadata corruption? OOB read only?)
-> finding (report one deduplicated root cause with a PoC input, trace, and an exploitability assessment)
```
Rules:
- N crash files reduced to one root cause is **one** vulnerability — but report its true severity (PC-control beats off-by-one read).
- An OOB read with no disclosure path is a memory-safety bug, not automatically a critical finding — say what the primitive is.
- Hangs and slow paths are coverage/DoS observations; only triage them as findings if a deadlock or unbounded allocation is demonstrated.
- A crash reachable only with a physically impossible input (e.g., a magic length that also fails format checks earlier) still needs a reachable path from the real entry point.
## Expected Output
```
+++ Campaign +++
map density: 4.23% / 8.41%
paths found: 1847
exec speed: 2145/sec
+++ Triage +++
raw crash files: 12
reproducible: 9
unique root causes: 3
#1 heap overflow in parse_header (ASAN) - write primitive, PC influence likely
#2 OOB read in decode_frame (UBSAN) - info-leak candidate
#3 infinite loop in skip_metadata - hang, not a crash
```