Skip to Content
CSE4303Introduction to Computer Security (Lecture 20)

CSE4303 Introduction to Computer Security (Lecture 20)

Due to lack of my attention, this lecture note is generated by AI to create continuations of the previous lecture note. I kept this warning because the note was created by AI.

Fuzz testing

American fuzzy lop (afl-fuzz)

Overview

  • Also known as afl-fuzz
  • ”… is a security-oriented fuzzer that employs a novel type of compile-time instrumentation and genetic algorithms to automatically discover clean, interesting test cases that trigger new internal states in the targeted binary.”
  • Requires minimal setup — just compile and provide example inputs

Bug trophy case

Projects in which afl-fuzz has found bugs include:

  • libjpeg-turbo
  • libpng
  • libtiff
  • mozjpeg
  • sqlite
  • ffmpeg
  • ntpd
  • OpenSSL
  • OpenSSH
  • tcpdump
  • wireshark
  • Firefox
  • Internet Explorer
  • Safari
  • Adobe Flash
  • bash
  • Android
  • iOS
  • LibreOffice
  • … and many more

How does it work?

afl-fuzz broadly attempts to get the program into unusual states:

  1. Compiles the program with a gcc wrapper (afl-gcc) that adds custom instrumentation to the compiled binary (feedback-driven)
  2. Creates new test cases by mutating test cases currently in the queue
  3. Runs inputs likely to get the program into a new state (as guided by instrumentation)
  4. Minimizes and saves test cases that reached new states; uses them to generate further test cases
  5. Repeat steps 2–5

The instrumentation tracks which code paths (edges in the control-flow graph) each input exercises, so the fuzzer can preferentially explore inputs that reach previously-unseen program states.

Basic afl-fuzz operation steps

  1. Get the target program source
  2. Compile with afl-gcc
  3. Choose starting test case(s)
    • Smaller is almost always better
    • afl source ships with many good starting test cases
  4. Create a test harness to deliver input to the target
  5. Start afl-fuzz
  6. Wait!
  7. Investigate results

Some of the provided test cases bundled with afl:

js: if (1==1) eval('1'); rtf: Test xml: <a b="c">d</a>

Understanding the afl-fuzz status screen

When afl-fuzz runs, it displays a live terminal dashboard:

american fuzzy lop 1.94b (strings) ┌─ process timing ─────────────────────────────────┬─ overall results ────┐ │ run time : 1 days, 1 hrs, 59 min, 44 sec │ cycles done : 0 │ │ last new path : 0 days, 0 hrs, 27 min, 12 sec │ total paths : 680 │ │ last uniq crash : none seen yet │ uniq crashes : 0 │ │ last uniq hang : 0 days, 15 hrs, 6 min, 7 sec │ uniq hangs : 79 │ ├─ cycle progress ────────────────┬─ map coverage ───────────────────────┤ │ now processing : 21 (3.09%) │ map density : 1908 (2.91%) │ │ paths timed out : 0 (0.00%) │ count coverage : 2.86 bits/tuple │ ├─ stage progress ────────────────┼─ findings in depth ──────────────────┤ │ now trying : arith 8/8 │ favored paths : 158 (23.24%) │ │ stage execs : 239k/1.13M │ new edges on : 219 (32.21%) │ │ total execs : 14.9M │ total crashes : 0 (0 unique) │ │ exec speed : 478.6/sec │ total hangs : 12.5k (79 unique) │ ├─ fuzzing strategy yields ───────────────────────┬─ path geometry ──────┤ │ bit flips : 289/1.37M, 31/1.37M, 14/1.37M │ levels : 3 │ │ byte flips : 1/171k, 1/62.9k, 1/66.4k │ pending : 672 │ │ arithmetics : 68/2.84M, 2/1.72M, 1/1.16M │ pend fav : 152 │ │ known ints : 8/218k, 7/1.04M, 3/1.90M │ own finds : 679 │ │ dictionary : 0/0, 0/0, 8/1.00M │ imported : n/a │ │ havoc : 245/351k, 0/0 │ variable : 0 │ │ trim : 1.83%/10.6k, 64.31% │ │ └────────────────────────────────────────────────────────────[cpu:193%]──┘

Process timing

Answers the questions:

  • How long has the fuzzer been running?
  • How long ago was the last new path/crash/hang discovered?

Key fields:

FieldMeaning
run timeTotal elapsed time
last new pathTime since the last new execution path was found
last uniq crashTime since the last unique crash was found
last uniq hangTime since the last unique hang was found

Overall results

High-level summary of what afl has found so far:

FieldMeaning
cycles doneNumber of complete passes over all queued test cases
total pathsTotal number of distinct execution paths discovered
uniq crashesUnique crashing inputs saved
uniq hangsUnique hanging inputs saved

Stage progress

Shows what the fuzzer is doing right now:

FieldMeaning
now tryingCurrent mutation stage (e.g., arith, havoc, trim)
stage execsExecutions completed in this stage vs. total planned
total execsGrand total of all executions so far
exec speedExecutions per second

Fuzzing strategy yields

afl cycles through several mutation strategies and tracks how many new paths each has found:

StrategyDescription
bit flipsFlip individual bits in the input
byte flipsFlip individual bytes
arithmeticsAdd/subtract small integers from byte values
known intsSubstitute common “interesting” integer values
dictionaryInsert tokens from a user-supplied dictionary
havocRandomised stacked mutations
trimMinimise test cases while preserving coverage

Each strategy reports new_paths_found / total_executions_in_stage.

Path geometry

Describes the shape of the discovered execution-path tree:

FieldMeaning
levelsDepth of the path tree
pendingTest cases not yet fully mutated
pend favFavoured pending test cases
own findsPaths discovered without importing from other instances
importedPaths imported from other parallel afl instances
variableTest cases that produce non-deterministic coverage
Last updated on