Ringkasan & Hubungan ke Vault

Fuzzing adalah jembatan antara Reverse Engineering (menemukan bug secara manual) dan Exploit Development (mengeksploitasi bug). Dengan fuzzing sistematis, lo bisa menemukan vulnerability pada skala yang gak mungkin dicapai manual. Catatan ini melengkapi hardware-hacking-re dengan automated bug discovery, dan malware-analysis-reverse-engineering-playbook dengan teknik exploit development modern.

Domain: Cyber Security / Vulnerability Research Tags: fuzzing afl libfuzzer symbolic-execution exploit-dev kernel

Daftar Isi

  1. Fundamental Fuzzing
  2. AFL++ Deep-Dive
  3. libFuzzer & Sanitizer Integration
  4. Structure-Aware Fuzzing
  5. Kernel Fuzzing dengan syzkaller
  6. Network & Protocol Fuzzing
  7. Hardware & Firmware Fuzzing
  8. Symbolic Execution & SMT Solvers
  9. CI/CD Fuzzing & OSS-Fuzz
  10. Crash Triage & Exploitability
  11. Workflow End-to-End
  12. Koneksi ke Vault

1. Fundamental Fuzzing

1.1 Apa Itu Fuzzing?

Fuzzing = memberikan input invalid/semi-valid/random ke program, lalu observasi apakah program crash/hang/leak. Tujuan: menemukan bugs yang gak kelihatan dari static analysis.

┌─────────────┐    ┌──────────────┐    ┌──────────┐    ┌──────────┐
│  Seed Corpus │───→│   Mutator    │───→│  Target   │───→│  Monitor │
└─────────────┘    └──────────────┘    └──────────┘    └──────────┘
                         ↑                   │
                         │           ┌───────┴───────┐
                         └───────────┤ Coverage Info  │
                                     └───────────────┘

1.2 Jenis Fuzzing

JenisCara KerjaContoh ToolKelebihanKekurangan
Black-boxInput random, no instrumentationzzuf, radamsaNo code changes neededCoverage rendah
White-boxSymbolic execution, constraint solvingSAGE, TritonCoverage maksimalScalability buruk
Grey-box (CG)Coverage feedback, lightweight instrumentasiAFL++, libFuzzer, HonggfuzzBest balance speed/coverageButuh source atau binary instrumentation
MutationalMutate existing seed (bitflip, havoc, splice)AFL++ (default)Simple, worksBisa stuck di path
GenerationalGenerate input from grammar/templatePeach, libprotobuf-mutatorInput valid structureButuh grammar definition
Grammar-basedInput dari grammar specificationDharma, NautilusDeep protocol coverageGrammar development effort

1.3 Coverage Metrics

  • Edge Coverage: count berapa kali edge A→B dieksekusi (standard AFL++)
  • Hit Count: seberapa sering edge dieksekusi (bucketed: 1, 2, 4, 8, 16+)
  • Line Coverage: line per line (gcov/lcov)
  • Function Coverage: function mana yang dipanggil
  • Branch Coverage: kedua sisi branch dieksekusi

1.4 Mutator Strategies

AFL++ mutator stages:

  1. Deterministic: sequential bitflips (1/2/4 bit), arithmetic add/sub, interest value, dictionary insertion — lama tapi exploration awal
  2. Havoc (default): random bitflips + insert + delete + splice + overwrite — kerjaan utama fuzzer
  3. Splice: kawin dua seed di titik potong random
  4. Custom mutator: lo bisa kasih mutator sendiri via AFL_CUSTOM_MUTATOR_LIBRARY
Bitflip:  01001010 → 01011010
Arithmetic: b"\x2a\x00\x00\x00" → b"\x2b\x00\x00\x00"
Interest:  b"\x01\x02\x03\x04" → b"\xff\xff\xff\xff" (nilai boundary)
Splice:    seed_a[0:len/2] + seed_b[len/2:]
Dictionary: ["GET", "POST", "Host:", ...] — common protocols

