Skip to content
All modules
AdvancedModule 25 of 27120 minutes

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

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.

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 are the chapters to read when you want the subject instead - each one named so you can check it rather than take our word for it. Nothing here is affiliate-linked or sold by us.

  • From Day Zero to Zero Day - Eugene Lim

    Chapter 7, Quick and Dirty Fuzzing

    The cheapest useful fuzzer, which is the one that should exist before any sophisticated one does.

  • From Day Zero to Zero Day - Eugene Lim

    Chapter 8, Coverage-Guided Fuzzing

    Instrumentation, corpora and scheduling explained in the order you actually need them.

  • From Day Zero to Zero Day - Eugene Lim

    Chapter 3, Automated Variant Analysis

    What to do after the first bug: the same mistake is usually present three more times.

  • Practical Binary Analysis - Dennis Andriesse

    Chapter 12, Principles of Symbolic Execution

    The other way to reach deep code, and an honest account of where it stops scaling.

  • Bug Bounty Bootcamp - Vickie Li

    Chapter 25, Automatic Vulnerability Discovery Using Fuzzers

    The same technique aimed at web targets, where the oracle is a response rather than a signal.