Complete Fuzzing Tutorial: From Zero to CVE Discovery
A complete beginner-to-expert guide to fuzzing. Every concept explained line-by-line. No shortcuts. No assumptions.
Philosophy
This is not a “quick start guide.” This is the resource you need if you want to actually understand fuzzing from first principles.
- Every line of code is explained
- Every concept builds on the previous one
- No “just run this command” — you’ll understand WHY
- Blog length doesn’t matter — depth does
If you’re coming from GitHub READMEs that say “just run afl-fuzz -i in -o out ./target” and you’re thinking “but WHY?” — this series is for you.
Phase 1 — The Mental Model (Foundation)
You cannot use tools effectively without understanding the underlying model. These blogs build your intuition from zero.
| # | Blog Title | What You’ll Understand |
|---|---|---|
| What Is Fuzzing and Why Does It Actually Work? | What Is Fuzzing and Why Does It Actually Work? | The fundamental question: why does throwing random data at a program find bugs? The mental model that makes everything else make sense. |
| How a Fuzzer Works: Mutations, Seeds, and Corpus Explained | How a Fuzzer Works: Mutations, Seeds, and Corpus Explained | Before touching AFL++ or any tool, understand the internal loop: how does a fuzzer decide what input to try next? What is a corpus? What is a seed? |
| The Taxonomy: Every Type of Fuzzing Explained | Black-box, grey-box, white-box, coverage-guided, mutation-based, generation-based. The complete map of fuzzing approaches. | |
| 4 | What Happens Inside a Program When It Crashes | Segmentation faults, stack traces, registers, memory corruption. You need to understand what a crash IS before you can find one. |
| 5 | Sanitizers: Detecting Bugs BEFORE They Crash | AddressSanitizer, UndefinedBehaviorSanitizer, MemorySanitizer. What they do at compile-time, how they instrument your binary, why fuzzing without sanitizers misses 90% of bugs. |
Phase 2 — Your First Fuzzing Lab (Hands-On Setup)
Now that you understand the theory, it’s time to get your hands dirty. But we go SLOW. Every installation step explained.
| # | Blog Title | What You’ll Build |
|---|---|---|
| 6 | Setting Up Your Fuzzing Environment From Scratch | Installing AFL++ on Ubuntu/macOS/WSL. Installing clang. Understanding compiler wrappers. Troubleshooting afl-clang-fast not found. Setting up your directory structure (in/, out/, crashes/). |
| 7 | Your First 5-Minute Fuzz Run (Complete Walkthrough) | Compiling a simple vulnerable C program with AFL++. Creating a seed corpus. Running afl-fuzz for the first time. Reading the TUI (what every number means). Understanding execs/sec, corpus count, unique crashes. |
| 8 | Reading AFL++ Output: What Those Numbers Actually Mean | Deep dive into the AFL++ status screen. What is pending, pend fav, own finds, imported? What is stability? When is your fuzzer stuck? How to diagnose performance issues. |
Phase 3 — AFL++ Deep Dive (The Engine Room)
You’ve run AFL++. Now it’s time to understand HOW it works under the hood.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 9 | AFL++ Architecture: How Coverage-Guided Fuzzing Actually Works | The feedback loop. How AFL++ instruments your binary. What is edge coverage vs. block coverage. The bitmap. The shared memory region. How AFL++ knows if an input discovered new code paths. |
| 10 | Compiling Targets with afl-clang-fast (Line-by-Line) | What happens when you run afl-clang-fast target.c -o target? How does the compiler wrapper inject instrumentation? What are the compile flags (-fsanitize=address, -g, -O0)? When to use each. |
| 11 | AFL++ Mutation Algorithms: Deterministic Stage | Bitflips, byte flips, arithmetic mutations, interesting values. How AFL++ systematically mutates inputs in the deterministic stage. Why this stage comes first. |
| 12 | AFL++ Mutation Algorithms: Havoc and Splicing | Random mutations, stacked mutations, splicing inputs together. When AFL++ switches from deterministic to havoc. Why both stages matter. |
| 13 | The Corpus: Seeds, Queue, Crashes, and Hangs | What is a seed? What is the queue? How does AFL++ decide which inputs to keep? What is corpus minimization? How afl-cmin works. |
| 14 | Dictionaries: Teaching the Fuzzer About Your File Format | When random mutations aren’t enough. Creating a dictionary file. How AFL++ uses tokens from the dictionary. When dictionaries matter (file formats, protocols). |
| 15 | Parallel Fuzzing: Running Multiple AFL++ Instances | Master/slave mode. Syncing corpora between instances. How to scale fuzzing across CPU cores. The -M and -S flags. |
Phase 4 — Writing Your First Fuzzing Harness
Theory is over. Now you write code that makes fuzzing possible.
| # | Blog Title | What You’ll Build |
|---|---|---|
| 16 | What Is a Fuzzing Harness and Why You Need One | The gap between “the program” and “the fuzzable interface.” Why you can’t just fuzz ./program. What a harness does. File-based vs in-memory harnesses. |
| 17 | Writing Your First AFL++ Harness (Complete Example) | A vulnerable C function. Writing the harness that feeds AFL++ input into it. Compiling with instrumentation. Running the fuzz. Finding the crash. Line-by-line code walkthrough. |
| 18 | Writing Harnesses for libFuzzer (In-Process Fuzzing) | The LLVMFuzzerTestOneInput function. How libFuzzer differs from AFL++. When to use libFuzzer vs AFL++. Writing a libFuzzer harness for the same target. |
| 19 | Harness Design Patterns: Handling State and Setup | What if your target needs initialization? What if it has global state? How to handle setup/teardown in a harness. Avoiding “poisoned” state across fuzzing iterations. |
| 20 | Fuzzing File Format Parsers (Real-World Example) | Choosing a real target (PNG parser, JSON parser, etc.). Writing the harness. Building the seed corpus. Running the fuzz campaign. Triaging the crashes. |
Phase 5 — libFuzzer Deep Dive
AFL++ is not the only fuzzer. libFuzzer has different strengths.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 21 | libFuzzer vs AFL++: When to Use Each | In-process vs fork-server model. Speed differences. Coverage differences. Use cases for each. |
| 22 | libFuzzer Instrumentation: How SanitizerCoverage Works | What -fsanitize=fuzzer actually does. The coverage hooks. How libFuzzer tracks edges. |
| 23 | libFuzzer Corpus Management and Merging | How libFuzzer builds its corpus. Merging corpora with merge=1. Minimizing with -minimize_crash=1. |
| 24 | Writing Custom Mutators for libFuzzer | When default mutations aren’t enough. Implementing a custom mutator. Guiding libFuzzer toward specific input structures. |
Phase 6 — Honggfuzz (The Underrated Fuzzer)
Honggfuzz is less popular but extremely powerful. You need to know it.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 25 | Honggfuzz: Why It’s Different (And When to Use It) | Persistent mode. Feedback-driven fuzzing without AFL++'s instrumentation. Hardware-based coverage (Intel PT). Multi-threaded by default. |
| 26 | Setting Up and Running Honggfuzz | Installation. Compiling targets with hfuzz-clang. Running your first Honggfuzz campaign. Reading the output. |
| 27 | Honggfuzz + Intel PT: Coverage Without Instrumentation | What is Intel PT? How Honggfuzz uses it for coverage feedback. When this matters (closed-source binaries). |
Phase 7 — Crash Triage and Bug Analysis
You found crashes. Now what? Most beginners stop here. You won’t.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 28 | Triaging Crashes: Unique vs Duplicate | You have 500 crash files. Are they all unique bugs? How to deduplicate crashes. Using afl-collect, stack hashes, sanitizer output. |
| 29 | Reading AddressSanitizer Output (Line-by-Line) | What does “heap-buffer-overflow on address 0x…” mean? Stack traces. Shadow bytes. How to map the crash back to your source code. |
| 30 | From Crash to Root Cause: Debugging with GDB | Loading the crash input into GDB. Examining registers. Walking the stack. Finding the exact line where the overflow happens. |
| 31 | Writing a Bug Report (CVE-Quality) | What makes a good bug report? Proof-of-concept. Root cause analysis. Impact assessment. Reproduction steps. Submitting to vendors. |
Phase 8 — Coverage Analysis (When Your Fuzzer Gets Stuck)
Your fuzzer has been running for 6 hours. No new paths. Is it stuck? How do you know?
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 32 | What Is Code Coverage and Why It Matters | Line coverage, branch coverage, edge coverage. The difference. Why fuzzers care about edges, not lines. |
| 33 | Generating Coverage Reports with lcov | Instrumenting your target with --coverage. Running your corpus through it. Generating HTML reports with lcov and genhtml. Reading the reports to find unreached code. |
| 34 | When Your Fuzzer Is Stuck: Diagnosing Coverage Plateaus | Your corpus hasn’t grown in hours. What does this mean? Is the target fully explored? Or is there a barrier (checksums, magic bytes, complex branching)? |
| 35 | Breaking Through: Solving Coverage Barriers | Identifying the barrier (checksums, CRCs, magic headers). Surgical harness changes. Custom mutators. Dictionaries. When to give up on a target. |
Phase 9 — OSS-Fuzz and Continuous Fuzzing
Now you understand harnesses, coverage, and tools. Time to see how Google fuzzes the entire internet.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 36 | What Is OSS-Fuzz and Why Google Runs It 24/7 | Continuous fuzzing infrastructure. ClusterFuzz. How OSS-Fuzz has found 10,000+ bugs. Why your project should be on it. |
| 37 | OSS-Fuzz Architecture: How It Actually Works | Docker containers. Build scripts. ClusterFuzz orchestration. Reproducing crashes. The full pipeline from code commit to bug report. |
| 38 | Integrating Your Project into OSS-Fuzz | Writing a build.sh script. Creating a Dockerfile. Defining fuzzing targets. Submitting a pull request. Getting your project accepted. |
| 39 | ClusterFuzz Deep Dive: The Engine Behind OSS-Fuzz | How ClusterFuzz distributes fuzzing jobs. Crash deduplication at scale. Bisecting regressions. The feedback loop from fuzzing to developers. |
Phase 10 — Kernel Fuzzing (syzkaller)
Userland is easy. The kernel is where it gets serious.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 40 | Why Kernel Fuzzing Is Completely Different | System calls vs library functions. The kernel doesn’t crash — it panics. State dependencies. Why you can’t just fuzz the kernel like a normal program. |
| 41 | syzkaller: Architecture and Design | Coverage-guided kernel fuzzing. Virtual machines. The executor. The syscall descriptions. How syzkaller generates valid syscall sequences. |
| 42 | Setting Up syzkaller (Step-by-Step) | Building syzkaller from source. Creating a VM image. Configuring the kernel with KASAN. Running your first syzkaller campaign. |
| 43 | Writing Syscall Descriptions for syzkaller | The syzlang language. Describing syscall arguments, structures, dependencies. Teaching syzkaller about a new subsystem. |
| 44 | Linux Kernel Fuzzing in Practice | Running syzkaller against a real kernel subsystem. Reading kernel panics. Bisecting kernel bugs. Reporting to LKML. |
Phase 11 — Binary-Only Fuzzing (No Source Code)
Everything so far assumed you had source code. What if you don’t?
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 45 | The Challenge of Binary-Only Fuzzing | No instrumentation. No sanitizers. No coverage. Emulation overhead. Why binary fuzzing is slow. |
| 46 | AFL++ QEMU Mode: Fuzzing Closed-Source Binaries | How QEMU mode works. User-mode emulation. QEMU’s instrumentation. Setting up afl-qemu-trace. Performance trade-offs. |
| 47 | Intel PT for Fast Binary Coverage | Hardware-assisted coverage. How Intel Processor Trace works. Using Honggfuzz with Intel PT. When this is faster than QEMU. |
| 48 | WinAFL: Fuzzing Windows Closed-Source Applications | DynamoRIO instrumentation. Persistent mode on Windows. Choosing a target function. Running WinAFL against a Windows DLL. |
Phase 12 — Advanced Fuzzing Techniques
You’ve mastered the basics. These are the cutting-edge techniques.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 49 | Structure-Aware Fuzzing: Beyond Random Bytes | When random mutations fail (structured inputs like XML, protocol messages). Grammar-based fuzzing. Protobuf fuzzing. |
| 50 | Snapshot Fuzzing: Fuzzing from the Middle | What is snapshot fuzzing? Saving execution state. Restoring and fuzzing from a snapshot. When this matters (deep program states, complex setup). |
| 51 | Differential Fuzzing: Finding Logic Bugs | Fuzzing two implementations of the same spec. Comparing outputs. Finding semantic differences. Use cases: OpenSSL vs BoringSSL, PDF parsers. |
| 52 | LibAFL: Building Custom Fuzzers | The LibAFL framework. When AFL++ isn’t enough. Writing your own fuzzer with Rust. Custom feedback mechanisms, custom mutators, custom schedulers. |
| 53 | AI-Assisted Fuzzing: LLMs for Seed Generation | Using GPT/Claude to generate valid input seeds. When this works (complex file formats). When it doesn’t (pure randomness still wins). |
Phase 13 — Network Protocol Fuzzing
Programs don’t just parse files. They parse network traffic too.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 54 | Network Protocol Fuzzing: The Unique Challenges | State machines. Handshakes. Session state. Why you can’t just throw random bytes at a TCP socket. |
| 55 | Boofuzz: The Network Fuzzing Framework | Protocol definitions. Primitives, blocks, sessions. Building a protocol model. Running a Boofuzz campaign against a network service. |
| 56 | Fuzzing TLS Implementations | Why TLS is hard to fuzz. State dependencies. Certificate validation. Building a harness for OpenSSL/BoringSSL. |
| 57 | Fuzzing Custom Protocols (Unknown Binary Protocols) | Reverse engineering a protocol from network captures. Inferring the state machine. Writing a fuzzer without a spec. |
Phase 14 — Android Fuzzing
Mobile devices are everywhere. Here’s how to fuzz them.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 58 | Android Attack Surface for Fuzzers | Native libraries. HAL interfaces. The Binder IPC mechanism. Where bugs hide in Android. |
| 59 | Fuzzing Android Native Libraries with AFL++ | Cross-compiling for ARM. Running AFL++ on-device vs in an emulator. Pushing inputs, pulling crashes. |
| 60 | Fuzzing the Android Binder Interface | What is Binder? Parcels and transactions. Writing a harness for a Binder service. |
| 61 | Fuzzing Android Apps (Java/Kotlin Layer) | Fuzzing at the Java layer. Monkey testing vs coverage-guided fuzzing. Tools: Jazzer, JQF. |
Phase 15 — IoT and Firmware Fuzzing
IoT devices are notoriously insecure. Here’s how to fuzz them.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 62 | IoT Fuzzing: The Unique Challenges | Embedded systems. Limited resources. No debuggers. Proprietary protocols. Extracting firmware. |
| 63 | Emulating Firmware with QEMU for Fuzzing | Extracting firmware from devices. Loading into QEMU. Setting up a virtual environment. Fuzzing in emulation. |
| 64 | Fuzzing Network Services on IoT Devices | Identifying network-facing services. Building harnesses for UPnP, MQTT, CoAP. Running AFL++ QEMU mode against them. |
| 65 | Fuzzing Bootloaders and Firmware Parsers | OTA update parsers. Bootloader vulnerabilities. Fuzzing the update mechanism. Building a corpus from real firmware images. |
Phase 16 — Real-World Fuzzing Workflows
How professionals actually run fuzzing campaigns in production.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 66 | The Professional Fuzzing Workflow (End-to-End) | Target selection. Harness writing. Corpus building. Campaign planning. Triage automation. Reporting. The complete process. |
| 67 | Fuzzing for 1 Hour vs 1 Week vs 1 Month | What to expect at each time scale. When to stop. Diminishing returns. How long is “long enough”? |
| 68 | Building a Seed Corpus: Quality vs Quantity | Manually creating seeds. Scraping seeds from test suites. Minimizing your corpus. When more seeds hurt performance. |
| 69 | Automating Crash Triage at Scale | You have 10,000 crashes. You can’t manually analyze them. Scripting deduplication. Prioritizing by severity. Building a triage pipeline. |
| 70 | From Fuzzing Campaign to CVE Submission | You found a real bug. Now what? Root cause analysis. Impact assessment. Writing the disclosure. Vendor coordination. Getting your CVE ID. |
Phase 17 — Building Your Own Fuzzing Infrastructure
You’re no longer just using tools. You’re building systems.
| # | Blog Title | What You’ll Learn |
|---|---|---|
| 71 | Designing a Private Fuzzing Cluster | Hardware requirements. Orchestration (Docker, Kubernetes). Distributed fuzzing. Centralized crash reporting. |
| 72 | Integrating Fuzzing into CI/CD | Running fuzzing in GitHub Actions. Automated regression testing. Catching bugs before they ship. |
| 73 | Fuzzing Metrics: What to Measure | Execs/sec, crashes/hour, coverage growth rate, unique crashes. Tracking performance over time. When metrics lie. |
| 74 | Building a Custom Fuzzer with LibAFL (Advanced) | When existing fuzzers aren’t enough. Using LibAFL to build domain-specific fuzzers. Custom feedback, schedulers, mutators. A complete example. |
| 75 | The Complete Fuzzing Lab: Hardware, VMs, Automation | The ultimate setup. Dedicated hardware. VM orchestration. Automated triage. Reporting dashboard. What a professional fuzzing lab looks like. |
Total: 75 Blogs
Every concept explained from zero.
Every line of code walked through.
No assumptions. No shortcuts.
This is the fuzzing course that should exist.
How to Use This Roadmap
- Start at Blog 1. Do not skip.
- Do the hands-on exercises. Reading is not enough.
- Don’t rush. Each blog builds on the previous ones.
- If you’re confused, re-read the previous blog. The foundation matters.
By Blog 75, you will understand fuzzing better than 95% of people who claim to “do fuzzing.”
This is not a sprint. This is a marathon. But you will finish it.