2. AFL++ Deep-Dive

2.1 Arsitektur AFL++

                  ┌──────────┐
                  │  afl-fuzz │ ←───────┐
                  └────┬─────┘          │
                       │               │
             ┌─────────┴─────────┐     │
             │    Fork Server     │     │
             │ (LLVM/PCGUARD)    │     │
             └─────────┬─────────┘     │
                       │               │
           ┌───────────┴───────────┐   │
           │   Instrumented Target  │   │
           │    (queue/*.cur_input) │───┘
           └───────────────────────┘

2.2 Instrumentasi

MetodeCommandKecepatanUse Case
LLVM LTOafl-clang-lto★★★★★Source available, best speed
LLVM PCGUARDafl-clang-fast★★★★Source available
GCCafl-gcc-fast★★★GCC projects
QEMUafl-qemu-trace★★Binary-only (x86/ARM)
Unicornafl-unicornBinary only, pure emulation
FRIDAafl-frida★★Binary only, persistent mode

2.3 Basic Command

# 1. Compile dengan AFL++ instrumentation
export AFL_USE_ASAN=1
export AFL_CC=afl-clang-lto
./configure --cc="$AFL_CC"
make -j$(nproc)
 
# 2. Fuzz
afl-fuzz -i seeds/ -o findings/ -- ./target @@
 
# 3. Parallel fuzzing (N core)
afl-fuzz -i seeds/ -o findings/ -M master -- ./target @@
afl-fuzz -i seeds/ -o findings/ -S slave1 -- ./target @@
afl-fuzz -i seeds/ -o findings/ -S slave2 -- ./target @@
 
# 4. Minimize crash
afl-tmin -i crash_file -o minimized_crash -- ./target @@

2.4 AFL++ Performance Tunables

# Power schedule (default: explore)
export AFL_FAST_CAL=1        # quick calibration
export AFL_CMPLOG=1          # Redqueen style input-to-state solving
export AFL_NO_CPU_RED=1      # supress CPU throttle warning
export AFL_EXPAND_HAVOC_NOW=1  # langsung pake havoc, skip deterministic
export AFL_SKIP_BIN_CHECK=1  # skip binary check (untuk QEMU mode)
 
# Crash exploration mode
export AFL_BENCH_UNTIL_CRASH=1  # stop setelah crash pertama

2.5 CMPLOG / Redqueen

Redqueen = teknik yang menemukan hubungan input-to-state. Contoh: program ngecek input[0] == 0xdeadbeef. Fuzzer biasa butuh 2^32 percobaan untuk guess magic byte. CMPLOG menggunakan QEMD mode untuk compare instruction trace, lalu patch input langsung dengan magic value.

export AFL_CMPLOG=1
afl-fuzz -i seeds/ -o findings/ -x dictionary.dict -- ./target @@

Ini alasan kenapa AFL++ bisa nge-bypass checksum dan magic value checks yang biasanya jadi bottleneck fuzzer.

2.6 Persistent Mode (LLVM)

Daripade fork server per input, persistent mode jalanin target dalam loop tanpa fork. 10-50× faster.

int main() {
  char buf[1024];
  while (__AFL_LOOP(10000)) {  // 10.000 iteration sebelum re-fork
    size_t len = read(0, buf, sizeof(buf) - 1);
    process_input(buf, len);
  }
  return 0;
}
afl-clang-lto -o persistent_target persistent_target.c
afl-fuzz -i seeds/ -o findings/ -- ./persistent_target

3. libFuzzer & Sanitizer Integration

3.1 libFuzzer Concepts

libFuzzer = in-process fuzzer yang jalan di LLVM. Beda dengan AFL++ (fork-based), libFuzzer panggil target function langsung dalam loop.

libFuzzer process:
┌──────────────────────────────────┐
│ ┌──────────┐   ┌────────────┐    │
│ │ Fuzzer   │──→│ Target Func │ ←───── Coverage feedback
│ │ Engine   │   │ (LLVM inst) │    │
│ └──────────┘   └────────────┘    │
│      ↑              │            │
│      └──────────────┘            │
└──────────────────────────────────┘

3.2 Basic Usage

// Fuzz target: LLVM akan panggil function ini
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  parse_input(data, size);  // target lo
  return 0;
}
# Compile
clang++ -fsanitize=fuzzer,address -o fuzzer_target fuzzer_target.cpp
 
# Run
./fuzzer_target -max_len=1024 -jobs=8 corpus/

3.3 Sanitizer Integration

SanitizerFlagDeteksi
AddressSanitizer (ASAN)-fsanitize=addressBuffer overflow, uaf, double free
UndefinedBehavior (UBSAN)-fsanitize=undefinedShift overflow, integer overflow
MemorySanitizer (MSAN)-fsanitize=memoryUninitialized memory
LeakSanitizer (LSAN)-fsanitize=leakMemory leak
ControlFlowIntegrity (CFI)-fsanitize=cfiCFI violation
HWASAN-fsanitize=hwaddressHardware-assisted ASAN (ARM)
# Best practice: ASAN + UBSAN + coverage
CFLAGS="-fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer"
export CFLAGS

3.4 libFuzzer Advanced

// Custom mutator (struct-aware fuzzing)
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size,
                                           size_t max_size, unsigned int seed) {
  Packet pkt;
  pkt.ParseFromArray(data, size);  // Protobuf-aware mutation
  // Mutate packet fields
  pkt.set_type(pkt.type() ^ (rand() & 0xff));
  pkt.SerializeToArray(data, max_size);
  return pkt.ByteSizeLong();
}
 
// Corpus splitting
// Set environment variable:
// FUZZER_CORPUS_DIR=/path/to/corpus — detects new coverage

3.5 Comparison: AFL++ vs libFuzzer

AspectAFL++libFuzzer
Process modelFork-based (fork per run)In-process (function call)
Speed~1K exec/s (heavy target)~100K exec/s (same target)
InstrumentationLLVM, GCC, QEMU, FRIDA, UnicornLLVM only
Binary-only✅ (QEMU/FRIDA)
ParallelMulti-instance via -SBuilt-in -jobs=8
Custom mutator.so libraryLLVMFuzzerCustomMutator
Corpus pruningBuilt-in cminAuto-minimize
Network target❌ (but can wrap)❌ (but can wrap)

4. Structure-Aware Fuzzing

4.1 Kenapa Perlu?

Fuzzer biasa generate byte random. Untuk protokol kompleks (TLS, DNS, HTTP/2), byte random mentah gak akan tembus parsing layer pertama. Structure-aware fuzzing generate input yang secara format valid, cuma semantic-nya corrupt.

Mutational (byte-level):    "\x01\xff\x00\xab\x12" → parsing fails di byte 0
Grammar-based (structure):  "GET /index.html HTTP/1.1\r\nHost: ..." → valid HTTP

4.2 libprotobuf-mutator

// 1. Define protobuf schema
message Packet {
  enum Type { SYN = 0; ACK = 1; DATA = 2; FIN = 3; }
  required Type type = 1;
  required uint32 seq = 2;
  optional bytes payload = 3;
}
 
// 2. Fuzz target with protobuf-aware mutator
#include <libprotobuf-mutator/src/libfuzzer.h>
 
DEFINE_PROTO_FUZZER(const Packet& packet) {
  process_packet(packet);
}

4.3 Grammar-based: Nautilus & Dharma

Nautilus memungkinkan lo define grammar dalam Python:

grammar = {
    "http_request": [["method", " ", "url", " ", "version", "\r\n", "header", "\r\n"]],
    "method": ["GET", "POST", "PUT", "DELETE"],
    "url": ["/", "/index.html", "/api/v1/data"],
    "version": ["HTTP/1.0", "HTTP/1.1"],
    "header": [["Host: example.com"], ["Content-Length: ", num]],
}

5. Kernel Fuzzing dengan syzkaller

5.1 Arsitektur syzkaller

Host Machine                    Target VM/Device
┌─────────────────┐            ┌──────────────────┐
│ syz-manager      │  SSH/RPC  │  syz-fuzzer      │
│ ├── Program gen  │──────────→│  ├── syscall exec │
│ ├── Corpus DB    │  ◄────────│  └── coverage rep │
│ ├── Crash DB     │  RPC      └──────────────────┘
│ └── Dashboard    │
└─────────────────┘

5.2 Syzlang — Syscall Description Language

// File: linux/system.syz
include <uapi/linux/socket.h>
 
resource fd[sock_fd]: -1
 
open$socket(family flags[32], type flags[32], proto flags[32]) fd
{
  syscall openat(AT_FDCWD, filename ptr[in, string], flags flags[open_flags], mode flags[open_mode])
}
 
// Lebih complex — ioctl untuk network device
ioctl$SIOCGIFINDEX(fd fd, cmd const[SIOCGIFINDEX], arg ptr[in, struct ifreq])
{
  syscall ioctl(fd, cmd, arg)
}
 
struct ifreq {
  ifr_name    array[char, IFNAMSIZ]
  ifr_ifindex int32
}

5.3 Setup syzkaller

# Minimal config (linux qemu)
cat > my.cfg << 'EOF'
{
  "name": "linux-kernel",
  "target": "linux/amd64",
  "http": ":56700",
  "workdir": "/workdir",
  "kernel_obj": "/linux/linux-6.1",
  "kernel_src": "/linux/linux-6.1",
  "sandbox": "none",
  "procs": 4,
  "type": "qemu",
  "vm": {
    "count": 2,
    "cpu": 2,
    "mem": 2048,
    "kernel": "/linux/arch/x86/boot/bzImage",
    "image": "/linux/image/stretch.img"
  }
}
EOF
 
# Run
bin/syz-manager -config=my.cfg

6. Network & Protocol Fuzzing

6.1 boofuzz (Network Protocol Fuzzer)

from boofuzz import *
 
session = Session(target=Target(connection=TCPSocketConnection("192.168.1.1", 80)))
define_protocol(session)
session.fuzz()
 
def define_protocol(session):
    s_initialize("HTTP_REQUEST")
    s_static("GET ")
    s_string("index.html")
    s_static(" HTTP/1.1\r\n")
    s_static("Host: ")
    s_string("example.com")
    s_static("\r\n\r\n")

6.2 AFLnet (Stateful Protocol Fuzzing)

AFLnet menambahkan state-aware fuzzing untuk protokol network:

Fuzzer tahu state machine target!
State: HANDSHAKE → AUTH → REQUEST → RESPONSE
AFLnet track transitions antar state, dan fuzz per state

7. Hardware & Firmware Fuzzing

7.1 Firmware Rehosting — firmadyne / FirmAFL

Untuk fuzz firmware embedded, lo perlu rehost (emulate) firmware-nya:

# firmadyne workflow
python3 scripts/makeImage.py -i firmware.bin -o /tmp/images/
sudo python3 scratch/run.sh /tmp/images/firmware_image
# Sekarang firmware jalan di QEMU → fuzz via AFLnet
afl-fuzz -i seeds/ -o findings/ -Q -- ./qemu-system-arm ...

Masalah utama: firmware gak selalu boot di QEMU (butuh hardware check, peripheral driver). Solusi partial: patch firmware atau emulate peripheral minimal.

7.2 Nyx / Fuzzware — Binary-Only HW Fuzzing

Fuzzware = automated firmware fuzzing tanpa manual rehosting. Menggunakan Unicorn engine + QEMU + symbolic execution untuk auto-model peripheral.

firmware.bin → Fuzzware → model peripheral → fuzz dengan AFL++

Use case: IoT router firmware, IOT devices, embedded Linux.

8. Symbolic Execution & SMT Solvers

8.1 Kenapa Kombinasi Fuzzing + Symbolic?

Fuzzing mencapai code coverage tinggi secara cepat, tapi gak bisa ngehandle constraint kompleks (checksum, complex branch conditions). Symbolic execution bisa solve constraint, tapi lambat. Hybrid: fuzzer untuk exploration → symbolic execution untuk path yang stuck.

8.2 Angr — Symbolic Execution Framework

import angr
 
# Load binary
proj = angr.Project("vuln_binary", auto_load_libs=False)
 
# Symbolic dari stdin
state = proj.factory.entry_state(
    stdin=angr.SimFile("/dev/stdin")
)
 
# Symbolic exploration
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=0x400000 + 0x1234)  # target address (win function)
 
if simgr.found:
    found_state = simgr.found[0]
    stdin_input = found_state.posix.stdin.concretize()
    print(f"Found input: {stdin_input}")

8.3 Z3 SMT Solver

from z3 import *
 
# Solve: find input such that buf[i] * 5 == 100
buf = [BitVec(f'buf_{i}', 8) for i in range(16)]
s = Solver()
 
for i in range(4):
    s.add(buf[i] * 5 == 100)  # buf[i] == 20
 
s.add(buf[0] == ord('A'))  # specific constraint
 
if s.check() == sat:
    model = s.model()
    print([model[buf[i]] for i in range(4)])

Z3 Theories untuk binary analysis:

  • QF_BV: quantifier-free bitvector — arithmetic, bitwise, shift
  • QF_ABV: arrays + bitvector — memory modeling
  • QF_FPBV: floating point + bitvector
  • Strings: string constraints (path explosion risk)

8.4 Fuzzing + Symbolic = Driller / FirmAFL

Driller (untuk binary) = AFL++ untuk exploration → Angr untuk solve constraint path:

AFL: alur sederhana → coverage → continue
Angr: AFL stuck di path X → symbolic execute X → solve constraint → inject seed → AFL lanjut

9. CI/CD Fuzzing & OSS-Fuzz

9.1 OSS-Fuzz Workflow

Google OSS-Fuzz = continuous fuzzing untuk open source.

┌────────────┐    ┌───────────┐    ┌───────────┐    ┌──────────┐
│  Developer  │───→│ OSS-Fuzz  │───→│ Cluster   │───→│ Issue    │
│  (PR/build) │    │  BuildBot │    │ Fuzz (GCE)│    │  Tracker │
└────────────┘    └───────────┘    └───────────┘    └──────────┘
                       │
                       ↓
                  ┌──────────┐
                  │ Coverage │
                  │ Report   │
                  └──────────┘

9.2 ClusterFuzzLite (Modern)

# .github/workflows/fuzz.yml
name: Fuzzing
on: [push, pull_request]
 
jobs:
  fuzz:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build fuzzers
        run: |
          docker build -t fuzzer -f Dockerfile.fuzz .
      - uses: google/clusterfuzzlite@v1
        with:
          fuzz_seconds: 300

10. Crash Triage & Exploitability

10.1 Crash Classification

ClassDescriptionAction
ExploitableControl RIP, arbitrary writePrioritize analysis
Probably ExploitableControlled dereferenceManual analysis
May be ExploitablePartial controlLow priority
UnknownNo clear exploitation primitiveDedup & log
Not ExploitableNull deref, assertionInform dev

10.2 Bang — Crash Analysis Tool

# AFL++ crash explorer
afl-crash-analyzer -i findings/default/crashes/ -- ./target @@
 
# Manual stack analysis
gdb --batch -ex "run < crash_file" -ex "bt" ./target
 
# Symbolicate crash
addr2line -e ./target -f -C 0x401234

10.3 Exploitability Heuristic

SignalContextExploitable?
SIGSEGVRIP = offset of input buffer✅ Almost guaranteed
SIGSEGVRIP = 0x4141414141414141✅ ROP chain possible
SIGSEGVRIP = controlled but limited⚠️ Partial overwrite possible
SIGABRTASAN: heap-buffer-overflow✅ Depends on primitive
SIGABRTASAN: stack-buffer-overflow✅ Often ROP-able
SIGSEGVRIP = NULL (null deref)❌ Usually denial-of-service

11. Workflow End-to-End

11.1 Target Selection

Prioritas target berdasarkan:

  1. Attack surface: network-facing, parsing user input
  2. Complexity: complex parsers (PDF, video, image) → high bug density
  3. Criticality: kernel modules, privilege boundary
  4. History: pernah punya CVE → pasti masih ada bug lain

11.2 End-to-End Pipeline

Phase 1: Reconnaissance
├── Static analysis target (Ghidra/IDA)
├── Identify input surface (file format, protocol, API)
├── Collect seed corpus (valid input samples)
└── Write harness / wrapper

Phase 2: Instrumentation
├── Source available → LLVM (AFL++ / libFuzzer)
├── Binary only (ELF) → QEMU mode / FRIDA
├── Binary only (PE) → WinAFL DynamoRIO
└── Kernel → syzkaller

Phase 3: Fuzzing
├── Single-core (exploration)
├── Multi-core (farming: 1 master + N slaves)
├── Parallel with cross-pollination
└── CI/CD integration (ClusterFuzzLite)

Phase 4: Triage
├── Deduplicate (stack hash)
├── Minimize (afl-tmin)
├── Exploitability classification
└── CVE assignment readiness

Phase 5: Exploitation
├── Control flow analysis
├── ROP chain / heap spray
├── Exploit PoC
└── Disclosure / report

11.3 Resource Sizing

Target TypeSuggested CoreDurationSuccess Rate
Command-line parser1-4 core1-24 jam★★★ High
Library (libpng, libxml)4-8 core1-7 hari★★★ High
Network protocol8-16 core1-30 hari★★ Medium
Kernel syscall16-32 core + VM7-90 hari★★ Medium
Firmware (QEMU rehost)4-8 core1-60 hari★ Low (emu issue)

12. Koneksi ke Vault

NoteHubungan
hardware-hacking-reTarget fuzzing: firmware, UART, JTAG — fuzzing automation
malware-analysis-reverse-engineering-playbookRE workflow → fuzzing target identification
incident-response-frameworkVulnerability discovery → responsible disclosure
web-hacking-exploitationWeb fuzzing methodology → Ffuf, Burp Intruder
purple-team-osi-killchainFuzzing di phase reconnaissance + weaponization
c2-server-fixPersistence mechanisms bisa divalidasi via fuzzing

Tool Comparison Summary

Tool                 Target Type        Difficulty   Cost
─────────────────────────────────────────────────────────
AFL++                Binary/ELF/Linux   Medium       Free
libFuzzer            ELF Libraries      Low          Free
syzkaller            Linux Kernel       High         Free (VM)
boofuzz              Network Protocols  Medium       Free
Peach                Network/File       High         $$$ (Pro)
WinAFL               Windows PE         Medium       Free
Honggfuzz            ELF/Linux          Low          Free
Angr                 RE/Analysis        High         Free
FirmAFL              Firmware           Very High    Free (QEMU)
ClusterFuzzLite      CI/CD              Medium       Free

📚 Referensi

  1. AFL++ documentation: https://aflplus.plus/
  2. libFuzzer tutorial: https://llvm.org/docs/LibFuzzer.html
  3. syzkaller: https://github.com/google/syzkaller
  4. OSS-Fuzz: https://github.com/google/oss-fuzz
  5. Angr: https://angr.io/
  6. Z3 Prover: https://github.com/Z3Prover/z3
  7. “Fuzzing: Brute Force Vulnerability Discovery” — Sutton, Greene, Amini
  8. Fuzzware: https://fuzzware.io/