ctf-agent 1.2.0

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 (152) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +192 -0
  3. package/README.md +522 -0
  4. package/agents/ctf-analyzer.md +58 -0
  5. package/agents/ctf-controller.md +151 -0
  6. package/agents/ctf-speedrun.md +74 -0
  7. package/bin/ctf-agent.js +119 -0
  8. package/docker-compose.yml +13 -0
  9. package/mcp_config.json +19 -0
  10. package/package.json +44 -0
  11. package/references/ctf-triage-ladder.md +68 -0
  12. package/references/exploit-databases.md +575 -0
  13. package/references/llm-safety-and-policy-compliance.md +173 -0
  14. package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
  15. package/references/security-events-and-intelligence.md +566 -0
  16. package/references/version-matrix.md +59 -0
  17. package/rules/ctf-execution-rules.md +44 -0
  18. package/rules/ctf-safety-framing-rules.md +140 -0
  19. package/rules/flag-validation-rules.md +25 -0
  20. package/scripts/__init__.py +1 -0
  21. package/scripts/ctf-tools.lock +205 -0
  22. package/scripts/ctf_init.py +1026 -0
  23. package/scripts/ctf_update.py +583 -0
  24. package/scripts/ctfd_client.py +81 -0
  25. package/scripts/cve_lookup.py +453 -0
  26. package/scripts/extract_flags.py +155 -0
  27. package/scripts/install_as_agent.py +278 -0
  28. package/scripts/install_ctf_tools.sh +603 -0
  29. package/scripts/parallel_triage.py +395 -0
  30. package/scripts/prompt_policy_sanitizer.py +283 -0
  31. package/scripts/scope_guard.py +444 -0
  32. package/scripts/skill_validator.py +504 -0
  33. package/scripts/workspace_cleaner.py +141 -0
  34. package/skills/ctf-ai-ml/SKILL.md +120 -0
  35. package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
  36. package/skills/ctf-ai-ml/llm-attacks.md +487 -0
  37. package/skills/ctf-ai-ml/model-attacks.md +422 -0
  38. package/skills/ctf-crypto/SKILL.md +320 -0
  39. package/skills/ctf-crypto/advanced-math.md +798 -0
  40. package/skills/ctf-crypto/classic-ciphers.md +651 -0
  41. package/skills/ctf-crypto/ecc-attacks.md +347 -0
  42. package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
  43. package/skills/ctf-crypto/exotic-crypto.md +528 -0
  44. package/skills/ctf-crypto/historical.md +113 -0
  45. package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
  46. package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
  47. package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
  48. package/skills/ctf-crypto/modern-ciphers.md +649 -0
  49. package/skills/ctf-crypto/prng-attacks.md +257 -0
  50. package/skills/ctf-crypto/prng.md +664 -0
  51. package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
  52. package/skills/ctf-crypto/rsa-attacks.md +487 -0
  53. package/skills/ctf-crypto/stream-ciphers.md +390 -0
  54. package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
  55. package/skills/ctf-forensics/3d-printing.md +121 -0
  56. package/skills/ctf-forensics/SKILL.md +379 -0
  57. package/skills/ctf-forensics/disk-advanced.md +497 -0
  58. package/skills/ctf-forensics/disk-and-memory.md +491 -0
  59. package/skills/ctf-forensics/disk-recovery.md +699 -0
  60. package/skills/ctf-forensics/linux-forensics.md +511 -0
  61. package/skills/ctf-forensics/network-advanced.md +583 -0
  62. package/skills/ctf-forensics/network.md +645 -0
  63. package/skills/ctf-forensics/peripheral-capture.md +287 -0
  64. package/skills/ctf-forensics/signals-and-hardware.md +713 -0
  65. package/skills/ctf-forensics/steganography.md +694 -0
  66. package/skills/ctf-forensics/stego-advanced-2.md +475 -0
  67. package/skills/ctf-forensics/stego-advanced.md +481 -0
  68. package/skills/ctf-forensics/stego-image.md +691 -0
  69. package/skills/ctf-forensics/windows.md +625 -0
  70. package/skills/ctf-malware/SKILL.md +181 -0
  71. package/skills/ctf-malware/c2-and-protocols.md +274 -0
  72. package/skills/ctf-malware/pe-and-dotnet.md +108 -0
  73. package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
  74. package/skills/ctf-misc/SKILL.md +498 -0
  75. package/skills/ctf-misc/bashjails.md +323 -0
  76. package/skills/ctf-misc/ctfd-navigation.md +465 -0
  77. package/skills/ctf-misc/dns.md +255 -0
  78. package/skills/ctf-misc/encodings-advanced.md +504 -0
  79. package/skills/ctf-misc/encodings.md +431 -0
  80. package/skills/ctf-misc/games-and-vms-2.md +254 -0
  81. package/skills/ctf-misc/games-and-vms-3.md +690 -0
  82. package/skills/ctf-misc/games-and-vms-4.md +229 -0
  83. package/skills/ctf-misc/games-and-vms.md +529 -0
  84. package/skills/ctf-misc/linux-privesc.md +333 -0
  85. package/skills/ctf-misc/pyjails.md +671 -0
  86. package/skills/ctf-misc/rf-sdr.md +91 -0
  87. package/skills/ctf-osint/SKILL.md +198 -0
  88. package/skills/ctf-osint/geolocation-and-media.md +464 -0
  89. package/skills/ctf-osint/social-media.md +312 -0
  90. package/skills/ctf-osint/web-and-dns.md +341 -0
  91. package/skills/ctf-pwn/SKILL.md +214 -0
  92. package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
  93. package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
  94. package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
  95. package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
  96. package/skills/ctf-pwn/advanced-exploits.md +773 -0
  97. package/skills/ctf-pwn/advanced.md +326 -0
  98. package/skills/ctf-pwn/field-notes.md +245 -0
  99. package/skills/ctf-pwn/format-string.md +694 -0
  100. package/skills/ctf-pwn/heap-fsop.md +285 -0
  101. package/skills/ctf-pwn/heap-techniques-2.md +333 -0
  102. package/skills/ctf-pwn/heap-techniques.md +513 -0
  103. package/skills/ctf-pwn/kernel-bypass.md +421 -0
  104. package/skills/ctf-pwn/kernel-techniques.md +366 -0
  105. package/skills/ctf-pwn/kernel.md +636 -0
  106. package/skills/ctf-pwn/overflow-basics.md +611 -0
  107. package/skills/ctf-pwn/rop-advanced.md +725 -0
  108. package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
  109. package/skills/ctf-pwn/sandbox-escape.md +313 -0
  110. package/skills/ctf-reverse/SKILL.md +163 -0
  111. package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
  112. package/skills/ctf-reverse/anti-analysis.md +693 -0
  113. package/skills/ctf-reverse/field-notes.md +376 -0
  114. package/skills/ctf-reverse/languages-compiled.md +666 -0
  115. package/skills/ctf-reverse/languages-platforms.md +592 -0
  116. package/skills/ctf-reverse/languages.md +553 -0
  117. package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
  118. package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
  119. package/skills/ctf-reverse/patterns-ctf.md +670 -0
  120. package/skills/ctf-reverse/patterns-runtime.md +274 -0
  121. package/skills/ctf-reverse/patterns.md +572 -0
  122. package/skills/ctf-reverse/platforms-hardware.md +387 -0
  123. package/skills/ctf-reverse/platforms.md +664 -0
  124. package/skills/ctf-reverse/tools-advanced-2.md +421 -0
  125. package/skills/ctf-reverse/tools-advanced.md +407 -0
  126. package/skills/ctf-reverse/tools-dynamic.md +679 -0
  127. package/skills/ctf-reverse/tools-emulation.md +319 -0
  128. package/skills/ctf-reverse/tools.md +573 -0
  129. package/skills/ctf-web/SKILL.md +153 -0
  130. package/skills/ctf-web/auth-and-access-2.md +82 -0
  131. package/skills/ctf-web/auth-and-access.md +783 -0
  132. package/skills/ctf-web/auth-infra.md +321 -0
  133. package/skills/ctf-web/auth-jwt.md +186 -0
  134. package/skills/ctf-web/client-side-advanced.md +739 -0
  135. package/skills/ctf-web/client-side.md +529 -0
  136. package/skills/ctf-web/cves.md +373 -0
  137. package/skills/ctf-web/field-notes.md +482 -0
  138. package/skills/ctf-web/node-and-prototype.md +200 -0
  139. package/skills/ctf-web/server-side-2.md +337 -0
  140. package/skills/ctf-web/server-side-advanced-2.md +559 -0
  141. package/skills/ctf-web/server-side-advanced-3.md +125 -0
  142. package/skills/ctf-web/server-side-advanced-4.md +480 -0
  143. package/skills/ctf-web/server-side-advanced.md +378 -0
  144. package/skills/ctf-web/server-side-deser.md +443 -0
  145. package/skills/ctf-web/server-side-exec-2.md +799 -0
  146. package/skills/ctf-web/server-side-exec.md +457 -0
  147. package/skills/ctf-web/server-side.md +629 -0
  148. package/skills/ctf-web/sql-injection.md +790 -0
  149. package/skills/ctf-web/web3.md +374 -0
  150. package/skills/ctf-writeup/SKILL.md +90 -0
  151. package/skills/solve-challenge/SKILL.md +269 -0
  152. package/skills.json +16 -0
