> offensive-fuzzing
offensive-fuzzing skill from SnailSploit/Claude-Red
curl "https://skillshub.wtf/SnailSploit/Claude-Red/offensive-fuzzing?format=md"SKILL: Fuzzing
Metadata
- Skill Name: fuzzing-methodology
- Folder: offensive-fuzzing
- Source: https://github.com/SnailSploit/offensive-checklist/blob/main/fuzzing.md
Description
Practical fuzzing methodology reference: target identification, fuzzer selection (AFL++, libFuzzer, Boofuzz, Peach), harness writing, corpus curation, mutation strategies, coverage measurement, and crash triage. Use when setting up or running fuzz campaigns against any target.
Trigger Phrases
Use this skill when the conversation involves any of:
fuzzing, AFL++, libFuzzer, Boofuzz, Peach, fuzz harness, corpus, mutation, coverage, crash triage, network fuzzing, file format fuzzing
Instructions for Claude
When this skill is active:
- Load and apply the full methodology below as your operational checklist
- Follow steps in order unless the user specifies otherwise
- For each technique, consider applicability to the current target/context
- Track which checklist items have been completed
- Suggest next steps based on findings
Full Methodology
Fuzzing
automated software testing technique that is used for program analysis
Types
BlackBox
- Generates random or model‑based inputs and feeds them into the program under test
- Fuzzer has no knowledge of the program internals during fuzzing
- Pros
- Extremely fast
- Easy to use
- Scalable
- Cons
- Random testing leads to poor coverage
GreyBox
- Relies on lightweight instrumentation of the program under test
- Fuzzer has some knowledge of the program internals during fuzzing
- Pros
- Feedback
- Scalable
- Relatively fast
- Cons
- Simplistic mutations
- Examples
- General: AFL++, Honggfuzz, BooFuzz, WinAFL
- Directed: UAFuzz, AFLGo
- Grammar Based: Tlspuffin, AFLSmart
- Taint Based: Angora,
- Concolic: QSYM, AFL, SymSan
- Self‑learning: SieveFuzz, RL‑Fuzz
- Binary Fuzzing: Jackalope
- Special Fuzzers: Papora, Medusa
- Kernel: syzkaller, kAFL, wtf, KF/x
- ETC: LibAFL (snapshot & Unicorn support 0.15.x), FuzzBench, ClusterFuzz, DynamoRIO
Snapshot
- Takes and restores memory/register snapshots of the target or VM to bypass expensive initialization.
- Pros
- Order‑of‑magnitude faster execution on large or stateful binaries
- Deterministic and easily reproducible
- Works with closed‑source targets (no rebuild needed)
- Cons
- Initial snapshot & harness creation can be complex
- Requires specialised snapshot engine support (e.g., Nyx, Snapchange, wtf)
- Examples
- Nyx (v2 with Intel‑PT support; note: Nyx integration requires the AFL++-Nyx fork, not mainline AFL++ 4.x)
- Snapchange
- wtf
Snapshot Fuzzing Recipes
- AFL++ Nyx (user-mode)
NYX_MODE=1 AFL_MAP_SIZE=1048576 afl-fuzz -i seeds -o findings -- ./target_nyx @@
WhiteBox
- Leverages heavyweight symbolic execution and static analysis, assuming full source availability
- Pros
- Solves path constraints to get past difficult logic
- Capable of generating inputs for deep, hard‑to‑reach program states
- Cons
- Complex
- Slow
- Not scalable
Ensemble Fuzzing
Ensemble fuzzing coordinates multiple heterogeneous fuzzers sharing a unified corpus, achieving better coverage than any single fuzzer.
Concept
- Cross-Pollination: Different fuzzers discover different code paths; sharing corpus maximizes coverage
- Complementary Strengths: AFL++ excels at control flow; Honggfuzz at crash detection; libFuzzer at in-process fuzzing
- Coordinated Scheduling: Use reinforcement learning or heuristics to select optimal fuzzer per input
Tools and Frameworks
- EnFuzz: Uses reinforcement learning to dynamically select which fuzzer runs on each input based on historical effectiveness
- CollAFL: Lightweight synchronization protocol for parallel fuzzer coordination without central coordinator
- CUPID: Analyzes feedback from all fuzzers to guide mutation strategies across the ensemble
Practical Setup
# Terminal 1: AFL++ primary with shared sync directory
afl-fuzz -M fuzzer1 -i seeds -o sync_dir -- ./target @@
# Terminal 2: Honggfuzz syncing to AFL corpus
../honggfuzz/honggfuzz -i sync_dir/fuzzer1/queue -W sync_dir/hfuzz \
--linux_perf_ipt_block -t 10 -- ./target ___FILE___
# Terminal 3: libFuzzer reading from both corpora
./target_libfuzzer sync_dir/fuzzer1/queue sync_dir/hfuzz/queue \
-max_total_time=3600 -runs=1000000
# Terminal 4: Sync monitor (optional)
watch -n 60 'ls -lh sync_dir/*/queue | wc -l'
Best Practices
- Start Simple: Begin with AFL++ + Honggfuzz; add libFuzzer if you have source
- Corpus Deduplication: Run
afl-cminperiodically to minimize combined corpus - Resource Allocation: Allocate 40% AFL++, 30% Honggfuzz, 30% libFuzzer based on empirical results
- Monitoring: Track unique crashes per fuzzer to identify which contributes most
Performance Gains
- Research shows 15-40% more coverage vs single fuzzer
- 2-3× more unique crashes in 24-hour runs
- Particularly effective on complex parsers with multiple code paths
Components
Power Scheduler
- Responsible for distributing the amount of fuzzing time among the seeds in the seed queue
- Prioritize more interesting seeds
- Usually measure by its ability to produce new code coverage
- Assigns a scope to each seed and picks the one with highest score
- Self‑learning schedulers such as SieveFuzz and RL‑Fuzz use reinforcement learning to allocate energy dynamically based on past mutation success.
- Explore/Exploit auto‑tuning: AFL++ 4.30+ folds MOpt into the core and dynamically balances energy between seeds.
Mutation
- Responsible for making small changes to the fuzzing seed, with the goal of exercising new program behavior
- Examples: bit-flips, addition/subtraction, deletion, etc
- Typically operate by making small, incremental changes
- LLM‑assisted mutations & harness scaffolding: Large‑language models can infer grammars/dictionaries (
--dict2) and draft starter harness code (e.g., LibAFL'sllm_mutator). - Overflow‑aware arithmetic heuristics: Enable
--arith8/16/32-smartin AFL++ (or equivalents) to target boundary‑condition overflows. - AFLPlusPlus
- Deterministic: includes single deterministic mutations on the content of the test cases
- Havoc: mutations are randomly stacked and also includes changes to the size of the test case
- Note: honggfuzz and libFuzzer implement weighted random mutation stacks instead of the deterministic/havoc split
- cmp_log guided mutations: Enable
-cmp_log(AFL++) orAFL_LLVM_CMPLOG=1to perform Redqueen‑style input‑to‑state transforms. - Snapshot‑aware mutations: With Nyx mode (
NYX_MODE=1) AFL++ randomises in‑memory state as well as file input for deep state machines. - LLM‑guided edits: HyLLfuzz uses GPT/Llama‑3 to generate branch‑targeted mutations, achieving ≈ 1.3× edge coverage.
Directed Fuzzing (reach a specific bug/function)
- AFLGo basics:
- Build with distance metrics to target BBs/functions, then run with exploration/exploitation phases
- Example:
export AFLGO=/path/to/aflgo cmake -DAFLGO=ON -DDISTANCE_CFG=BBtargets.txt .. make clean all afl-fuzz -z exp -c 45m -i seeds -o out -- ./target @@
- libAFL targeted stages: use objective feedbacks to push towards addresses/symbols of interest
Executor
- Responsible for executing the program under test with mutated fuzzing seed in a performant manner
- AFL++ uses a forkserver to skip the cost of expensive initialization and startup code
- AFL++ also offers persistent fuzzing mode, where the essential code is run inside a loop without a need for fork
- GPU‑accelerated execution loops are possible with CUDA‑AFL and LibAFL's
VulkanExecutor, ideal for shader or graphics targets. - Recent AFL++ versions ship a Nyx executor capable of high exec/s on user‑mode targets; activate with
NYX_MODE=1(verify version and build flags).
Persistent Mode Implementation
HF_ITER Style (Honggfuzz):
Honggfuzz offers HF_ITER-style persistent mode that's often easier to implement than ASAN-style for complex targets:
#include "honggfuzz.h"
int main(int argc, char** argv) {
// Expensive initialization (run once)
initialize_target();
// Persistent fuzzing loop
for (;;) {
size_t len;
uint8_t *buf;
// Get input from honggfuzz
HF_ITER(&buf, &len);
// Convert to target-appropriate format
FILE* input_stream = fmemopen(buf, len, "r");
// Execute target with fuzzed input
int result = target_function(input_stream);
// Cleanup for next iteration
fclose(input_stream);
reset_target_state();
}
}
Memory Management Considerations:
// Prevent memory leaks in persistent mode
void reset_target_state() {
// Free any allocated memory
cleanup_buffers();
// Reset global state
memset(&global_state, 0, sizeof(global_state));
// Close any open file handles
close_handles();
}
ASAN-Style Alternative:
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Direct fuzzing interface - no manual loop needed
return target_function(data, size);
}
Feedback
- Set of program state information from running with a particular input seed
- Fuzzers use feedback to determine fitness of a given seed(basic block coverage, edge coverage, path coverage)
- AFLPlusPlus uses edge coverage (keeps a shared bitmap between the target and the fuzzer)
- AFL++ uses edge coverage (keeps a shared bitmap between the target and the fuzzer)
- Hardware trace sources such as Intel® Processor Trace (IPT) and ARM ETM/CoreSight provide near‑zero‑overhead edge coverage for large binaries.
- LibAFL 0.15.2 can derive edge coverage from Last Branch Records, giving zero‑instrumentation tracing on recent Intel CPUs (
LBRFeedback).
Intel PT Coverage Setup
Honggfuzz with Intel PT:
Intel PT provides hardware-based coverage tracking ideal for binary-only targets where source instrumentation isn't possible:
# Basic Intel PT setup with honggfuzz
../honggfuzz/honggfuzz -i input_corpus/ -W workspace/ --linux_perf_ipt_block -t 10 -- ./target @@
# Performance tuning
../honggfuzz/honggfuzz -i input_corpus/ -W workspace/ \
--linux_perf_ipt_block \
--linux_perf_ignore_unknown \
--threads 4 \
-t 30 -- ./target @@
Intel PT Requirements:
- Modern Intel CPU with PT support (check with
cat /proc/cpuinfo | grep intel_pt) - Linux kernel with PT enabled (
CONFIG_INTEL_PT=y) - Sufficient privileges or
CAP_SYS_ADMINcapability
Troubleshooting Intel PT:
# Check PT availability
dmesg | grep -i "intel.*pt"
cat /sys/devices/intel_pt/type
# Permission issues
echo 'kernel.perf_event_paranoid = -1' >> /etc/sysctl.conf
sysctl -p
# Alternative: use capsh for specific capability
capsh --caps="cap_sys_admin+eip" -- -c "./honggfuzz_command"
Oracle
- Detects if any interesting behavior occurred during execution of the program under test with a given input
- Code Sanitizers are special compile-time instrumentation for the program under test that perform run-time checks
- AFL++ offers
QASANto run binaries that are not instrumented withASanunder QEMU with the AFL++ instrumentation - Different Bugs Require Different Oracles
- No Source: Statically rewrite the binary or
YOLOit - Decoupled Sanitization: use SAND to off-load sanitizer checks and speed up fuzzing
- Memory Safety: use Address or Leak or Memory Sanitizer (try HWASAN for lower memory usage); or use ARM's MTE for hardware‑assisted tagging on AArch64
- Concurrency Issues: use Thread Sanitizer – LLVM 18 adds detection for C++20 std::atomic_wait
- Type Safety: use Type Sanitizer
- Undefined Behavior: use
UBSan - Heap Hardening: Scudo Hardened Allocator (part of LLVM's compiler-rt, available in recent Clang versions) detects overflows and double‑frees with minimal performance cost.
- Kernel Undefined Behavior: Kernel UBSan (KUBSan) — enable with
CONFIG_UBSAN_TRAP=y(verify availability in your kernel). - Control‑Flow Integrity: KCFI (Clang 18) adds low-overhead forward-edge CFI; enable with
-fsanitize=kcfi. - Data‑Flow: Data‑Flow Sanitizer v2 adds taint‑tracking (
-fsanitize=dataflow) and now works with libFuzzer. - Security‑property oracles: Idempotency or differential fuzzing for APIs (e.g., DiffSink for compiler targets).
- Kernel Stuff: use
KASAN,KMSAN,KCSAN - Logic Bugs: Differential or Property(Correctness-Idempotency) Oracles
- No Source: Statically rewrite the binary or
Property/Differential Oracles (quick patterns)
- Idempotency:
f(x) == f(f(x))for normalizations/parsers - Differential: compare two implementations or two versions, bucket on output mismatch
- Invariants: monotonic lengths, checksum equality, schema validation post‑parse
Seed Corpus
What is a Seed Corpus?
Seed corpus is a collection of input files used as a starting point for fuzzing. In mutational fuzzing, the fuzzer takes existing files and makes random mutations (flipping, reordering, removing, inserting data) before having the target application parse the mutated file.
Why is a Seed Corpus Important?
- Increases code coverage, which correlates strongly with finding crashes
- Allows fuzzers to start close to "interesting" points in the target application
- Helps overcome "unsolvable cliffs" in code coverage that fuzzers might struggle with
- Research shows fuzzers perform significantly better when bootstrapped with a minimized corpus
Creating a Seed Corpus
-
Manual Creation
- Create files with different command-line tools or GUI applications
- Use all possible tools for your file format to generate diverse outputs
- Automate where possible, but can be time-consuming
-
Existing Test Suites and Bug Reports
- Leverage test suites from the target application
- Extract test cases from bug reports (high signal value)
-
Web Crawling
- Use Common Crawl or similar datasets to extract relevant file types
- Filter based on MIME types
- Perform corpus distillation: keep only files that trigger new code paths
Corpus Distillation Process
- Iterate through each potential seed file
- Check file size (smaller files generally more efficient for fuzzing)
- Run the file with code coverage instrumentation
- Record if the file triggers any new code coverage not seen before
- Keep only files that increase code coverage
- Perform final minimum-set cover minimization for the smallest possible corpus
Tools for Corpus Creation
- common-corpus: Tool to build fuzzing corpus from Common Crawl data
- AFL's afl-cmin: Corpus minimization tool
- AFL's afl-tmin: Test case minimizer
- cf‑min – distributed/cluster‑friendly corpus minimizer
- Crash‑Repro‑Recorder (CRR) bundles – store the exact sequence of inputs needed to reproduce a crash deterministically
Crash Triage Pipeline
# 1) Minimize
afl-tmin -i crash -o crash.min -- ./target @@
# 2) Symbolize/Log
ASAN_OPTIONS=abort_on_error=1:symbolize=1 ./target crash.min 2>asan.log
# 3) Coverage Hash
./cov-tool --bbids ./target crash.min > cov.hash
# 4) Bucket
./bucket.py --key "$(cat cov.hash)" --log asan.log --out triage/
Cross‑platform crash analysis quick cheatsheets (user‑mode)
-
Linux
- Enable coredumps and replay:
ulimit -c unlimited sysctl -w kernel.core_pattern=core.%e.%p ./target crash.min # produces core gdb -q ./target core.* -ex 'set pagination off' -ex bt -ex 'info reg' -ex q addr2line -e ./target 0xDEADBEAF - Stabilize runs:
taskset -c 0 chrt -f 99 ./target @@; setASAN_OPTIONS=allocator_may_return_null=1:handle_abort=1.
- Enable coredumps and replay:
-
Windows
- Local dumps (WER):
New-Item 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -Force | Out-Null New-ItemProperty -Path 'HKLM:\...\LocalDumps' -Name DumpType -Type DWord -Value 2 -Force | Out-Null - PageHeap (user mode):
gflags /p /enable target.exe /full - WinDbg basics:
.symfix; .reload /f !analyze -v k; r; lm - Optional: record Time‑Travel Debugging (TTD) to replay non‑deterministic crashes.
- Local dumps (WER):
-
macOS
lldb -o 'bt all' -- ./target crash.min; setDEVELOPER_DIRto Xcode for symbols.
Kernel crash triage quicksheet
-
Linux
- KASAN/KMSAN logs:
dmesg -T | egrep -i 'kasan|kmsan' -A 60 - Decode stacks:
./scripts/decode_stacktrace.sh vmlinux /lib/modules/$(uname -r)/build < dmesg.log - Map addresses:
addr2line -e vmlinux 0xffffffff81234567
- KASAN/KMSAN logs:
-
Windows
- Driver Verifier:
verifier /standard /driver yourdrv.sys - KD/WinDbg:
!analyze -v; kv; r; !verifier 3; !irpfind
- Driver Verifier:
Sanitizer options (quick reference)
- ASAN_OPTIONS:
abort_on_error=1:symbolize=1:allocator_may_return_null=1:detect_stack_use_after_return=1 - UBSAN_OPTIONS:
print_stacktrace=1:halt_on_error=1 - TSAN_OPTIONS:
halt_on_error=1:history_size=7:second_deadlock_stack=1 - MSAN_OPTIONS:
poison_in_dtor=1:track_origins=2 - HWASAN (AArch64):
abort_on_error=1:stack_history_size=7
syzkaller crash repro and bisection (essentials)
# Reproduce from syz repro
syz-execprog -repeat=0 -procs=1 -wait=5m -cover=0 -debug target.repro
# Run minimized C reproducer under KASAN/KCFI build for clarity
make -j$(nproc) CONFIG_KASAN=y CONFIG_UBSAN=y CONFIG_KCFI=y
# Git bisection (when you have a fix commit)
git bisect start <bad> <good>
git bisect run ./repro.sh
Workflow
flowchart TD
A[Research Program Under Test] --> B[Choose Analysis Techniques];
B --> C[Initial Fuzzer Setup];
subgraph "Setup Details"
C --> C1[Gather Initial Seed Corpus];
C --> C2[Instrument Target];
C --> C3[Configure Execution];
C --> C4[Select Fuzzing Parameters];
end
C --> D[Begin Fuzzing];
D --> E{Monitor Fuzzing Progress};
E -- Stalled? --> F[Troubleshoot/Adjust];
F --> D;
E -- Crashes Found? --> G[Process Fuzzing Results];
subgraph "Result Processing"
G --> G1[Triage Crashes];
G --> G2[Deduplicate Test Cases];
G --> G3[Minimize Test Cases];
end
G --> H[Report Vulnerabilities / Refine];
H --> I[End];
E -- No Crashes/Finished --> I;
classDef setup fill:#99e,stroke:#111,stroke-width:2px,color:#333;
class C1,C2,C3,C4 setup;
classDef process fill:#e6e,stroke:#111,stroke-width:2px,color:#333;
class G1,G2,G3 process;
Research the Program Under Test
- Familiarize yourself with the program under test
- Learn what the program under test does and how it operates
- Interact with the program & learn how to use it
- Identify inputs & outputs
- Identify program areas to focus analysis efforts on Looking for
- Potentially Vulnerable program code
- Previously patched code
- Previous vulnerabilities
- Newly developed code
- Complex logic
- Input data ingestion sites
- For kernel modules, look beyond traditional attack vectors:
- Beyond IOCTL handlers and
copy_from_usercalls - Specialized subsystems like DMA-BUF may have attack surface through:
- Custom callbacks in operation structures
- Memory mapping handlers
- Page fault handlers
- VM operation structures
- Allocation/free mechanisms
- Identify all user-controlled inputs, especially those passed to functions that don't use
copy_from_user
- Beyond IOCTL handlers and
Choose the Right Set of Program Analyses
- Types of analyses that you select to conduct depends on a variety of factors
- Size
- Format
- Interface
- Complexity
Initial Fuzzer Setup
-
Construct a representative initial seed corpus by gathering a set of program inputs that resemble the input format program expects
-
Instrument the program under test with coverage and sanitization
-
Recommended build flags (Clang/LLVM):
# LibFuzzer + ASan/UBSan (C/C++) CC=clang CXX=clang++ CFLAGS="-O1 -g -fno-omit-frame-pointer" \ CXXFLAGS="-O1 -g -fno-omit-frame-pointer" \ LDFLAGS="" \ cmake -DCMAKE_C_FLAGS="-fsanitize=address,undefined -fsanitize-recover=undefined" \ -DCMAKE_CXX_FLAGS="-fsanitize=fuzzer,address,undefined -fsanitize-recover=undefined" .. # MSVC (Windows) AddressSanitizer for x64 # In Visual Studio 2022+: Project Properties → C/C++ → Address Sanitizer: Yes (/fsanitize=address) # Runtime options set ASAN_OPTIONS=detect_leaks=1:halt_on_error=1:strict_string_checks=1 -
Execution method with Harness or command line arguments
-
Select fuzzing parameters like power schedule, dictionary, custom mutator, etc
-
Fuzzing setup to run in parallel, etc
Quick‑Start Recipes
-
LibFuzzer harness (C++):
#include <cstdint> #include <cstddef> extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { /* parse_or_process(data, size); */ return 0; } -
AFL++ on a CLI target:
# Instrument CC=afl-clang-fast CXX=afl-clang-fast++ cmake -DCMAKE_BUILD_TYPE=Release .. && make -j # Seed dir with a few minimal valid inputs afl-fuzz -i seeds -o findings -- ./target @@ # Useful extras: dictionary and cmplog for hard compares afl-fuzz -i seeds -x dict.txt -o findings -c 0 -- ./target @@ # Or enable cmplog build/runner pair AFL_LLVM_CMPLOG=1 CC=afl-clang-fast CXX=afl-clang-fast++ make clean all afl-fuzz -i seeds -o findings -M f1 -- ./target @@ afl-fuzz -i seeds -o findings -S s1 -c 0 -- ./target @@ -
Windows binary‑only (QEMU mode):
afl-fuzz -Q -i seeds -o findings -- target.exe @@
Begin Fuzzing
- Start the actual fuzzing process and wait for any crashes
- Fuzzing might get stalled, become unstable or have poor performance
Process the Fuzzing Results
- Once the fuzzer produces a set of interesting test cases, we need to refine them
- Triage
- Group test cases by root cause and/or vulnerability type
- Prioritize patching the more sever vulnerabilities
- Deduplication: Remove all non-unique test cases
- Minimization: get rid of unnecessary bytes of input
Crash dedup & triage tips
- Prefer stack‑hash or coverage‑hash based bucketing (e.g., AFLTriage, Crash Triage scripts).
- Minimize before debugging:
afl-tmin,llvm-reduce, orcreducefor textual formats. - Use stable environments: pin CPU governor, disable ASLR where safe, fix random seeds.
- Export sanitizer logs to files for CI artifacts.
Reproducibility quick checklist
- Save and replay exact input sequences in persistent mode
- Pin CPU governor; fix RNG seeds; disable ASLR only where safe and necessary
- Minimize before debugging (
afl-tmin,llvm-reduce,creduce) - Record binary hashes and sanitizer options with every crash
Obstacles
Binary Only vs Source Fuzzing
- Sometimes only executables are available, without any source code
- Solution
- Binary Rewriting: inserting coverage and sanitization into a binary without recompilation (e.g.,
retrowrite, binary‑only ASan/QASan) - Dynamic Binary Instrumentation: inserting coverage and sanitization at runtime (e.g.,
QASAN, DynamoRIO, Frida/QBDI)
- Binary Rewriting: inserting coverage and sanitization into a binary without recompilation (e.g.,
Fuzzing Harness
- Some fuzzing targets are difficult to interact with
- Solution
- Fuzzing harness acts as a middleware between the program under test and the fuzzer
- Can also use function hooking to replace network or file function calls
Library Harness Best Practices
- Research Existing Work: Search for existing harnesses or test suites
- Optimize Compilation: Use
-O1or-O3flags during compilation - Balance Coverage vs Speed: A good harness maximizes code coverage while maintaining execution speed
- Strategic Targeting: Create multiple small harnesses for different library components
- Resource Management: Ensure proper initialization and cleanup of library resources
- Input Manipulation: Create functions that transform fuzzer input into valid library parameters
- Persistent Mode: For maximum efficiency, implement persistent mode harnesses that reuse library instances
Snapshot Harnessing Tips
- Snapshot after expensive initialization, right before the parse/dispatch loop
- Map fuzzer input into in‑memory buffers; avoid filesystem and network overhead
- Seed RNG and log it; ensure deterministic time sources where possible
- Export coverage early and often (breakpoints or tracepoints) for plateau detection
Structure‑aware fuzzing
- Extract tokens/keywords to a dictionary (AFL++
--dict2orAFL_TOKEN_FILE). - Use libprotobuf‑mutator for protobuf/gRPC targets; generate corpus from
.protoexamples. - For HTTP/REST/GraphQL, record real traffic and convert to templates with placeholders.
When building harnesses for libraries:
- Start with a basic implementation that validates core functionality
- Gradually expand to cover more API functions
- Use the documentation to understand parameter boundaries and edge cases
- Test with a variety of input encodings and configurations
- Consider structural awareness when fuzzing format-specific libraries
Resources:
- Awesome LibFuzzer Harness Collection
- OSS-Fuzz project repositories
Fuzzer Stalls
- Fuzzer progress has come to a halt
- Solution
- Run a collection of different fuzzers
- Produce actionable coverage statistics with tools like VisFuzz or afl-cov that inform you of where the fuzzer is getting stuck
- Use a concolic fuzzer, which combines constraints solving with fuzzing to help traditional fuzzers get past difficult conditional statements
- If all else fails, move on to a different analysis technique
- For AFL++: enable
-c 0(cmplog), tryAFL_MAP_SIZE=1048576, use-L 0for MOpt, and add custom mutators.
Plateau escape tactics
- Switch to directed fuzzing (e.g., AFLGo/UAFuzz) for a specific function/basic block
- Add grammar/dictionary; enable CMPLOG/Redqueen to unlock hard compares
- Use concolic assistance (QSYM, Driller, libAFL concolic) on stubborn branches
- Reduce target surface via snapshotting or split harness to increase exec/s
Fuzzing Reproducibility
- Inability to reproduce crashing test cases produced by fuzzer
- Solution
- During persistent fuzzing, save all inputs starting from when a new process is created and replay those inputs in same order to reproduce behavior
- AFLPlusPlus offers special compile-time instrumentation that attempts to eliminate concurrency issues
Speed & Performance
- Fuzzer is running slowly
- Solution
- Use snapshot fuzzing to eliminate execution of redundant, unimportant code
- Avoid using complex fuzzing logic
- Parallel fuzzing can sometimes help
- Pin CPU governor to performance; disable throttling; set
AFL_SKIP_CPUFREQ=1when needed. - Prefer
llvm_modeoverqemu_modewhere possible; enable LTO instrumentation for higher throughput.
Techniques
Syzkaller
- Limit enabled syscalls to make fuzzing go deeper
- Write new
syzlangdescriptions - Change the mutation of fuzzing inputs(integrate symbolic execution)
- Start fuzzing from the crafted corpus
- Customize
kcovor use cover filter for directed fuzzing - Extend grammar for better coverage
- External Network Fuzzing:
- Packet Injection: Utilize
TUN/TAPvirtual network devices to inject network packets from within the VM, allowing the kernel to process them as if they were received externally. This approach is compatible with syzkaller's architecture, which runs the fuzzer process inside the VM. - Coverage Collection: Employ
KCOVto gather code coverage from the kernel's network packet parsing code.KCOVcan be adapted to work withTUN/TAPto trace the execution paths taken during packet processing. - Pseudo-syscalls: Implement
syzkallerpseudo-syscalls to manage network-related operations, such as packet injection and resource management (e.g.,syz_emit_ethernetfor sending packets,syz_extract_tcp_resfor handling TCP sequence and acknowledgement numbers). - Syscall Descriptions: Create detailed
syzlangdescriptions for network protocols and packet structures to guide the fuzzer. This includes defining packet fields, checksums, and relationships between different protocol layers. - Integration Challenges:
- Checksums: Implement logic to correctly calculate and update checksums for various protocols (IP, TCP, UDP, ICMP) as the fuzzer mutates packet data.
- TCP Connections: Develop sequences of syscalls and pseudo-syscalls to establish and manage TCP connections, enabling fuzzing of stateful TCP communication.
- ARP Traffic: Minimize or filter out ARP traffic to isolate the fuzzing of specific protocols and avoid interference.
- IPv6 Support: Extend descriptions and logic to support IPv6, including handling extension headers and specific IPv6 features.
- Reading Code: For understanding external network fuzzing implementation, refer to the original pull request in syzkaller and the current sources, focusing on
initialize_netdevices(),syz_emit_ethernet(), and network protocol descriptions insyzlang. - Upstream docs – See
docs/external_fuzzing_network.mdin the syzkaller repo for checksum helpers and packet templates.
- Packet Injection: Utilize
Target Selection
- Use syzbot coverage heatmap to identify subsystems with less-than-ideal coverage
- Look for subsystems with coverage between 1-20% (completely uncovered might have good reasons)
- Network subsystems are easier to fuzz than hardware-dependent ones
- Check syzbot dashboard to identify promising targets and current fuzzing status
Attack Surface Analysis
- Analyze kernel code to understand the attack surface (e.g., examining netlink handlers)
- Map out the available operations (e.g., socket operations, netlink commands)
- Understand the code paths that process user inputs for targeted fuzzing
Performance Optimization
- Use hardware virtualization when possible for better performance
- KVM on Linux, HVF on macOS can provide 3-5x speedup over TCG emulation
- Adapt QEMU parameters to work with available accelerators
Syzkaller Configuration and Setup
-
Cross-Architecture Setup:
- When configuring on non-standard hosts (e.g., ARM64 Mac), compile the target elements (kernel, rootfs) natively on Linux VM
- Go 1.23 fixes the internal linker, but you still need
CROSS_COMPILE=when the kernel uses a non‑GNU tool‑chain. - Specify OS/arch pairs when compiling:
make HOSTOS=darwin HOSTARCH=arm64 TARGETOS=linux TARGETARCH=arm64 - Build
syz-executoron a Linux machine and copy to your host if cross-compilation fails
-
Kernel Module Fuzzing:
- Extract constants with
syz-extracttargeting specific syscall descriptions:bin/syz-extract -os linux -sourcedir /path/to/linux -arch arm64 -build module_name.txt - If extraction fails, manually compile programs to determine constant values
- Use the obtained values to create/fix
.constfiles for your module
- Extract constants with
-
Configuration File Example:
{ "name": "QEMU-aarch64", "target": "linux/arm64", "http": ":56700", "workdir": "/path/to/workdir", "kernel_obj": "/path/to/kernel", "syzkaller": "/path/to/syzkaller", "image": "/path/to/rootfs.ext3", "sshkey": "/path/to/id_rsa", "procs": 8, "enable_syscalls": ["openat$module_name", "ioctl$IOCTL_CMD", "mmap"], "type": "qemu", "vm": { "count": 4, "qemu": "/path/to/qemu-system-aarch64", "cmdline": "console=ttyAMA0 root=/dev/vda", "kernel": "/path/to/Image", "cpu": 2, "mem": 2048 } }
Kernel fuzzing practicalities
-
Use
KCFIandKASANbuilds for safer fuzzing;CONFIG_DEBUG_INFO_BTF=yhelps symbolization. -
Prefer TUN/TAP packet injection over raw sockets for stable replay.
-
Stabilize coverage with
kcovfilters andsyz_cover_filter. -
Performance Considerations:
- For ARM64 Macs, thermal throttling can significantly reduce execution rates
- Monitor execution rates for performance degradation
- VM acceleration and hardware features can improve performance
- Consider using Hardware Tag-Based KASAN for better performance vs. coverage tradeoff
- Linux 6.8+ configs
- Enable:
CONFIG_KASAN=y(or HWASAN on AArch64),CONFIG_KCSAN=y,CONFIG_UBSAN=y,CONFIG_KCFI=y,CONFIG_DEBUG_INFO_BTF=y. - Prefer
CONFIG_KFENCE=nduring fuzzing; enable later to confirm bugs.
AFL
- Crafting high quality harness
- identify existing harnesses oss-fuzz
- adapt and enhance for your fuzzing objectives
- Corpus
- use
afl-tminandafl-cminto tune corpus dynamically
- use
- Code Coverage
- use
afl-covto understand the code coverage - then analyze and fine tune your harness
- and optimize your test corpus based on coverage feedback
- use
- Efficient Crash Triage
- use AFLTriage and AddressSanitizer
- try
afl-collect/afl-plotand enableASAN_OPTIONS=abort_on_error=1:symbolize=1
Modern AFL++ tips
- Use
-M/-Sfor parallel fuzzer instances; combine-c 0(cmplog) on some slaves. - Persistent mode (
__AFL_LOOP(N)) for hot loops; in‑process fuzzing withafl++-unicornfor emulated targets. - Dictionaries (
-x) andlaf-intel/split-switchesto simplify hard conditions at compile time.
MacOS
IPC Fuzzing
- We can mutate and fuzz the message that
mach_msgis sending- Simple to do but slow
- Hard to determine which process caused the crash
- Hard to identify code coverage
- We can directly send a message to Target message handler(skipping kernel)
- Very fast and easy to instrument
- Easy to understand what caused the crash
- but Different from end exploit, might need to invoke initialization routines
- Write a Fuzzing harness
void *lib_handle = dlopen("libexample.dylib", RTLD_LAZY);
pFunction = dlsym(lib_handle, "DesiredFunction");
EDR
EDR Attack Surface Overview
EDR solutions present a significant attack surface due to their complex architecture:
Potential vulnerability categories:
- Memory corruptions in file scanning & emulation (e.g., CVE-2021-1647)
- Arbitrary file deletion via symlink vulnerabilities
- User-Mode IPC authorization issues or memory corruptions
- User-to-driver authorization bypass
- Classic driver vulnerabilities (WDM, KMDF, Mini-Filter)
- Server-to-agent authentication flaws
- Parsing bugs in server responses
- Classic Windows application vulnerabilities (DLL hijacking, file permissions)
- Emulation/sandbox escapes
- Logic bugs in security implementations
Microsoft Defender's Scanning Engine (mpengine.dll)
Microsoft Defender includes a local analysis engine mpengine.dll that performs static checks and uses emulation environments for different file types. This engine presents a significant attack surface due to its complexity and the variety of file formats it processes.
Target Characteristics:
- Installed by default on Windows systems
- Runs as SYSTEM with high privileges
- Has 1-click remote attack surface through file scanning
- Processes numerous file formats with complex parsing logic
- Prone to memory corruption vulnerabilities
Fuzzing Methodology:
Snapshot Fuzzing with WTF:
- Uses Windows Terminal Framework for coverage-guided fuzzing
- Takes snapshots after Defender initiates file scanning
- Maintains identical configuration to real environment
- Avoids limitations of manual engine bootstrapping
Alternative Approaches:
- kAFL/NYX: Additional fuzzing frameworks tested
- Jackalope: Cross-platform coverage-guided fuzzer
- Manual harness: Historic approach using
RSIG_BOOTENGINEandRSIG_SCAN_STREAMBUFFER
Practical Attack Scenarios:
Web-based DoS:
<!-- Crash Defender via malicious file download -->
<a href="crash.pdf">Download PDF</a>
<!-- Crashes MsMpEng.exe when file is scanned -->
Network Share DoS:
# Upload crash file to SMB share before credential dumping
copy crash.doc \\target\share\
# Defender crashes when scanning uploaded file
mimikatz.exe privilege::debug sekurlsa::logonpasswords
Fuzzing Setup Requirements:
Snapshot Creation:
// Example WTF harness setup
if (!g_Backend->SetBreakpoint("nt!KeBugCheck2", [](Backend_t *Backend) {
const uint64_t BCode = Backend->GetArg(0);
const std::string Filename = fmt::format("crash-{:#x}", BCode);
Backend->Stop(Crash_t(Filename));
}))
Coverage Analysis:
- Use IDA Lighthouse for visualization
- Monitor for DRIVER_VERIFIER_DETECTED_VIOLATION (0xc4)
- Track IRQL_NOT_LESS_OR_EQUAL (0xa) crashes
Defense Implications:
- Demonstrates need for robust input validation
- Shows importance of crash recovery mechanisms
- Highlights risks of complex file parsing engines
- Suggests value of sandboxing scanning processes
Cross-platform mpengine.dll Fuzzing
Recent advances enable fuzzing the latest Windows Defender engine (v1.1.25020.1007) on Linux using loadlibrary with Intel PT coverage:
// Disable Lua VM to avoid stability issues
void my_lua_exec(){
return;
}
int main(int argc, char** argv){
// Hook luaV_execute to bypass Lua signature processing
insert_function_redirect((void*)luaV_execute_address, my_lua_exec, HOOK_REPLACE_FUNCTION);
// Setup persistent fuzzing loop
for (;;) {
size_t len;
uint8_t *buf;
HF_ITER(&buf, &len);
ScanDescriptor.UserPtr = fmemopen(buf, len, "r");
if (__rsignal(&KernelHandle, RSIG_SCAN_STREAMBUFFER, &ScanParams, sizeof ScanParams) != 0) {
// Handle scan results
}
}
}
Performance Optimizations
- Persistent Mode: Eliminates initialization overhead, achieving hundreds of exec/s
- Intel PT Coverage: Hardware-based tracing for binary-only targets
- Lua VM Bypassing: Reduces crashes and focuses on native code vulnerabilities
honggfuzz with Intel PT Setup
# Non-persistent mode (slower, ~4s/execution)
../honggfuzz/honggfuzz -i ~/input/ -W ~/workspace/ --linux_perf_ipt_block -t 10 -- ./mpclient_x64 ___FILE___
# Persistent mode (faster, hundreds/sec)
../honggfuzz/honggfuzz -i ~/input/ -W ~/workspace/ --linux_perf_ipt_block -t 10 -- ./mpclient_x64_persistent
Common Issues and Solutions
- Cache Files: Mock
mpcache-*file access to return NULL handles for 2025+ engines - Path Normalization: Use absolute paths (e.g.,
C:\inputvsinput) to avoid Lua failures - Floating Point Exceptions: Often originate from .NET emulator, require debugging
Lua VM Analysis and Bypassing
Understanding Defender's Lua Implementation:
Microsoft Defender uses Lua 5.1.5 for signature implementation, with native functions exposed through MpCommon and mp tables:
-- Example signature logic that can fail
local l_0_0 = ((MpCommon.PathToWin32Path)((mp.getfilename)(mp.FILEPATH_QUERY_FULL))):lower()
-- Calls native LsaMpCommonLib::PathToWin32Path() function
Debugging Lua Execution:
// Hook luaV_execute main execution loop
75a16bbdc 4c 8b f1 MOV R14,RCX ; R14 := lua_state
75a16bbdf 49 8b 46 28 MOV RAX,qword ptr [R14 + 0x28]
75a16bbe3 4d 8b 66 30 MOV R12,qword ptr [R14 + 0x30] ; R12 := state->savedpc
75a16bc07 41 8b 1c 24 MOV EBX,dword ptr [R12] ; EBX := Lua instruction (4 bytes)
// Common failure point in luaV_gettable()
if ((lua_TValue *)callinfo[2] <= key_scalar_val) {
luaG_runerror(state,"attempt to %s a %s value","index",type_name);
// "attempt to index a nil value" - throws C++ exception
}
Signature Extraction and Analysis:
- Use commial's scripts to decompress .VDM signature files
- luadec for full decompilation with restored headers
- LuaPytecode for low-level bytecode analysis
# Extract VDM contents and analyze bytecode
python extract_vdm.py defender.vdm
luadec extracted_bytecode.luac
Bypassing Strategy:
Replace Lua execution entirely to focus on native code vulnerabilities while maintaining unpacker functionality:
// Complete Lua bypass - maintains unpacker execution
void my_lua_exec(){
return; // Skip all signature processing
}
// Alternative: Selective bypassing for specific functions
if (lua_function_name == "problematic_signature") {
return; // Skip only problematic signatures
}
Fuzzing Scanning Engines
Setting Up WTF (WhatsApp Trace Framework) for EDR Fuzzing:
// Basic WTF harness for mpengine.dll fuzzing
#include "wtf.h"
// Crash handler for detecting vulnerabilities
if (!g_Backend->SetBreakpoint("nt!KeBugCheck2", [](Backend_t *Backend) {
const uint64_t BugCode = Backend->GetArg(0);
const uint64_t Parameter1 = Backend->GetArg(1);
// Log crash details
const std::string Filename = fmt::format("crash-{:#x}-{:#x}", BugCode, Parameter1);
DebugPrint("Crash detected: {} (BugCode: {:#x})\n", Filename, BugCode);
Backend->Stop(Crash_t(Filename));
})) {
DebugPrint("Failed to set crash breakpoint\n");
return false;
}
// Monitor specific crash types
g_Backend->SetBreakpoint("nt!KeBugCheckEx", CrashHandler);
Snapshot Positioning for Microsoft Defender:
# Trigger file scan via MpCmdRun.exe
MpCmdRun.exe -Scan -ScanType 3 -File "C:\test\target.exe"
# Alternative: Use Explorer context menu scan
# Right-click -> "Scan with Microsoft Defender"
# Monitor for scanning process start
Get-Process | Where-Object {$_.ProcessName -eq "MsMpEng"}
WTF Configuration Example:
{
"snapshot_path": "defender_scan.dmp",
"backend": "bochscpu",
"target": "mpengine.dll",
"max_iterations": 1000000,
"timeout": 30,
"coverage_breakpoints": [
"mpengine!UfsScannerWrapper::ScanFile",
"mpengine!pefile_scan_mp",
"mpengine!macho_scanfile"
]
}
Alternative Fuzzing Frameworks:
kAFL/NYX Setup:
# Install kAFL dependencies
git clone https://github.com/IntelLabs/kAFL.git
cd kAFL
./install.sh
# Create fuzzing target
python kafl_fuzz.py \
--memory 2048 \
--input corpus/ \
--work-dir workdir/ \
--seed-dir seeds/ \
--target targets/mpengine_target.py
Jackalope Configuration:
# Jackalope harness for EDR fuzzing
import jackalope
# Initialize fuzzer
fuzzer = jackalope.TargetFuzzer(
target_binary="MpCmdRun.exe",
target_args=["-Scan", "-ScanType", "3", "-File", "@@"],
coverage_type="drcov",
target_timeout=30000
)
# Add input corpus
fuzzer.add_corpus_dir("corpus/")
# Start fuzzing
fuzzer.fuzz()
Coverage Analysis Tools:
IDA Lighthouse Integration:
# Load WTF traces in IDA with Lighthouse
import lighthouse
lighthouse.load_coverage_file("wtf_coverage.log")
lighthouse.coverage.show_coverage()
Dynamic Analysis with Tenet:
# Time-travel debugging with Tenet
import tenet
trace = tenet.load_trace("wtf_trace.log")
trace.seek_to_address(0x7ffcdbb6e1e7) # OOB read location
File Format Corpus Building:
# Collect diverse file samples for fuzzing
$formats = @("*.exe", "*.dll", "*.pdf", "*.docx", "*.xlsx", "*.js", "*.vbs")
$corpus_dir = "C:\fuzzing\corpus\"
foreach ($format in $formats) {
Get-ChildItem -Path "C:\Windows\System32" -Filter $format -Recurse |
ForEach-Object { Copy-Item $_.FullName "$corpus_dir\$($_.Name)" }
}
# Add malware samples (use VirusTotal/MWDB)
# Add crafted samples with known vulnerabilities
Debugging Crashes:
# WinDBG analysis of mpengine crashes
.load wow64exts
!analyze -v
# Check for DRIVER_VERIFIER_DETECTED_VIOLATION (0xc4)
!verifier
# Examine call stack for OOB reads
k
!address @rax # Check if address is valid
# PageHeap analysis for heap corruption
!heap -p -a @rax
Driver Interface Fuzzing
FilterConnectionPort Fuzzing:
// Sophos Intercept X port fuzzing example
#include <windows.h>
#include <fltuser.h>
HANDLE hPort;
HRESULT hr = FilterConnectCommunicationPort(
L"\\SophosPortName",
0,
NULL,
0,
NULL,
&hPort
);
if (SUCCEEDED(hr)) {
// Send malformed messages
BYTE fuzzData[1024];
DWORD bytesReturned;
for (int i = 0; i < 10000; i++) {
// Generate mutated data
GenerateFuzzData(fuzzData, sizeof(fuzzData));
FilterSendMessage(
hPort,
fuzzData,
sizeof(fuzzData),
NULL,
0,
&bytesReturned
);
}
}
IOCTL Fuzzing:
// EDR device driver IOCTL fuzzing
#include <winioctl.h>
HANDLE hDevice = CreateFile(
L"\\\\.\\PaloEdrControlDevice",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hDevice != INVALID_HANDLE_VALUE) {
DWORD bytesReturned;
BYTE inputBuffer[4096];
BYTE outputBuffer[4096];
// Fuzz different IOCTL codes
DWORD ioctlCodes[] = {
0x2260D0, 0x2260D4, 0x2260D8, 0x2260DC,
// Add more discovered codes
};
for (DWORD ioctl : ioctlCodes) {
for (int i = 0; i < 1000; i++) {
GenerateFuzzData(inputBuffer, sizeof(inputBuffer));
DeviceIoControl(
hDevice,
ioctl,
inputBuffer,
sizeof(inputBuffer),
outputBuffer,
sizeof(outputBuffer),
&bytesReturned,
NULL
);
}
}
}
Mini-Filter Communication Port Fuzzing
Snapshot fuzzing approach:
- Target FilterConnectionPorts with malformed messages
- Use tools like WTF (WhatsApp Trace Framework) for coverage-guided fuzzing
- Focus on message parsing logic in mini-filter drivers
WTF Snapshot Fuzzing Implementation:
// Example WTF harness for mini-filter fuzzing
if (!g_Backend->SetBreakpoint("nt!KeBugCheck2", [](Backend_t *Backend) {
const uint64_t BCode = Backend->GetArg(0);
const uint64_t B0 = Backend->GetArg(1);
// Log crash details for analysis
const std::string Filename = fmt::format("crash-{:#x}-{:#x}", BCode, B0);
DebugPrint("KeBugCheck2: {}\n\n", Filename);
Backend->Stop(Crash_t(Filename));
}))
Fuzzing Setup Process:
- Snapshot Creation: Create snapshot at FilterConnectionPort message handling entry point
- Coverage Collection: Use IDA Lighthouse to visualize code coverage from fuzzing
- Crash Analysis: Monitor for DRIVER_VERIFIER_DETECTED_VIOLATION (0xc4) and IRQL_NOT_LESS_OR_EQUAL (0xa) bug checks
- False Positive Handling: Address snapshot IRQL inconsistencies where CR8 register stores interrupted state rather than actual IRQL
Debugging Techniques:
- Tenet Integration: Load WTF traces in IDA for time-travel debugging capability
- ret-sync: Synchronize WinDBG with IDA for live vs. snapshot execution comparison
- Memory Access Monitoring: Use breakpoints on
nt!ProbeForRead/nt!ProbeForWriteto track pointer validation
ETC
Rust Fuzzing & UB Hunting
Rust's memory safety guarantees don't eliminate all bugs; unsafe blocks, FFI boundaries, and logic errors still need fuzzing.
Complete Rust Fuzzing Stack
1. cargo-fuzz (libFuzzer integration)
cargo install cargo-fuzz
cargo fuzz init
RUSTFLAGS="-Zsanitizer=address" RUSTC_BOOTSTRAP=1 cargo fuzz run fuzz_target_1
# With coverage tracking
RUSTFLAGS="-Zsanitizer=address -C instrument-coverage" cargo fuzz coverage fuzz_target_1
llvm-cov show target/coverage/debug/fuzz_target_1 \
-instr-profile=fuzz-coverage.profdata -format=html > coverage.html
2. cargo-careful (Nightly Bounds Checking)
Catches UB that Miri misses, particularly in std and runtime edge cases:
cargo install cargo-careful
cargo +nightly careful test
cargo +nightly careful run --release
# Example: catches out-of-bounds that compile-time checks miss
# unsafe { slice.get_unchecked(idx) } with runtime bounds violations
3. Miri (Interpreter-Based UB Detection)
cargo +nightly miri setup
MIRIFLAGS="-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check" cargo +nightly miri test
# Advanced: track specific allocations
MIRIFLAGS="-Zmiri-track-alloc-id=1234" cargo +nightly miri test
4. loom (Concurrency Bug Detection)
For testing lock-free data structures and concurrent code:
// Example loom test for concurrent queue
#[cfg(loom)]
#[test]
fn test_concurrent_queue() {
loom::model(|| {
let queue = Arc::new(Queue::new());
let q1 = queue.clone();
let q2 = queue.clone();
let t1 = loom::thread::spawn(move || {
q1.push(1);
});
let t2 = loom::thread::spawn(move || {
q2.pop()
});
t1.join().unwrap();
t2.join().unwrap();
});
}
# Run loom tests
RUSTFLAGS="--cfg loom" cargo test --release
5. proptest (Property-Based Fuzzing)
Generate arbitrary inputs for property testing:
use proptest::prelude::*;
proptest! {
#[test]
fn test_parser_doesnt_panic(s in "\\PC*") {
// Property: parser should never panic on any input
let _ = std::panic::catch_unwind(|| {
parse_input(&s)
});
}
#[test]
fn test_serialization_roundtrip(data: Vec<u8>) {
// Property: deserialize(serialize(x)) == x
let serialized = serialize(&data);
let deserialized = deserialize(&serialized).unwrap();
prop_assert_eq!(data, deserialized);
}
}
Rust-Specific Vulnerability Classes
Unsafe Block Vulnerabilities:
// Common patterns to fuzz:
unsafe {
// 1. Vec::from_raw_parts with wrong capacity
Vec::from_raw_parts(ptr, len, wrong_capacity)
// 2. Unchecked indexing
slice.get_unchecked(oob_idx)
// 3. Transmute with size mismatch
std::mem::transmute::<SmallType, LargeType>(val)
// 4. Pointer arithmetic
ptr.offset(unchecked_offset)
}
FFI Boundary Bugs:
// Fuzz C library calls
#[no_mangle]
pub extern "C" fn parse_external(data: *const u8, len: usize) {
unsafe {
// Size mismatch between Rust and C types
let c_struct: CStruct = libc_parse(data, len as c_int); // Truncation!
}
}
Comprehensive Rust Fuzzing Workflow
# 1. Start with property tests (fast)
cargo test
# 2. Run Miri on test suite (catches UB)
cargo +nightly miri test
# 3. Add cargo-careful for runtime bounds checks
cargo +nightly careful test
# 4. Fuzz with cargo-fuzz (find crashes)
cargo fuzz run fuzz_target_1 -- -max_total_time=3600
# 5. Test concurrency with loom (if applicable)
RUSTFLAGS="--cfg loom" cargo test --release
# 6. Coverage analysis
cargo fuzz coverage fuzz_target_1
Integration with LibAFL (Advanced)
For Rust projects needing custom fuzzing logic:
use libafl::prelude::*;
// Custom Rust fuzzer with LibAFL
let mut harness = |input: &BytesInput| {
let data = input.bytes();
ExitKind::Ok
};
// Add custom mutators, feedback, etc.
Snapshot Fuzzing
- Takes a snapshot of the target program/OS memory state and registers
- Executes from snapshot in emulated environment, mutating memory data
- Resets to original snapshot when execution crashes or reaches specified point
- Advantages:
- Fast execution (skips program startup)
- Highly deterministic testing
- No source code required
- Easy tracking of code coverage and crashes
- Disadvantages:
- Time-consuming setup process
- Requires specialized knowledge
- Tools:
- wtf (what the fuzz) – Windows/Linux/macOS, supports > 4 GB snapshots
- Snapchange (AWS)
- Nyx v2 – integrates Intel® PT tracing and plugs into AFL++ (
NYX_MODE=1), sustaining ~20 k exec/s on full VM targets.
Embedded Systems Fuzzing
- Targets firmware, IoT devices, and embedded software
- Challenges:
- Architecture diversity (MIPS, ARM, etc.)
- Binary-only targets (no source access)
- Emulation requirements
- Limited or no sanitizer support
- Tools:
- LibAFL (0.15.2) – Modular Rust framework; key features include Unicorn engine, snapshot module, StatsD monitoring, LBRFeedback, SAND (Decoupled Sanitization) support, and a Rust-based binary-only ASan for its updated QEMU (v9.2.2) backend.
- Qemu-based emulation
- Nautilus - Grammar-based fuzzing
Language Ecosystem Fuzzing
- Go (1.18+): built‑in fuzzing via
go test -fuzz=Fuzz -run=^$ ./...withFuzzXxx(*testing.F, data []byte)signatures. - Python: Atheris for native CPython fuzzing; integrates with
pytestand OSS‑Fuzz. - Rust:
cargo-fuzz(libFuzzer), or LibAFL for custom pipelines; coverage viacargo llvm-cov.
CI/CD Fuzzing
-
Lightweight CI with ClusterFuzzLite or GitHub Actions matrix jobs; cache corpora between runs.
-
Example (GitHub Actions):
name: fuzz on: [push, pull_request] jobs: afl: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build with afl-clang-fast run: | sudo apt-get update && sudo apt-get install -y clang llvm make clean && CC=afl-clang-fast CXX=afl-clang-fast++ make -j - name: Run AFL++ (short smoke) run: | mkdir -p seeds findings echo "{}" > seeds/min.json timeout 15m afl-fuzz -i seeds -o findings -- ./target @@ || true libfuzzer: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build fuzz target run: | cmake -S . -B build -DCMAKE_CXX_FLAGS="-fsanitize=fuzzer,address,undefined -O1 -g" cmake --build build -j - name: Run fuzz target (sanitizers) run: timeout 15m ./build/my_fuzz_target -max_total_time=900 || true -
Upload artifacts (crashes, logs) in CI for manual triage:
- name: Upload crashes if: always() uses: actions/upload-artifact@v4 with: name: crashes path: | findings/**/crashes/* findings/**/hangs/* **/*.log
OSS‑Fuzz onboarding (quick checklist)
- Build system supports sanitizers and libFuzzer entrypoints
- Minimal seed corpus in
seed_corpus/ - Reproducers saved on crash; asserts map to sanitizer failures
project.yamlconfigured with timeouts, fuzzers, and language
LLM‑Guided Fuzzing
- Use LLMs to propose input dictionaries, seed structures, and targeted mutations when coverage stalls.
- Tools: ChatAFL/HyLLFuzz integrations; prompt with protocol docs or examples to generate grammar hints.
Grammar-Based Fuzzing
- Generates inputs according to a defined grammar/structure
- Useful for highly-structured inputs where random mutations would be rejected
- Hybrid approaches combine grammar with coverage feedback
- Examples:
- Nautilus - Grammar mutational fuzzer
- AFLSmart - Smart greybox fuzzer with input awareness
- Tlspuffin - Protocol fuzzer for TLS
Triaging and Analysis
- Process for analyzing fuzzer-generated crashes
- Techniques:
- Crash reproducibility - Using minimized test cases
- Crash minimization - Removing unnecessary input bytes
- Root cause analysis - Identifying the vulnerable code
- Backtrace reconstruction - Finding where the crash occurs
- Partial overwrites - Leaking memory addresses
- Memory pattern analysis - Identifying corruption patterns
Extended Instrumentation
- Extends coverage-guided fuzzing instrumentation to collect additional data beyond basic edge coverage
- Benefits:
- Identifies vulnerable execution paths more efficiently
- Provides better feedback to guide the fuzzer toward interesting targets
- Can focus fuzzing on historically vulnerable code areas
- Implementation techniques:
- Access program counter (PC) information during execution
- Track real-time stack traces to identify vulnerable functions
- Utilize return address information to trace execution paths
- Compare PC to specific address spaces of interest
- Example application:
- Modifying Fuzzilli's instrumentation for JerryScript to extract useful data
- Using
__builtin_return_address(0)to get current PC address - Tracking stack traces to narrow down root causes of vulnerabilities
- Potential improvements:
- Feed historical vulnerability data to guide future fuzzing
- Correlate "dangerous" files to their address space
- Direct fuzzer to focus on specific paths by prioritizing certain inputs
eBPF & Kernel‑in‑Kernel Fuzzing
- syzkaller's
executor_bpfand verifier‑stress templates exercise the in‑kernel eBPF verifier and JIT paths.
WebAssembly Runtime Fuzzing
- Differential‑fuzz runtimes such as V8, Wasmer, and Wasmtime with tools like
wasmtime-fuzzandwafl.
Smart‑Contract Fuzzing
- Use Echidna and Foundry‑fuzz for Solidity, or Move‑Fuzz for Aptos/Sui; all integrate cleanly into CI pipelines.
USB & Bluetooth Stack Fuzzing
- Snapshot‑plus‑wire‑capture harnesses from HydraUSBFuzz and BT‑SnoopFuzz enable realistic peripheral fuzzing.
DMA-BUF Subsystem Fuzzing
- Target memory-sharing frameworks in the Linux kernel that don't use traditional
copy_from_user - Focus on fuzzing:
- Custom implementations of
struct dma_buf_opscallbacks - Page fault handlers in VM operations structures
- DMA-BUF heap allocation operations
- Bounds checking in buffer access operations
- Custom implementations of
- Generate test cases that exercise:
- Memory mapping with different page offsets
- Buffer allocation with various sizes and flags
- Complex interaction patterns between different DMA-BUF operations
- Use coverage-guided fuzzing with kernel instrumentation to identify execution paths in these subsystems
AI/ML Model Fuzzing
- Tools such as DeepFuzz and TextFuzzer measure neuron coverage and search for jailbreak or adversarial failures.
Fuzzing Rust Crates
- First‑class Rust support through
cargo‑fuzz,honggfuzz‑rs, or LibAFL with Cargo feature flags.
Diagrams
Fuzzer Architecture
flowchart TB
Input["Input Generation/Mutation"]
Target["Target Program"]
Feedback["Feedback Mechanism"]
Crash["Crash Detection"]
Analysis["Crash Analysis"]
Input --> Target
Target --> Feedback
Feedback --> Input
Target --> Crash
Crash --> Analysis
subgraph Fuzzer
Input
Feedback
end
subgraph Target Environment
Target
Crash
end
subgraph Post-Processing
Analysis
end
Coverage-Guided Fuzzing Process
sequenceDiagram
participant F as Fuzzer
participant H as Harness
participant T as Target
participant C as Coverage Tracker
F->>F: Generate/Mutate Input
F->>H: Send Input
H->>T: Execute with Input
T->>C: Record Code Coverage
C->>F: Return Coverage Info
F->>F: Evaluate Coverage
F->>F: Add to Corpus if New Coverage
alt Crash Detected
T->>H: Crash Information
H->>F: Report Crash
F->>F: Save Crash Input
end
Memory Error Detection Techniques
flowchart LR
M["Memory Errors"]
ASan["Address Sanitizer"]
MSan["Memory Sanitizer"]
PHeap["Page Heap"]
Valgrind["Valgrind"]
M --> ASan
M --> MSan
M --> PHeap
M --> Valgrind
subgraph "Error Types"
BOF["Buffer Overflow"]
UAF["Use-After-Free"]
UIR["Uninitialized Read"]
end
ASan --> BOF
ASan --> UAF
MSan --> UIR
PHeap --> BOF
PHeap --> UAF
Valgrind --> BOF
Valgrind --> UAF
Valgrind --> UIR
> related_skills --same-repo
> offensive-xxe
offensive-xxe skill from SnailSploit/Claude-Red
> offensive-xss
offensive-xss skill from SnailSploit/Claude-Red
> offensive-windows-mitigations
offensive-windows-mitigations skill from SnailSploit/Claude-Red
> offensive-windows-boundaries
offensive-windows-boundaries skill from SnailSploit/Claude-Red