A hands-on introduction to AFL++ fuzzing using Fuzzing101 Exercise 1.
- Python 3.11+ - If not installed, see: https://www.python.org/downloads/
- macOS, Windows (with Hyper-V), or Linux
Note for Linux users: The setup script is designed for macOS/Windows. If you're on Linux, follow the manual installation steps in the script's comments to set up your environment.
The setup script automates VM creation and installs all dependencies:
python3 vm_setup.pyWhat it does:
- Installs Multipass (if needed)
- Creates Ubuntu 20.04 VM (2 CPUs, 4GB RAM, 20GB disk)
- Installs build tools, LLVM/Clang, debugging tools
- Configures core dump pattern for AFL++ fuzzing
- Clones Fuzzing101 repository directly in the VM
Windows Users: After Multipass installation, you must close and reopen your terminal (or open a new tab) to update the PATH environment variable. Then run the script again.
multipass shell fuzzing-vm
cd Fuzzing101/Exercise\ 1
# Follow the exercise instructionsThis workshop setup differs from the official Fuzzing101 instructions in several ways:
Official Guide: Build AFL++ from source using make distrib (which doesnt really exist)
This Workshop: Use system package
sudo apt install -y afl++Why: More reliable, no build failures, consistent environment. GCC plugin mode works perfectly for all exercises.
Official Guide: Requires manual core pattern configuration
sudo su
echo core >/proc/sys/kernel/core_pattern
exitThis Workshop: Automatically configured during VM setup by vm_setup.py. You should not need to configure this manually.
What is core_pattern?
When a program crashes, Linux can save a "core dump" (a snapshot of the program's memory) to help with debugging. The core_pattern setting controls where these dumps go. By default, many systems send crash notifications to an external utility (like apport on Ubuntu), which causes delays. AFL++ needs immediate crash detection, so we configure the system to write core dumps directly to a file named "core" in the current directory instead of sending them to an external program.
If you want to learn how AFL++ is built:
# Inside the VM
multipass shell fuzzing-vm
# Remove system package (if installed)
sudo apt remove afl++
# Clone and build from source
git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus
make all
sudo make installNote: LLVM mode may fail to build on Ubuntu 20.04, but GCC mode is sufficient for all Fuzzing101 exercises.
Note: The original Fuzzing101 PDF URLs are outdated and no longer work. Use these updated PDFs instead:
cd $HOME/fuzzing_xpdf/pdf_examples
# Download updated PDF samples
wget -O sample0.pdf https://ontheline.trincoll.edu/images/bookdown/sample-local-pdf.pdf
wget -O sample1.pdf https://pdfobject.com/pdf/sample.pdf
wget -O sample2.pdf https://hutchesonlab.fiu.edu/wp-content/uploads/sample-pdf.pdfPerformance Tip: Avoid PDFs larger than 100KB for the initial corpus - they significantly slow down fuzzing.
When running AFL++, you'll see "exec speed" showing executions per second. Here's what to expect:
Small programs (parsers, utilities):
- Good: >5,000 exec/sec
- Acceptable: 1,000-5,000 exec/sec
- Slow: <1,000 exec/sec
Medium programs (PDF readers, image processors):
- Good: >1,000 exec/sec
- Acceptable: 500-1,000 exec/sec
- Slow: <500 exec/sec
Large programs (browsers, compilers):
- Good: >100 exec/sec
- Acceptable: 50-100 exec/sec
- Slow: <50 exec/sec
For this Xpdf exercise, achieving >1,000 exec/sec with the recommended PDF corpus is good performance.
AFL++ provides different compilers for instrumenting your code. Here's what they do:
afl-clang-fast / afl-clang-fast++ (LLVM mode) - What we use in this workshop
- Uses the LLVM compiler to add instrumentation
- Fast and efficient
- Works with the apt-installed AFL++ package
afl-gcc-fast / afl-g++-fast (GCC plugin mode)
- Uses GCC compiler with a plugin to add instrumentation
- Good alternative when LLVM isn't available
- Not included in older apt packages
afl-cc / afl-c++ (Auto-selecting wrapper)
- Automatically picks the best compiler available
- Only in newer AFL++ versions (not in apt package version 2.59d)
- Convenient but not needed for this workshop
CPU & Heat: AFL++ uses 100% CPU continuously - your computer will get hot. The workshop VM is limited to 2 CPUs and 4GB RAM to prevent issues.
Disk: Output directories can grow to several GB. You can monitor them with df -h and clean old outputs with rm -rf ~/fuzzing_xpdf/out/
# Shell into VM
multipass shell fuzzing-vm
# List all VMs
multipass list
# Get VM info
multipass info fuzzing-vm
# Stop the VM
multipass stop fuzzing-vm
# Start the VM
multipass start fuzzing-vm
# Execute command in VM without entering shell
multipass exec fuzzing-vm -- <command>If you want to delete the VM after the workshop to free up disk space, feel free to do so:
Delete VM completely:
# Stop and delete
multipass stop fuzzing-vm
multipass delete fuzzing-vm
# Free up disk space
multipass purgeOne-liner:
multipass delete fuzzing-vm && multipass purge# macOS
brew uninstall --cask multipass
# Windows
winget uninstall Canonical.Multipass
# Or: Settings → Apps → Multipass → Uninstall
# Linux
sudo snap remove multipassEssential commands for navigating the VM and following the exercises:
# Print current directory
pwd
# List files in current directory
ls
# List with details (size, permissions, dates)
ls -la
# Change directory
cd path/to/directory
# Go to home directory
cd ~
cd $HOME
# Go up one directory
cd ..
# Go to previous directory
cd -# Create directory
mkdir directory_name
# Remove file
rm filename
# Remove directory and contents
rm -rf directory_name
# Copy file
cp source.txt destination.txt
# Move/rename file
mv oldname.txt newname.txt
# View file contents
cat file.txt
# View file with paging
less file.txt
# (press 'q' to quit)
# Edit file
vim file.txt
nano file.txt# List running processes
ps aux
# Find specific process
ps aux | grep process_name
# Kill process by PID
kill <PID>
# Kill process by name
pkill process_name
# Stop running command
Ctrl+C# Check disk space
df -h
# Check memory usage
free -h
# Check CPU/memory usage (live)
top
# (press 'q' to quit)
# Download file from URL
wget https://example.com/file.tar.gz
# Extract tar.gz archive
tar -xvzf file.tar.gz# Set variable for current session
export CC=afl-cc
export CXX=afl-c++
# View variable
echo $CC
echo $HOME
# View all environment variables
env# Make script executable
chmod +x script.sh
# Run executable
./script.sh
# Run with sudo (root privileges)
sudo command# Find files by name (searches current directory and subdirectories)
find . -name "filename.txt"
find /path/to/search -name "*.pdf"
# Locate files quickly (uses system database, faster but may be outdated)
locate filename.txt
# Find location of executable/command
which python3
which afl-fuzz
# Show all locations of a command
whereis gccThis section provides a general workflow for fuzzing any software target with AFL++. These steps apply to most classic fuzzing scenarios.
Obtain the source code of the software you want to fuzz and compile it normally.
Why: You need to ensure the software builds and runs correctly before adding instrumentation.
Create a directory with sample input files that the software can process.
Why: You need test files to verify the software works correctly. Later, (in many cases) same files will be used as the seed corpus for fuzzing.
Run the compiled binary with your sample inputs to confirm it works as expected.
Remove all compiled files after verifying the software works.
Why: You need a clean slate before recompiling with AFL++ instrumentation (more on instrumentation below).
Alternative approach: Some people keep two separate builds - one with the normal compiler for testing, and one with AFL++ for fuzzing. This avoids having to switch between builds.
There are multiple ways to install AFL++:
Method 1: System Package (Recommended for beginners and used in this workshop)
- Pros: Fast, reliable, no compilation errors
- Cons: May not be the latest version
Method 2: Build from Source (Advanced)
- Pros: Latest features, full control over build options
- Cons: May fail to build (especially LLVM mode), requires build dependencies
For this workshop, we will stick to using the system package.
Recompile the software using AFL++'s special compilers to add fuzzing instrumentation.
Why: AFL++ needs to instrument the binary to track code coverage during fuzzing.
What is Instrumentation? Instrumentation is the process of adding extra code to a program during compilation. This code doesn't change what the program does, but it records information about which parts of the code are executed. When AFL++ instruments a binary, it inserts small "probes" at key points (like the start of functions or branches) that track:
- Which code paths have been executed
- How often each path is taken
- Which branches were taken in conditional statements
This coverage information is crucial for AFL++'s feedback loop - it tells the fuzzer which inputs are "interesting" because they explore new code paths.
About Compiler Variables:
CC: C compiler (normallygcc, we set it toafl-clang-fast)CXX: C++ compiler (normallyg++, we set it toafl-clang-fast++)
When you set these variables and rebuild, the build system uses AFL++'s compilers instead of the standard ones, automatically instrumenting the code.
Start AFL++ and let it run. The longer it runs, the more code paths it explores.
How long to run: Minutes for simple bugs, hours or days for complex software. Watch the "unique crashes" counter.
After AFL++ finds crashes, verify them by running the target with the crashing input.
Use a debugger (like gdb) to understand why the crash occurs.
Analyze the crash to determine:
- What caused it (buffer overflow, null pointer dereference, etc.)
- Where in the code it happened
- If it's exploitable
Review the source code and crash details to assess if this is a security vulnerability.
- Is it a memory corruption bug?
- Can an attacker control the crash?
- What's the potential impact?
If the bug is exploitable, you may develop a proof-of-concept exploit.
Note: Only perform this on software you have permission to test. This is for educational and authorized security research only.
If you've found a genuine security vulnerability:
- Report it to the software vendor/maintainer privately
- Follow coordinated disclosure practices
- Request a CVE ID if appropriate (valued by employers and by the community)
Educational Purpose: This workshop teaches security research techniques for authorized testing only. Use these skills exclusively on systems you own or have explicit permission to test.
Your Responsibility: You are solely responsible for how you use this knowledge. The instructor and workshop organizers take no responsibility for:
- Hardware issues (overheating, wear), data loss, or system instability
- Misuse of techniques learned (unauthorized testing, exploitation, or illegal activities)
- Any consequences of your actions
By participating, you agree to use this knowledge ethically and legally, and accept full responsibility for your actions.
These resources cover the basics of fuzzing, core tools, and learning materials:
- Fuzzing101 Repository - Step-by-step tutorial series for learning fuzzing from scratch
- Multipass Documentation - Tool for quickly spinning up Ubuntu VMs (relates to Fuzzing101 setup)
- AFL++ Documentation - Comprehensive documentation for AFL++, the most popular coverage-guided fuzzer
- AFL++ Tutorials - Good list of tutorials for getting started with AFL++
- Awesome-Fuzzing - Curated list of fuzzing resources, tools, and papers
These resources showcase advanced techniques, real-world case studies, and novel approaches to fuzzing:
- Leveling Up Fuzzing: Finding More Vulnerabilities - Google's advanced fuzzing techniques and improvements
- SMT Solvers Guide - Introduction to SMT solvers, useful for constraint-based fuzzing
- Boosting Skeleton-Driven SMT Solver Fuzzing by Leveraging LLM to Produce Formula Generators - Latest research on fuzzing techniques
- Effective Fuzzing: dav1d Case Study - Real-world example of fuzzing a video decoder
- Breaking the Sound Barrier: Fuzzing Audio Codecs - Advanced case study on fuzzing audio processing
- Jackalope - Customizable, distributed fuzzer from Google Project Zero
- Fuzzing Ladybird Browser - Case study on fuzzing a web browser with modern tools
- JIT Bug Finding with SMT and Fuzzing - Novel approach combining SMT solvers with fuzzing for JIT compilers
- LLM4Decompile - LLM-based binary decompilation for generating recompilable source code
- LLAMAFUZZ - LLM-enhanced greybox fuzzing for structured data mutation
- RetroWrite - Binary rewriting framework for efficient binary-only fuzzing instrumentation
- OSS-Fuzz-Gen - Google's LLM-powered fuzz target generation framework
Author: Sasha Zyuzin
Good luck! 🐛