@@ -0,0 +1,679 @@
1
+ # CTF Reverse - Dynamic Analysis Tools
2
+
3
+ ## Table of Contents
4
+ - [Frida (Dynamic Instrumentation)](#frida-dynamic-instrumentation)
5
+ - [Installation](#installation)
6
+ - [Basic Function Hooking](#basic-function-hooking)
7
+ - [Anti-Debug Bypass](#anti-debug-bypass)
8
+ - [Memory Scanning and Patching](#memory-scanning-and-patching)
9
+ - [Function Replacement](#function-replacement)
10
+ - [Tracing and Stalker](#tracing-and-stalker)
11
+ - [r2frida (Radare2 + Frida Integration)](#r2frida-radare2--frida-integration)
12
+ - [Frida for Android/iOS](#frida-for-androidios)
13
+ - [Frida Memoization for Recursive Function Speedup (hxp CTF 2017)](#frida-memoization-for-recursive-function-speedup-hxp-ctf-2017)
14
+ - [angr (Symbolic Execution)](#angr-symbolic-execution)
15
+ - [angr Installation](#angr-installation)
16
+ - [Basic Path Exploration](#basic-path-exploration)
17
+ - [Symbolic Input with Constraints](#symbolic-input-with-constraints)
18
+ - [Hook Functions to Simplify Analysis](#hook-functions-to-simplify-analysis)
19
+ - [Exploring from Specific Address](#exploring-from-specific-address)
20
+ - [Common Patterns and Tips](#common-patterns-and-tips)
21
+ - [Dealing with Path Explosion](#dealing-with-path-explosion)
22
+ - [angr CFG Recovery](#angr-cfg-recovery)
23
+ - [lldb (LLVM Debugger)](#lldb-llvm-debugger)
24
+ - [Basic Commands](#basic-commands)
25
+ - [Scripting (Python)](#scripting-python)
26
+ - [x64dbg (Windows Debugger)](#x64dbg-windows-debugger)
27
+ - [Key Features](#key-features)
28
+ - [Scripting](#scripting)
29
+ - [Common CTF Workflow](#common-ctf-workflow)
30
+ - [GDB Register Side-Channel on putchar() (picoCTF 2018)](#gdb-register-side-channel-on-putchar-picoctf-2018)
31
+ - [radare2 Visual Panels for Custom VM Tracing (OTW Advent 2018)](#radare2-visual-panels-for-custom-vm-tracing-otw-advent-2018)
32
+ - [libSegFault.so Register Dump at Crash (OTW Advent 2018)](#libsegfaultso-register-dump-at-crash-otw-advent-2018)
33
+ - [r2pipe Binary Walking + DP Constraint Solver (OTW Advent 2018)](#r2pipe-binary-walking--dp-constraint-solver-otw-advent-2018)
34
+ - [GDB Commands at strcmp to Recover Dynamic XOR Key (TAMUctf 2019)](#gdb-commands-at-strcmp-to-recover-dynamic-xor-key-tamuctf-2019)
35
+
36
+ For Qiling/Triton emulation and Intel Pin / LD_PRELOAD side-channel techniques, see [tools-emulation.md](tools-emulation.md).
37
+
38
+ ---
39
+
40
+ ## Frida (Dynamic Instrumentation)
41
+
42
+ Frida injects JavaScript into running processes for real-time hooking, tracing, and modification. Essential for anti-debug bypass, runtime inspection, and mobile RE.
43
+
44
+ ### Installation
45
+
46
+ ```bash
47
+ pip install frida-tools frida
48
+ # Verify
49
+ frida --version
50
+ ```
51
+
52
+ ### Basic Function Hooking
53
+
54
+ ```javascript
55
+ // hook.js — intercept a function and log arguments/return value
56
+ Interceptor.attach(Module.findExportByName(null, "strcmp"), {
57
+ onEnter: function(args) {
58
+ this.arg0 = Memory.readUtf8String(args[0]);
59
+ this.arg1 = Memory.readUtf8String(args[1]);
60
+ console.log(`strcmp("${this.arg0}", "${this.arg1}")`);
61
+ },
62
+ onLeave: function(retval) {
63
+ console.log(` → ${retval}`);
64
+ }
65
+ });
66
+ ```
67
+
68
+ ```bash
69
+ # Attach to running process
70
+ frida -p $(pidof binary) -l hook.js
71
+
72
+ # Spawn and instrument from start
73
+ frida -f ./binary -l hook.js --no-pause
74
+
75
+ # One-liner: hook strcmp and dump comparisons
76
+ frida -f ./binary --no-pause -e '
77
+ Interceptor.attach(Module.findExportByName(null, "strcmp"), {
78
+ onEnter(args) {
79
+ console.log("strcmp:", Memory.readUtf8String(args[0]), Memory.readUtf8String(args[1]));
80
+ }
81
+ });
82
+ '
83
+ ```
84
+
85
+ ### Anti-Debug Bypass
86
+
87
+ ```javascript
88
+ // Bypass ptrace(PTRACE_TRACEME) — returns 0 (success) without calling
89
+ Interceptor.attach(Module.findExportByName(null, "ptrace"), {
90
+ onEnter: function(args) {
91
+ this.request = args[0].toInt32();
92
+ },
93
+ onLeave: function(retval) {
94
+ if (this.request === 0) { // PTRACE_TRACEME
95
+ retval.replace(ptr(0));
96
+ console.log("[*] ptrace(TRACEME) bypassed");
97
+ }
98
+ }
99
+ });
100
+
101
+ // Bypass IsDebuggerPresent (Windows)
102
+ var isDbg = Module.findExportByName("kernel32.dll", "IsDebuggerPresent");
103
+ Interceptor.attach(isDbg, {
104
+ onLeave: function(retval) {
105
+ retval.replace(ptr(0));
106
+ }
107
+ });
108
+
109
+ // Bypass timing checks — hook clock_gettime to return constant
110
+ Interceptor.attach(Module.findExportByName(null, "clock_gettime"), {
111
+ onLeave: function(retval) {
112
+ // Force constant timestamp to defeat timing checks
113
+ var ts = this.context.rsi || this.context.x1; // x86 or ARM
114
+ Memory.writeU64(ts, 0); // tv_sec
115
+ Memory.writeU64(ts.add(8), 0); // tv_nsec
116
+ }
117
+ });
118
+ ```
119
+
120
+ ### Memory Scanning and Patching
121
+
122
+ ```javascript
123
+ // Scan for flag pattern in memory
124
+ Process.enumerateRanges('r--').forEach(function(range) {
125
+ Memory.scan(range.base, range.size, "66 6c 61 67 7b", { // "flag{"
126
+ onMatch: function(address, size) {
127
+ console.log("[FLAG] Found at:", address, Memory.readUtf8String(address, 64));
128
+ },
129
+ onComplete: function() {}
130
+ });
131
+ });
132
+
133
+ // Patch instruction (NOP out a check)
134
+ var addr = Module.findBaseAddress("binary").add(0x1234);
135
+ Memory.patchCode(addr, 2, function(code) {
136
+ var writer = new X86Writer(code, { pc: addr });
137
+ writer.putNop();
138
+ writer.putNop();
139
+ writer.flush();
140
+ });
141
+ ```
142
+
143
+ ### Function Replacement
144
+
145
+ ```javascript
146
+ // Replace a validation function to always return true
147
+ var checkFlag = Module.findExportByName(null, "check_flag");
148
+ Interceptor.replace(checkFlag, new NativeCallback(function(input) {
149
+ console.log("[*] check_flag called with:", Memory.readUtf8String(input));
150
+ return 1; // always valid
151
+ }, 'int', ['pointer']));
152
+ ```
153
+
154
+ ### Tracing and Stalker
155
+
156
+ ```javascript
157
+ // Trace all calls in a function (Stalker — instruction-level tracing)
158
+ var targetAddr = Module.findExportByName(null, "main");
159
+ Stalker.follow(Process.getCurrentThreadId(), {
160
+ transform: function(iterator) {
161
+ var instruction;
162
+ while ((instruction = iterator.next()) !== null) {
163
+ if (instruction.mnemonic === "call") {
164
+ iterator.putCallout(function(context) {
165
+ console.log("CALL at", context.pc, "→", ptr(context.pc).readPointer());
166
+ });
167
+ }
168
+ iterator.keep();
169
+ }
170
+ }
171
+ });
172
+ ```
173
+
174
+ ### r2frida (Radare2 + Frida Integration)
175
+
176
+ ```bash
177
+ # Attach radare2 to process via Frida
178
+ r2 frida://spawn/./binary
179
+
180
+ # r2frida commands
181
+ \ii # List imports
182
+ \il # List loaded modules
183
+ \dt strcmp # Trace strcmp calls
184
+ \dc # Continue execution
185
+ \dm # List memory maps
186
+ ```
187
+
188
+ ### Frida for Android/iOS
189
+
190
+ ```bash
191
+ # Android (requires rooted device or Frida server)
192
+ adb push frida-server /data/local/tmp/
193
+ adb shell "chmod 755 /data/local/tmp/frida-server && /data/local/tmp/frida-server &"
194
+
195
+ # Hook Android Java methods
196
+ frida -U -f com.example.app -l hook_android.js --no-pause
197
+ ```
198
+
199
+ ```javascript
200
+ // hook_android.js — hook Java method
201
+ Java.perform(function() {
202
+ var MainActivity = Java.use("com.example.app.MainActivity");
203
+ MainActivity.checkPassword.implementation = function(input) {
204
+ console.log("[*] checkPassword called with:", input);
205
+ var result = this.checkPassword(input);
206
+ console.log("[*] Result:", result);
207
+ return result;
208
+ };
209
+ });
210
+ ```
211
+
212
+ **Key insight:** Frida excels where static analysis fails — obfuscated code, packed binaries, and runtime-generated data. Hook comparison functions (`strcmp`, `memcmp`, custom validators) to extract expected values without reversing the algorithm. Use `Interceptor.attach` for observation, `Interceptor.replace` for modification.
213
+
214
+ **When to use:** Anti-debugging bypass, extracting runtime-computed keys, hooking crypto functions to dump plaintext, mobile app analysis, packed binary inspection.
215
+
216
+ ### Frida Memoization for Recursive Function Speedup (hxp CTF 2017)
217
+
218
+ Hook a recursive function with Frida, memoize results, and replay cached values to skip redundant computation. Fibonacci-like recursive challenges with exponential complexity become instant with memoization.
219
+
220
+ ```javascript
221
+ // memo_hook.js — memoize a recursive function to skip redundant calls
222
+ var memo = {};
223
+ var funcAddr = ptr("0x400abc"); // Address of the recursive function
224
+ var retAddr = ptr("0x400def"); // Address of the function's ret instruction
225
+
226
+ Interceptor.attach(funcAddr, {
227
+ onEnter: function(args) {
228
+ this.key = args[0].toInt32();
229
+ if (memo[this.key] !== undefined) {
230
+ // Skip computation entirely: set return value and jump to ret
231
+ this.context.rax = memo[this.key];
232
+ this.context.rip = retAddr;
233
+ }
234
+ },
235
+ onLeave: function(retval) {
236
+ // Cache the result for future calls with the same argument
237
+ memo[this.key] = retval.toInt32();
238
+ }
239
+ });
240
+ ```
241
+
242
+ ```bash
243
+ # Usage
244
+ frida -f ./binary -l memo_hook.js --no-pause
245
+ ```
246
+
247
+ For multi-argument functions, build a composite key:
248
+ ```javascript
249
+ Interceptor.attach(funcAddr, {
250
+ onEnter: function(args) {
251
+ this.key = args[0].toInt32() + "," + args[1].toInt32();
252
+ if (memo[this.key] !== undefined) {
253
+ this.context.rax = memo[this.key];
254
+ this.context.rip = retAddr;
255
+ }
256
+ },
257
+ onLeave: function(retval) {
258
+ memo[this.key] = retval.toInt32();
259
+ }
260
+ });
261
+ ```
262
+
263
+ **Key insight:** Frida's `Interceptor` can both read and modify register state, allowing you to skip function execution entirely by setting `rax` (return value) and `rip` (to the `ret` instruction). This works on any recursive function where the same arguments produce the same result. Exponential-time recursive computations (Fibonacci, Ackermann, tree traversals) become linear with memoization.
264
+
265
+ **References:** hxp CTF 2017
266
+
267
+ ---
268
+
269
+ ## angr (Symbolic Execution)
270
+
271
+ angr automatically explores program paths to find inputs satisfying constraints. Solves many flag-checking binaries in minutes that take hours manually.
272
+
273
+ ### angr Installation
274
+
275
+ ```bash
276
+ pip install angr
277
+ ```
278
+
279
+ ### Basic Path Exploration
280
+
281
+ ```python
282
+ import angr
283
+ import claripy
284
+
285
+ # Load binary
286
+ proj = angr.Project('./binary', auto_load_libs=False)
287
+
288
+ # Find address of "Correct!" print, avoid "Wrong!" print
289
+ # Get these from disassembly (objdump -d or Ghidra)
290
+ FIND_ADDR = 0x401234 # Address of success path
291
+ AVOID_ADDR = 0x401256 # Address of failure path
292
+
293
+ # Create simulation manager and explore
294
+ simgr = proj.factory.simgr()
295
+ simgr.explore(find=FIND_ADDR, avoid=AVOID_ADDR)
296
+
297
+ if simgr.found:
298
+ found = simgr.found[0]
299
+ # Get stdin that reaches the target
300
+ print("Flag:", found.posix.dumps(0)) # fd 0 = stdin
301
+ ```
302
+
303
+ ### Symbolic Input with Constraints
304
+
305
+ ```python
306
+ import angr
307
+ import claripy
308
+
309
+ proj = angr.Project('./binary', auto_load_libs=False)
310
+
311
+ # Create symbolic input (e.g., 32-byte flag)
312
+ flag_len = 32
313
+ flag_chars = [claripy.BVS(f'flag_{i}', 8) for i in range(flag_len)]
314
+ flag = claripy.Concat(*flag_chars + [claripy.BVV(b'\n')])
315
+
316
+ # Constrain to printable ASCII
317
+ state = proj.factory.entry_state(stdin=flag)
318
+ for c in flag_chars:
319
+ state.solver.add(c >= 0x20)
320
+ state.solver.add(c <= 0x7e)
321
+
322
+ # Constrain known prefix: "flag{"
323
+ state.solver.add(flag_chars[0] == ord('f'))
324
+ state.solver.add(flag_chars[1] == ord('l'))
325
+ state.solver.add(flag_chars[2] == ord('a'))
326
+ state.solver.add(flag_chars[3] == ord('g'))
327
+ state.solver.add(flag_chars[4] == ord('{'))
328
+ state.solver.add(flag_chars[flag_len-1] == ord('}'))
329
+
330
+ simgr = proj.factory.simgr(state)
331
+ simgr.explore(find=0x401234, avoid=0x401256)
332
+
333
+ if simgr.found:
334
+ found = simgr.found[0]
335
+ result = found.solver.eval(flag, cast_to=bytes)
336
+ print("Flag:", result.decode())
337
+ ```
338
+
339
+ ### Hook Functions to Simplify Analysis
340
+
341
+ ```python
342
+ import angr
343
+
344
+ proj = angr.Project('./binary', auto_load_libs=False)
345
+
346
+ # Hook printf to avoid path explosion in I/O
347
+ @proj.hook(0x401100, length=5) # Address of call to printf
348
+ def skip_printf(state):
349
+ pass # Do nothing, just skip
350
+
351
+ # Hook sleep/anti-debug functions
352
+ @proj.hook(0x401050, length=5) # Address of call to sleep
353
+ def skip_sleep(state):
354
+ pass
355
+
356
+ # Replace a function with a summary
357
+ class AlwaysSucceed(angr.SimProcedure):
358
+ def run(self):
359
+ return 1
360
+
361
+ proj.hook_symbol('check_license', AlwaysSucceed())
362
+ ```
363
+
364
+ ### Exploring from Specific Address
365
+
366
+ ```python
367
+ # Start from middle of function (skip initialization)
368
+ state = proj.factory.blank_state(addr=0x401200)
369
+
370
+ # Set up registers/memory manually
371
+ state.regs.rdi = 0x600000 # Pointer to input buffer
372
+ state.memory.store(0x600000, b"AAAA" + b"\x00" * 28)
373
+
374
+ simgr = proj.factory.simgr(state)
375
+ simgr.explore(find=0x401300, avoid=0x401350)
376
+ ```
377
+
378
+ ### Common Patterns and Tips
379
+
380
+ ```python
381
+ # Pattern 1: argv-based input
382
+ state = proj.factory.entry_state(args=['./binary', flag_sym])
383
+
384
+ # Pattern 2: Multiple find/avoid addresses
385
+ simgr.explore(
386
+ find=[0x401234, 0x401300], # Any success path
387
+ avoid=[0x401256, 0x401400] # All failure paths
388
+ )
389
+
390
+ # Pattern 3: Find by output string (no address needed)
391
+ def is_successful(state):
392
+ stdout = state.posix.dumps(1) # fd 1 = stdout
393
+ return b"Correct" in stdout
394
+
395
+ def should_avoid(state):
396
+ stdout = state.posix.dumps(1)
397
+ return b"Wrong" in stdout
398
+
399
+ simgr.explore(find=is_successful, avoid=should_avoid)
400
+
401
+ # Pattern 4: Timeout protection
402
+ simgr.explore(find=0x401234, avoid=0x401256, num_find=1)
403
+ # Or use exploration techniques:
404
+ simgr.use_technique(angr.exploration_techniques.DFS()) # Depth-first
405
+ simgr.use_technique(angr.exploration_techniques.LengthLimiter(max_length=500))
406
+ ```
407
+
408
+ ### Dealing with Path Explosion
409
+
410
+ ```python
411
+ # Use DFS instead of BFS (default) for flag checkers
412
+ simgr.use_technique(angr.exploration_techniques.DFS())
413
+
414
+ # Limit symbolic memory operations
415
+ state.options.add(angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY)
416
+ state.options.add(angr.options.ZERO_FILL_UNCONSTRAINED_REGISTERS)
417
+
418
+ # Hook expensive functions (crypto, hashing) to avoid explosion
419
+ import hashlib
420
+ class SHA256Hook(angr.SimProcedure):
421
+ def run(self, data, length, output):
422
+ # Concretize input and compute hash
423
+ concrete_data = self.state.solver.eval(
424
+ self.state.memory.load(data, self.state.solver.eval(length)),
425
+ cast_to=bytes
426
+ )
427
+ h = hashlib.sha256(concrete_data).digest()
428
+ self.state.memory.store(output, h)
429
+
430
+ proj.hook_symbol('SHA256', SHA256Hook())
431
+ ```
432
+
433
+ ### angr CFG Recovery
434
+
435
+ ```python
436
+ # Control flow graph for understanding structure
437
+ cfg = proj.analyses.CFGFast()
438
+ print(f"Functions found: {len(cfg.functions)}")
439
+
440
+ # Find main
441
+ for addr, func in cfg.functions.items():
442
+ if func.name == 'main':
443
+ print(f"main at {addr:#x}")
444
+ break
445
+
446
+ # Cross-references
447
+ node = cfg.model.get_any_node(0x401234)
448
+ print("Predecessors:", [hex(p.addr) for p in cfg.model.get_predecessors(node)])
449
+ ```
450
+
451
+ **Key insight:** angr works best on flag-checker binaries with clear success/failure paths. For complex binaries, hook expensive functions (crypto, I/O) and use DFS exploration. Start with the simplest approach (just find/avoid addresses) before adding constraints. If angr is slow, constrain input to printable ASCII and add known prefix.
452
+
453
+ **When to use:** Flag validators with branching logic, maze/path-finding binaries, constraint-heavy checks, automated binary analysis. Less effective for: heavy crypto, floating-point math, complex heap operations.
454
+
455
+ ---
456
+
457
+ ## lldb (LLVM Debugger)
458
+
459
+ Primary debugger for macOS/iOS. Also works on Linux. Preferred for Swift/Objective-C and Apple platform binaries.
460
+
461
+ ### Basic Commands
462
+
463
+ ```bash
464
+ lldb ./binary
465
+ (lldb) run # Run program
466
+ (lldb) b main # Breakpoint on main
467
+ (lldb) b 0x401234 # Breakpoint at address
468
+ (lldb) breakpoint set -r "check.*" # Regex breakpoint
469
+ (lldb) c # Continue
470
+ (lldb) si # Step instruction
471
+ (lldb) ni # Next instruction
472
+ (lldb) register read # Show all registers
473
+ (lldb) register write rax 0 # Modify register
474
+ (lldb) memory read 0x401000 -c 32 # Read 32 bytes
475
+ (lldb) x/s $rsi # Examine string (GDB-style)
476
+ (lldb) dis -n main # Disassemble function
477
+ (lldb) image list # Loaded modules + base addresses
478
+ ```
479
+
480
+ ### Scripting (Python)
481
+
482
+ ```python
483
+ # lldb Python scripting
484
+ import lldb
485
+
486
+ def hook_strcmp(debugger, command, result, internal_dict):
487
+ target = debugger.GetSelectedTarget()
488
+ process = target.GetProcess()
489
+ thread = process.GetSelectedThread()
490
+ frame = thread.GetSelectedFrame()
491
+ arg0 = frame.FindRegister("rdi").GetValueAsUnsigned()
492
+ arg1 = frame.FindRegister("rsi").GetValueAsUnsigned()
493
+ s0 = process.ReadCStringFromMemory(arg0, 256, lldb.SBError())
494
+ s1 = process.ReadCStringFromMemory(arg1, 256, lldb.SBError())
495
+ print(f'strcmp("{s0}", "{s1}")')
496
+
497
+ # Register in lldb: command script add -f script.hook_strcmp hook_strcmp
498
+ ```
499
+
500
+ **Key insight:** Use lldb for macOS binaries (Mach-O), iOS apps, and when GDB isn't available. `image list` gives ASLR slide for PIE binaries. Scripting API is more structured than GDB's.
501
+
502
+ ---
503
+
504
+ ## x64dbg (Windows Debugger)
505
+
506
+ Open-source Windows debugger with modern UI. Alternative to OllyDbg/WinDbg for Windows RE challenges.
507
+
508
+ ### Key Features
509
+
510
+ ```bash
511
+ # Launch
512
+ x64dbg.exe binary.exe # 64-bit
513
+ x32dbg.exe binary.exe # 32-bit
514
+
515
+ # Essential shortcuts
516
+ F2 → Toggle breakpoint
517
+ F7 → Step into
518
+ F8 → Step over
519
+ F9 → Run
520
+ Ctrl+G → Go to address
521
+ Ctrl+F → Find pattern in memory
522
+ ```
523
+
524
+ ### Scripting
525
+
526
+ ```bash
527
+ # x64dbg command line
528
+ bp 0x401234 # Breakpoint
529
+ SetBPX 0x401234, 0, "log {s:utf8@[esp+4]}" # Log string arg on hit
530
+ run # Continue
531
+ StepOver # Step over
532
+ ```
533
+
534
+ ### Common CTF Workflow
535
+
536
+ 1. Set breakpoint on `GetWindowTextA`/`MessageBoxA` for GUI crackers
537
+ 2. Trace back from success/failure message
538
+ 3. Use **Scylla** plugin for IAT reconstruction on packed binaries
539
+ 4. **Snowman** decompiler plugin for quick pseudo-C
540
+
541
+ **Key insight:** x64dbg has built-in pattern scanning, hardware breakpoints, and conditional logging. For Windows CTF binaries, it's often faster than IDA/Ghidra for dynamic analysis. Use the **xAnalyzer** plugin for automatic function argument annotation.
542
+
543
+ ---
544
+
545
+ ## GDB Register Side-Channel on putchar() (picoCTF 2018)
546
+
547
+ **Pattern:** The binary decrypts a flag one character at a time and calls `putchar()` with a `usleep()` between prints. Rather than wait out the sleeps, set a breakpoint on `putchar@plt` and log `$rdi` (on glibc x86-64 the character lives there) at every hit. A GDB logging loop dumps the full flag in milliseconds regardless of the artificial delay.
548
+
549
+ ```gdb
550
+ # ~/.gdbinit for this challenge
551
+ set pagination off
552
+ set logging file flag.log
553
+ set logging overwrite on
554
+ set logging on
555
+
556
+ break putchar
557
+ commands
558
+ silent
559
+ printf "%c", $rdi
560
+ continue
561
+ end
562
+
563
+ run
564
+ ```
565
+
566
+ ```bash
567
+ gdb -batch -x script.gdb ./crackme
568
+ cat flag.log
569
+ ```
570
+
571
+ **Key insight:** Any time a program artificially slows output with `usleep`, `nanosleep`, or busy-loop delays, the character to be printed is already in a register before the sleep runs. Breakpoint on the output function (`putchar`, `fputc`, `write` with `fd=1`), print the first-argument register (`$rdi` on x86-64, `$r0` on ARM, `$a0` on RISC-V/MIPS), and let GDB scripting batch-extract the data. Works even on anti-debug binaries when hardware breakpoints are available.
572
+
573
+ **References:** picoCTF 2018 — learn gdb, writeup 11784
574
+
575
+ ---
576
+
577
+ ## radare2 Visual Panels for Custom VM Tracing (OTW Advent 2018)
578
+
579
+ **Pattern:** Custom-VM binaries look opaque until you can see the program counter, next opcode, stack, and heap simultaneously. radare2's panel mode (`V!`) lets you pin all four views on one screen and step through host-level instructions while watching the VM state move.
580
+
581
+ ```text
582
+ f sp @ rbp-0x160 # flag VM sp
583
+ f ip @ rbp-0x158 # flag VM ip
584
+ f stack @ rbp-0x150
585
+ f heap @ rbp-0x148
586
+
587
+ V! # enter panels
588
+ # panel 1: ?v [ip]; pd 1 @ [ip] (next VM instruction)
589
+ # panel 2: pxQ 0x60 @ sp (stack)
590
+ # panel 3: pxQ 0x60 @ heap (heap)
591
+ # panel 4: afvd (local vars / registers)
592
+ ```
593
+
594
+ Set conditional breakpoints on host-level branches that correspond to VM opcode dispatch, and step with `ds`. Combine with `e io.cache=true` for non-destructive patching of VM opcodes during analysis.
595
+
596
+ **Key insight:** Custom VMs are reversible in minutes once you watch their state live. Panel mode beats static decompilation because the host binary often lacks decompiler-friendly structure; the VM becomes self-explanatory when you see every register tick in real time.
597
+
598
+ **References:** OverTheWire Advent 2018 — Jackinthebox, writeup 12789
599
+
600
+ ---
601
+
602
+ ## libSegFault.so Register Dump at Crash (OTW Advent 2018)
603
+
604
+ **Pattern:** You need the exact register state at shellcode entry but gdb is unavailable or hooked. Preload `libSegFault.so` (shipped with glibc) and crash the program: it prints a full register dump, backtrace, and memory map to stderr.
605
+
606
+ ```bash
607
+ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libSegFault.so ./target
608
+ # or 32-bit:
609
+ LD_PRELOAD=/lib32/libSegFault.so ./target
610
+
611
+ # Force the crash:
612
+ # segfault_handler dumps: RIP, RSP, RAX..R15, stack backtrace
613
+ ```
614
+
615
+ Read the printed registers to discover which already point at your shellcode (common: `RAX` → buffer, `RDI` → zero) and design minimal shellcode.
616
+
617
+ **Key insight:** libSegFault is installed on every glibc system as part of standard debugging infrastructure. It turns any segfault into a free register snapshot, even on hardened boxes without `strace`/`gdb` permissions.
618
+
619
+ **References:** OverTheWire Advent Bonanza 2018 — Day 22, writeup 12757
620
+
621
+ ---
622
+
623
+ ## r2pipe Binary Walking + DP Constraint Solver (OTW Advent 2018)
624
+
625
+ **Pattern:** 12 MB binary with 300k+ basic blocks performs chained hash checks on `argv[1]`. Walk every block via `r2pipe`, classify each instruction as hash/cmp/jmp/print, build a constraint graph, then solve with dynamic programming + backtracking over input positions.
626
+
627
+ ```python
628
+ import r2pipe
629
+ r = r2pipe.open('./huge_binary')
630
+ r.cmd('aaa')
631
+ for fn in r.cmdj('aflj'):
632
+ for block in r.cmdj(f"pdfj @ {fn['offset']}")['ops']:
633
+ op = block['type']
634
+ if op == 'cmp': constraints.append(parse_cmp(block))
635
+ if op == 'call': targets.append(block['jump'])
636
+ # DP: memoize (position, accepted_set) -> char
637
+ ```
638
+
639
+ **Key insight:** Big binaries with hash chains are solvable if you treat each branch as an inequality on input bytes. r2pipe's JSON output is machine-readable; DP over position/value tuples prunes most branches before running.
640
+
641
+ **References:** OverTheWire Advent Bonanza 2018 — Day 8, writeup 12771
642
+
643
+ ---
644
+
645
+ ## GDB Commands at strcmp to Recover Dynamic XOR Key (TAMUctf 2019)
646
+
647
+ **Pattern (Obfuscaxor):** Binary uses the [obfy](https://github.com/fritzone/obfy) C++ template obfuscator to bury a simple `enc(input)` XOR loop under thousands of opaque predicates. The terminal check is still `strcmp(expected_ciphertext, enc(input))` — so instead of unwinding obfy, break at the `strcmp` call and dump both operands:
648
+
649
+ ```
650
+ disassemble verify_key
651
+ # ... 0x5555555560b9 <+96>: call strcmp@plt
652
+ break *verify_key+96
653
+ commands
654
+ silent
655
+ printf "RDI (expected): "
656
+ x/4xg $rdi
657
+ printf "RSI (computed): "
658
+ x/4xg $rsi
659
+ continue
660
+ end
661
+ run
662
+ ```
663
+
664
+ Feed a known plaintext (`AAAAAAAAA`) and record `computed_A[i]`. Because `enc` is a byte-wise XOR keystream, the key byte is recovered directly from the delta with the target:
665
+
666
+ ```python
667
+ # input_char ^ key = computed_char, and we want: target_char ^ key = target_input
668
+ def to_ans(got_A, expected):
669
+ return chr(got_A ^ ord('A') ^ expected)
670
+
671
+ # Sanity: flip just one byte of input and confirm only one computed byte moves.
672
+ ```
673
+
674
+ Chain the per-byte recovery over the full 16-byte target and reconstruct the correct key (`p3Asujmn9CEeCB3A` for this challenge).
675
+
676
+ **Key insight:** When `strcmp` is the last gate, the obfuscator is irrelevant — its output still has to equal a fixed string at a known call site. GDB's `commands` block turns the breakpoint into an automatic oracle: one run with `AAAA...` leaks the keystream, and a second pass with any target string gives the valid input. Works for any keyed transform that is effectively a permutation of the input under a fixed key.
677
+
678
+ **References:** TAMUctf 2019 — Obfuscaxor, writeup 13574
679
+