Fuzzing and crash triage
Stop reading for the bug and make the crash come to you - then work out which crashes are the same bug and which one is exploitable.
Assumes24. Binary exploitation
By the end you can
- Write a harness that reaches the interesting code in as few layers as possible
- Build a seed corpus and say why each seed is there
- Explain what coverage instrumentation buys, and what it costs on a slow target
- Turn a sanitiser report into a one-line statement of the bug's class and location
- De-duplicate crashes by root cause rather than by stack hash
- Judge exploitability from the primitive rather than from the crash message
1. Read
Coverage-guided fuzzing: making the crash come to you
When a pwn or rev challenge hands you a parser and asks for the bug, you can read every line - or you can let AFL++ find the crash while you sleep. Harnesses, corpus, sanitizers, and what to do when the fuzzer gets stuck on a checksum.
Integer bugs: overflow, signedness, truncation, and the off-by-one
The length check that passes because the length wrapped, the negative index that survives a bounds check, and the 16-bit truncation that turns 65,540 into 4. Where arithmetic bugs come from and how to spot them in a decompiler.
2. Use the tools
In the order they come up while solving. Read what each one does, or go straight to the workspace tab that runs it.
- ELF, PE and Mach-O binary analyzer
Parse headers, sections, imports, and symbols from Linux, Windows, and macOS binaries, with C++ symbol demangling and gadget discovery.
Open it in the workspace - Cyclic pattern generator and offset finder
Generate a de Bruijn sequence and find the exact overflow offset from a crashed register value - the pwntools cyclic workflow, in the browser.
Open it in the workspace - Buffer overflow offset finder
Find the exact number of bytes before the saved return address using a de Bruijn pattern and the value from a single crash.
Open it in the workspace - Struct pack and unpack (p32, p64, u32, u64)
Convert integers to little-endian byte strings and back at 8, 16, 32, and 64 bits - the pwntools p32/p64 helpers without the install.
Open it in the workspace - Pwntools exploit script generator
Generate a working pwntools template with the right context, process or remote connection, and the boilerplate every exploit repeats.
Open it in the workspace
3. Try one now
Generated in your browser and checked in your browser. No account, nothing to download, and a fresh one whenever you want another.
4. Practise on the real thing
Real picoCTF challenges that use these techniques, easiest first. 21 match in total - see the full index.
Common mistakes
The wrong turns this topic reliably produces. Written as the mistake rather than the rule, because the rule is easy to agree with and easy to walk straight past.
- Fuzzing the whole program through its normal entry point. Most of the run is spent in argument parsing and setup; the harness exists to skip that.
- Counting crashes. A thousand crashes are usually a handful of bugs, and until they are de-duplicated the number means nothing.
- Treating a sanitiser report as an exploit. Heap-buffer-overflow READ of size 1 and WRITE of size 8 are very different findings.
- Judging a corpus by how many files are in it. A thousand near-identical seeds explore one path; a corpus is doing its job when each seed reaches code the others do not, which is a coverage measurement rather than a count.
- Fuzzing a target built without sanitisers. Corruption that does not happen to crash passes unnoticed, so the run finds the loud bugs and silently misses the class this module is about.
Checkpoint
Take a small parsing target, produce a harness and a seed corpus, run it to a crash, and hand in the minimised input plus a one-sentence root cause.
Teaching note
The lesson students resist is that harness quality dominates everything else. Show two runs on the same target - one through the CLI, one through a direct call into the parser - and let the coverage numbers make the argument.
Go deeper
The lessons above are written to get you through a challenge. These go after the subject instead. Each one opens our notes on that chapter - what it argues, what to take from it and where it stops - so this is somewhere to read now rather than a book to buy first. Nothing here is affiliate-linked or sold by us.
Chapter 7, Quick and Dirty Fuzzing
From Day Zero to Zero Day - Eugene Lim
The cheapest useful fuzzer, which is the one that should exist before any sophisticated one does.
Chapter 8, Coverage-Guided Fuzzing
From Day Zero to Zero Day - Eugene Lim
Instrumentation, corpora and scheduling explained in the order you actually need them.
Chapter 3, Automated Variant Analysis
From Day Zero to Zero Day - Eugene Lim
What to do after the first bug: the same mistake is usually present three more times.
Chapter 12, Principles of Symbolic Execution
Practical Binary Analysis - Dennis Andriesse
The other way to reach deep code, and an honest account of where it stops scaling.
Chapter 25, Automatic Vulnerability Discovery Using Fuzzers
Bug Bounty Bootcamp - Vickie Li
The same technique aimed at web targets, where the oracle is a response rather than a signal.
Every book the curriculum cites has a page in the library.