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,572 @@
1
+ # CTF Reverse - Patterns & Techniques
2
+
3
+ ## Table of Contents
4
+ - [Custom VM Reversing](#custom-vm-reversing)
5
+ - [Analysis Steps](#analysis-steps)
6
+ - [Common VM Patterns](#common-vm-patterns)
7
+ - [RVA-Based Opcode Dispatching](#rva-based-opcode-dispatching)
8
+ - [State Machine VMs (90K+ states)](#state-machine-vms-90k-states)
9
+ - [Custom VM Reverse Engineering via Fuzzing and Instruction Set Discovery (hxp CTF 2017)](#custom-vm-reverse-engineering-via-fuzzing-and-instruction-set-discovery-hxp-ctf-2017)
10
+ - [Anti-Debugging Techniques](#anti-debugging-techniques)
11
+ - [Common Checks](#common-checks)
12
+ - [Bypass Technique](#bypass-technique)
13
+ - [LD_PRELOAD Hook](#ld_preload-hook)
14
+ - [pwntools Binary Patching (Crypto-Cat)](#pwntools-binary-patching-crypto-cat)
15
+ - [Nanomites](#nanomites)
16
+ - [Linux (Signal-Based)](#linux-signal-based)
17
+ - [Windows (Debug Events)](#windows-debug-events)
18
+ - [Analysis](#analysis)
19
+ - [Self-Modifying Code](#self-modifying-code)
20
+ - [Pattern: XOR Decryption](#pattern-xor-decryption)
21
+ - [Known-Plaintext XOR (Flag Prefix)](#known-plaintext-xor-flag-prefix)
22
+ - [Variant: XOR with Position Index](#variant-xor-with-position-index)
23
+ - [Mixed-Mode (x86-64 / x86) Stagers](#mixed-mode-x86-64--x86-stagers)
24
+ - [LLVM (Low Level Virtual Machine) Obfuscation (Control Flow Flattening)](#llvm-low-level-virtual-machine-obfuscation-control-flow-flattening)
25
+ - [Pattern](#pattern)
26
+ - [De-obfuscation](#de-obfuscation)
27
+ - [S-Box / Keystream Generation](#s-box--keystream-generation)
28
+ - [Fisher-Yates Shuffle (Xorshift32)](#fisher-yates-shuffle-xorshift32)
29
+ - [Xorshift64* Keystream](#xorshift64-keystream)
30
+ - [Identifying Patterns](#identifying-patterns)
31
+ - [SECCOMP/BPF Filter Analysis](#seccompbpf-filter-analysis)
32
+ - [BPF Analysis](#bpf-analysis)
33
+ - [Exception Handler Obfuscation](#exception-handler-obfuscation)
34
+ - [RtlInstallFunctionTableCallback](#rtlinstallfunctiontablecallback)
35
+ - [Vectored Exception Handlers (VEH)](#vectored-exception-handlers-veh)
36
+ - [Memory Dump Analysis](#memory-dump-analysis)
37
+ - [When Binary Dumps Memory](#when-binary-dumps-memory)
38
+ - [Known Plaintext Attack](#known-plaintext-attack)
39
+ - [Byte-Wise Uniform Transforms](#byte-wise-uniform-transforms)
40
+ - [x86-64 Gotchas](#x86-64-gotchas)
41
+ - [Sign Extension](#sign-extension)
42
+ - [Loop Boundary State Updates](#loop-boundary-state-updates)
43
+ - [Custom Mangle Function Reversing](#custom-mangle-function-reversing)
44
+ - [Position-Based Transformation Reversing](#position-based-transformation-reversing)
45
+ - [Hex-Encoded String Comparison](#hex-encoded-string-comparison)
46
+ - [Signal-Based Binary Exploration](#signal-based-binary-exploration)
47
+
48
+ For malware patching, multi-stage shellcode loaders, timing/signal oracles, and CTF-specific runtime attacks (INT3 coredump oracle, signal handler chain, printf format string VM, quadtree image format), see [patterns-runtime.md](patterns-runtime.md).
49
+
50
+ ---
51
+
52
+ ## Custom VM Reversing
53
+
54
+ ### Analysis Steps
55
+ 1. Identify VM structure: registers, memory, instruction pointer
56
+ 2. Reverse `executeIns`/`runvm` function for opcode meanings
57
+ 3. Write a disassembler to parse bytecode
58
+ 4. Decompile disassembly to understand algorithm
59
+
60
+ ### Common VM Patterns
61
+ ```c
62
+ switch (opcode) {
63
+ case 1: *R[op1] *= op2; break; // MUL
64
+ case 2: *R[op1] -= op2; break; // SUB
65
+ case 3: *R[op1] = ~*R[op1]; break; // NOT
66
+ case 4: *R[op1] ^= mem[op2]; break; // XOR
67
+ case 5: *R[op1] = *R[op2]; break; // MOV
68
+ case 7: if (R0) IP += op1; break; // JNZ
69
+ case 8: putc(R0); break; // PRINT
70
+ case 10: R0 = getc(); break; // INPUT
71
+ }
72
+ ```
73
+
74
+ ### RVA-Based Opcode Dispatching
75
+ - Opcodes are RVAs pointing to handler functions
76
+ - Handler performs operation, reads next RVA, jumps
77
+ - Map all handlers by following RVA chain
78
+
79
+ ### State Machine VMs (90K+ states)
80
+ ```java
81
+ // BFS for valid path
82
+ var agenda = new ArrayDeque<State>();
83
+ agenda.add(new State(0, ""));
84
+ while (!agenda.isEmpty()) {
85
+ var current = agenda.remove();
86
+ if (current.path.length() == TARGET_LENGTH) {
87
+ println(current.path);
88
+ continue;
89
+ }
90
+ for (var transition : machine.get(current.state).entrySet()) {
91
+ agenda.add(new State(transition.getValue(),
92
+ current.path + (char)transition.getKey()));
93
+ }
94
+ }
95
+ ```
96
+
97
+ **Key insight:** Custom VMs appear when the challenge bundles a bytecode blob alongside a dispatcher loop. Reverse the opcode switch table first, then write a disassembler to lift the bytecode before attempting to understand the algorithm.
98
+
99
+ ### Custom VM Reverse Engineering via Fuzzing and Instruction Set Discovery (hxp CTF 2017)
100
+
101
+ Methodical black-box approach to reversing unknown VM bytecode when static analysis of the dispatch loop is too complex:
102
+
103
+ **Step 1: Determine instruction alignment.**
104
+ Dump the bytecode as bit strings at various widths (6-11 bits) to identify instruction alignment. Look for repeating patterns that suggest opcode boundaries.
105
+
106
+ **Step 2: Fuzz with random bytes.**
107
+ Send single instructions and observe effects on registers/memory to map opcodes. Reduce to minimal programs: find the shortest input that produces each observable effect.
108
+
109
+ **Step 3: Build the instruction set.**
110
+ Example discovered ISA (variable-length 6-11 bit):
111
+ ```text
112
+ 000 xxxxxxxx jmpz 001 xxxxxxxx jmp 010 xxxxxxxx call
113
+ 011 xxxxxxxx label 1000 xxxxxxx loadram 1001 xxxxxxx saveram
114
+ 110 xxxxxxxx loadi 11100 xxxxxx shl 11101 xxxxxx shr
115
+ 111100 not 111101 and 111110 or 111111 setif
116
+ ```
117
+
118
+ **Step 4: Build assembler/disassembler.**
119
+ Write tools to assemble and disassemble the discovered ISA, then disassemble the challenge bytecode to understand its algorithm.
120
+
121
+ **Step 5: Implement missing primitives.**
122
+ If the ISA lacks expected operations, synthesize them from available instructions. Example: implementing XTEA decryption using only AND/OR/NOT (no native XOR or ADD):
123
+ ```python
124
+ # XOR from AND/OR/NOT: XOR(a, b) = (a OR b) AND NOT(a AND b)
125
+ # ADD via full-adder chains using AND/OR/NOT for carry propagation
126
+ def xor_from_primitives(a, b):
127
+ return (a | b) & ~(a & b)
128
+
129
+ def add_from_primitives(a, b, bits=32):
130
+ carry = 0
131
+ result = 0
132
+ for i in range(bits):
133
+ ai = (a >> i) & 1
134
+ bi = (b >> i) & 1
135
+ sum_bit = xor_from_primitives(xor_from_primitives(ai, bi), carry)
136
+ carry = (ai & bi) | (carry & xor_from_primitives(ai, bi))
137
+ result |= (sum_bit << i)
138
+ return result
139
+ ```
140
+
141
+ **Key insight:** When static analysis of a VM's dispatch loop is too complex, black-box fuzzing can map the ISA faster. Send single instructions and observe state changes. Variable-length instruction sets require testing multiple bit widths. Once the ISA is known, complex algorithms (XTEA) can be implemented even with minimal primitives (AND/OR/NOT).
142
+
143
+ **References:** hxp CTF 2017
144
+
145
+ ---
146
+
147
+ ## Anti-Debugging Techniques
148
+
149
+ ### Common Checks
150
+ - `IsDebuggerPresent()` (Windows)
151
+ - `ptrace(PTRACE_TRACEME)` (Linux)
152
+ - `/proc/self/status` TracerPid
153
+ - Timing checks (`rdtsc`, `time()`)
154
+ - Registry checks (Windows)
155
+
156
+ ### Bypass Technique
157
+ 1. Identify `test` instructions after debug checks
158
+ 2. Set breakpoint at the `test`
159
+ 3. Modify register to bypass conditional
160
+
161
+ ```bash
162
+ # In radare2
163
+ db 0x401234 # Break at test
164
+ dc # Run
165
+ dr eax=0 # Clear flag
166
+ dc # Continue
167
+ ```
168
+
169
+ ### LD_PRELOAD Hook
170
+ ```c
171
+ #define _GNU_SOURCE
172
+ #include <dlfcn.h>
173
+ #include <sys/ptrace.h>
174
+
175
+ long int ptrace(enum __ptrace_request req, ...) {
176
+ long int (*orig)(enum __ptrace_request, pid_t, void*, void*);
177
+ orig = dlsym(RTLD_NEXT, "ptrace");
178
+ // Log or modify behavior
179
+ return orig(req, pid, addr, data);
180
+ }
181
+ ```
182
+
183
+ Compile: `gcc -shared -fPIC -ldl hook.c -o hook.so`
184
+ Run: `LD_PRELOAD=./hook.so ./binary`
185
+
186
+ **Key insight:** Anti-debugging checks are the first obstacle in most reversing challenges. Look for `ptrace`, `IsDebuggerPresent`, or timing checks early in `main()` and patch or hook them before attempting deeper analysis.
187
+
188
+ ### pwntools Binary Patching (Crypto-Cat)
189
+ Patch out anti-debug calls directly using pwntools — replaces function with `ret` instruction:
190
+ ```python
191
+ from pwn import *
192
+
193
+ elf = ELF('./challenge', checksec=False)
194
+ elf.asm(elf.symbols.ptrace, 'ret') # Replace ptrace() with immediate return
195
+ elf.save('patched') # Save patched binary
196
+ ```
197
+
198
+ Other common patches:
199
+ ```python
200
+ elf.asm(addr, 'nop') # NOP out an instruction
201
+ elf.asm(addr, 'xor eax, eax; ret') # Return 0 (bypass checks)
202
+ elf.asm(addr, 'mov eax, 1; ret') # Return 1 (force success)
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Nanomites
208
+
209
+ ### Linux (Signal-Based)
210
+ - `SIGTRAP` (`int 3`) → Custom operation
211
+ - `SIGILL` (`ud2`) → Custom operation
212
+ - `SIGFPE` (`idiv 0`) → Custom operation
213
+ - `SIGSEGV` (null deref) → Custom operation
214
+
215
+ ### Windows (Debug Events)
216
+ - `EXCEPTION_DEBUG_EVENT` → Main handler
217
+ - Parent modifies child via `PTRACE_POKETEXT`
218
+ - Magic markers: `0x1337BABE`, `0xDEADC0DE`
219
+
220
+ ### Analysis
221
+ 1. Check for `fork()` + `ptrace(PTRACE_TRACEME)`
222
+ 2. Find `WaitForDebugEvent` loop
223
+ 3. Map EAX values to operations
224
+ 4. Log operations to reconstruct algorithm
225
+
226
+ **Key insight:** Nanomites hide the real computation inside signal/exception handlers that only fire under a debugger parent. If the binary forks and the child calls `ptrace(TRACEME)`, the parent is the real CPU -- log its POKE operations to reconstruct the algorithm.
227
+
228
+ ---
229
+
230
+ ## Self-Modifying Code
231
+
232
+ ### Pattern: XOR Decryption
233
+ ```asm
234
+ lea rax, next_block
235
+ mov dl, [rcx] ; Input char
236
+ xor_loop:
237
+ xor [rax+rbx], dl
238
+ inc rbx
239
+ cmp rbx, BLOCK_SIZE
240
+ jnz xor_loop
241
+ jmp rax ; Execute decrypted
242
+ ```
243
+
244
+ **Solution:** Known opcode at block start reveals XOR key (flag char).
245
+
246
+ **Key insight:** Self-modifying code decrypts the next block using each input character as a key. A known-good opcode at the start of each decrypted block (e.g., function prologue) reveals the correct key byte, recovering the flag one character at a time.
247
+
248
+ ---
249
+
250
+ ## Known-Plaintext XOR (Flag Prefix)
251
+
252
+ **Pattern:** Encrypted bytes given; flag format known (e.g., `0xL4ugh{`).
253
+
254
+ **Approach:**
255
+ 1. Assume repeating XOR key.
256
+ 2. Use known prefix (and any hint phrase) to recover key bytes.
257
+ 3. Try small key lengths and validate printable output.
258
+
259
+ ```python
260
+ enc = bytes.fromhex("...") # ciphertext
261
+ known = b"0xL4ugh{say_yes_to_me"
262
+ for klen in range(2, 33):
263
+ key = bytearray(klen)
264
+ ok = True
265
+ for i, b in enumerate(known):
266
+ if i >= len(enc):
267
+ break
268
+ ki = i % klen
269
+ v = enc[i] ^ b
270
+ if key[ki] != 0 and key[ki] != v:
271
+ ok = False
272
+ break
273
+ key[ki] = v
274
+ if not ok:
275
+ continue
276
+ pt = bytes(enc[i] ^ key[i % klen] for i in range(len(enc)))
277
+ if all(32 <= c < 127 for c in pt):
278
+ print(klen, key, pt)
279
+ ```
280
+
281
+ **Note:** Challenge hints often appear verbatim in the flag body (e.g., "say_yes_to_me").
282
+
283
+ ### Variant: XOR with Position Index
284
+ **Pattern:** `cipher[i] = plain[i] ^ key[i % k] ^ i` (or `^ (i & 0xff)`).
285
+
286
+ **Symptoms:**
287
+ - Repeating-key XOR almost fits known prefix but breaks at later positions
288
+ - XOR with known prefix yields a "key" that changes by +1 per index
289
+
290
+ **Fix:** Remove index first, then recover key with known prefix.
291
+ ```python
292
+ enc = bytes.fromhex("...")
293
+ known = b"0xL4ugh{say_yes_to_me"
294
+ for klen in range(2, 33):
295
+ key = bytearray(klen)
296
+ ok = True
297
+ for i, b in enumerate(known):
298
+ if i >= len(enc):
299
+ break
300
+ ki = i % klen
301
+ v = (enc[i] ^ i) ^ b # strip index XOR
302
+ if key[ki] != 0 and key[ki] != v:
303
+ ok = False
304
+ break
305
+ key[ki] = v
306
+ if not ok:
307
+ continue
308
+ pt = bytes((enc[i] ^ i) ^ key[i % klen] for i in range(len(enc)))
309
+ if all(32 <= c < 127 for c in pt):
310
+ print(klen, key, pt)
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Mixed-Mode (x86-64 / x86) Stagers
316
+
317
+ **Pattern:** 64-bit ELF jumps into a 32-bit blob via far return (`retf`/`retfq`), often after anti-debug.
318
+
319
+ **Identification:**
320
+ - Bytes `0xCB` (retf) or `0xCA` (retf imm16), sometimes preceded by `0x48` (retfq)
321
+ - 32-bit disasm shows SSE ops (`psubb`, `pxor`, `paddb`) in a tight loop
322
+ - Computed jumps into the 32-bit region
323
+
324
+ **Gotchas:**
325
+ - `retf` pops **6 bytes**: 4-byte EIP + 2-byte CS (not 8)
326
+ - 32-bit blob may rely on inherited **XMM state** and **EFLAGS**
327
+ - Missing XMM/flags transfer when switching emulators yields wrong output
328
+
329
+ **Bypass/Emulation Tips:**
330
+ 1. Create a UC_MODE_32 emulator, copy memory + GPRs, **EFLAGS**, and **XMM regs**
331
+ 2. Run 32-bit block, then copy memory + regs back to 64-bit
332
+ 3. If anti-debug uses `fork/ptrace` + patching, emulate parent to log POKEs and apply them in child
333
+
334
+ ---
335
+
336
+ ## LLVM (Low Level Virtual Machine) Obfuscation (Control Flow Flattening)
337
+
338
+ ### Pattern
339
+ ```c
340
+ while (1) {
341
+ if (i == 0xA57D3848) { /* block */ }
342
+ if (i != 0xA5AA2438) break;
343
+ i = 0x39ABA8E6; // Next state
344
+ }
345
+ ```
346
+
347
+ ### De-obfuscation
348
+ 1. GDB script to break at `je` instructions
349
+ 2. Log state variable values
350
+ 3. Map state transitions
351
+ 4. Reconstruct true control flow
352
+
353
+ **Key insight:** Control flow flattening replaces structured if/else/loops with a single dispatcher switch. The state variable is the key -- trace its values at runtime to reconstruct the original control flow graph without fighting the obfuscation statically.
354
+
355
+ ---
356
+
357
+ ## S-Box / Keystream Generation
358
+
359
+ ### Fisher-Yates Shuffle (Xorshift32)
360
+ ```python
361
+ def gen_sbox():
362
+ sbox = list(range(256))
363
+ state = SEED
364
+ for i in range(255, -1, -1):
365
+ state = ((state << 13) ^ state) & 0xffffffff
366
+ state = ((state >> 17) ^ state) & 0xffffffff
367
+ state = ((state << 5) ^ state) & 0xffffffff
368
+ j = state % (i + 1) if i > 0 else 0
369
+ sbox[i], sbox[j] = sbox[j], sbox[i]
370
+ return sbox
371
+ ```
372
+
373
+ ### Xorshift64* Keystream
374
+ ```python
375
+ def gen_keystream():
376
+ ks = []
377
+ state = SEED_64
378
+ mul = 0x2545f4914f6cdd1d
379
+ for _ in range(256):
380
+ state ^= (state >> 12)
381
+ state ^= (state << 25)
382
+ state ^= (state >> 27)
383
+ state = (state * mul) & 0xffffffffffffffff
384
+ ks.append((state >> 56) & 0xff)
385
+ return ks
386
+ ```
387
+
388
+ ### Identifying Patterns
389
+ - Xorshift32: shifts 13, 17, 5 (no multiplication constant)
390
+ - Xorshift64*: shifts 12, 25, 27, then multiply by `0x2545f4914f6cdd1d`
391
+ - Other common constant: `0x9e3779b97f4a7c15` (golden ratio)
392
+
393
+ **Key insight:** Recognize S-box generation by the Fisher-Yates shuffle pattern (loop counting down from 255, swap with PRNG-chosen index) and keystream generators by the xorshift constants. Once the PRNG family is identified, the algorithm is fully determined by its seed.
394
+
395
+ ---
396
+
397
+ ## SECCOMP/BPF Filter Analysis
398
+
399
+ ```bash
400
+ seccomp-tools dump ./binary
401
+ ```
402
+
403
+ ### BPF Analysis
404
+ - `A = sys_number` followed by comparisons
405
+ - `mem[N] = A`, `A = mem[N]` for memory ops
406
+ - Map to constraint equations, solve with z3
407
+
408
+ ```python
409
+ from z3 import *
410
+ flag = [BitVec(f'c{i}', 32) for i in range(14)]
411
+ s = Solver()
412
+ s.add(flag[0] >= 0x20, flag[0] < 0x7f)
413
+ # Add constraints from filter
414
+ if s.check() == sat:
415
+ m = s.model()
416
+ print(''.join(chr(m[c].as_long()) for c in flag))
417
+ ```
418
+
419
+ **Key insight:** SECCOMP (Secure Computing Mode) filters encode flag validation as BPF bytecode operating on syscall arguments. Dump the filter with `seccomp-tools`, translate the comparisons and memory operations into z3 constraints, and solve for the flag without ever running the binary.
420
+
421
+ ---
422
+
423
+ ## Exception Handler Obfuscation
424
+
425
+ ### RtlInstallFunctionTableCallback
426
+ - Dynamic exception handler registration
427
+ - Handler installs new handler, modifies code
428
+ - Use x64dbg with exception handler breaks
429
+
430
+ ### Vectored Exception Handlers (VEH)
431
+ - `AddVectoredExceptionHandler` installs handler
432
+ - Handler decrypts code at exception address
433
+ - Step through, dump decrypted code
434
+
435
+ **Key insight:** Exception-handler-based obfuscation hides the real control flow inside SEH/VEH handlers that trigger on deliberate faults. Set breakpoints inside the exception handlers rather than on the faulting instructions to follow the actual execution path.
436
+
437
+ ---
438
+
439
+ ## Memory Dump Analysis
440
+
441
+ ### When Binary Dumps Memory
442
+ - Check for `/proc/self/maps` reads
443
+ - Check for `/proc/self/mem` reads
444
+ - Heap data often appended to dump
445
+
446
+ ### Known Plaintext Attack
447
+ ```python
448
+ prologue = bytes([0xf3, 0x0f, 0x1e, 0xfa, 0x55, 0x48, 0x89, 0xe5])
449
+ encrypted = data[func_offset:func_offset+8]
450
+ partial_key = bytes(a ^ b for a, b in zip(encrypted, prologue))
451
+ ```
452
+
453
+ **Key insight:** When a binary reads `/proc/self/mem` or `/proc/self/maps`, it is dumping its own memory -- possibly after encrypting it. Use known function prologues (`endbr64; push rbp; mov rbp, rsp`) as known plaintext to recover the XOR key from the encrypted dump.
454
+
455
+ ---
456
+
457
+ ## Byte-Wise Uniform Transforms
458
+
459
+ **Pattern:** Output buffer depends on each input byte independently (no cross-byte coupling).
460
+
461
+ **Detection:**
462
+ - Change one input position → only one output position changes
463
+ - Fill input with a single byte → output buffer becomes constant
464
+
465
+ **Solve:**
466
+ 1. For each byte value 0..255, run the program with that byte repeated
467
+ 2. Record output byte → build mapping and inverse mapping
468
+ 3. Apply inverse mapping to static target bytes to recover the flag
469
+
470
+ ---
471
+
472
+ ## x86-64 Gotchas
473
+
474
+ ### Sign Extension
475
+ ```python
476
+ esi = 0xffffffc7 # NOT -57
477
+
478
+ # For XOR: low byte only
479
+ esi_xor = esi & 0xff # 0xc7
480
+
481
+ # For addition: full 32-bit with overflow
482
+ r12 = (r13 + esi) & 0xffffffff
483
+ ```
484
+
485
+ ### Loop Boundary State Updates
486
+ Assembly often splits state updates across loop boundaries:
487
+ ```asm
488
+ jmp loop_middle ; First iteration in middle!
489
+
490
+ loop_top: ; State for iterations 2+
491
+ mov r13, sbox[a & 0xf]
492
+ ; Uses OLD 'a', not new!
493
+
494
+ loop_middle:
495
+ ; Main computation
496
+ inc a
497
+ jne loop_top
498
+ ```
499
+
500
+ **Key insight:** Decompilers often get x86-64 sign extension and loop boundary state updates wrong. Always verify decompiled output against the raw assembly for operations involving `movsx`/`cdqe`, and check whether loop variables update before or after their use in each iteration.
501
+
502
+ ---
503
+
504
+ ## Custom Mangle Function Reversing
505
+
506
+ **Pattern (Flag Appraisal):** Binary mangles input 2 bytes at a time with intermediate state, compares to static target.
507
+
508
+ **Approach:**
509
+ 1. Extract static target bytes from `.rodata` section
510
+ 2. Understand mangle: processes pairs with running state value
511
+ 3. Write inverse function (process in reverse, undo each operation)
512
+ 4. Feed target bytes through inverse → recovers flag
513
+
514
+ **Key insight:** When a binary mangles input in pairs with running state and compares to a static target, extract the target from `.rodata` and write the inverse function. Process the target bytes in reverse order, undoing each operation, to recover the original input.
515
+
516
+ ---
517
+
518
+ ## Position-Based Transformation Reversing
519
+
520
+ **Pattern (PascalCTF 2026):** Binary transforms input by adding/subtracting position index.
521
+
522
+ **Reversing:**
523
+ ```python
524
+ expected = [...] # Extract from .rodata
525
+ flag = ''
526
+ for i, b in enumerate(expected):
527
+ if i % 2 == 0:
528
+ flag += chr(b - i) # Even: input = output - i
529
+ else:
530
+ flag += chr(b + i) # Odd: input = output + i
531
+ ```
532
+
533
+ ---
534
+
535
+ ## Hex-Encoded String Comparison
536
+
537
+ **Pattern (Spider's Curse):** Input converted to hex, compared against hex constant.
538
+
539
+ **Quick solve:** Extract hex constant from strings/Ghidra, decode:
540
+ ```bash
541
+ echo "4d65746143..." | xxd -r -p
542
+ ```
543
+
544
+ ---
545
+
546
+ ## Signal-Based Binary Exploration
547
+
548
+ **Pattern (Signal Signal Little Star):** Binary uses UNIX signals as a binary tree navigation mechanism.
549
+
550
+ **Identification:**
551
+ - Multiple `sigaction()` calls with `SA_SIGINFO`
552
+ - `sigaltstack()` setup (alternate signal stack)
553
+ - Handler decodes embedded payload, installs next pair of signals
554
+ - Two types: Node (installs children) vs Leaf (prints message + exits)
555
+
556
+ **Solving approach:**
557
+ 1. Hook `sigaction` via `LD_PRELOAD` to log signal installations
558
+ 2. DFS through the binary tree by sending signals
559
+ 3. At each stage, observe which 2 signals are installed
560
+ 4. Send one, check if program exits (leaf) or installs 2 more (node)
561
+ 5. If wrong leaf, backtrack and try sibling
562
+
563
+ ```c
564
+ // LD_PRELOAD interposer to log sigaction calls
565
+ int sigaction(int signum, const struct sigaction *act, ...) {
566
+ if (act && (act->sa_flags & SA_SIGINFO))
567
+ log("SET %d SA_SIGINFO=1\n", signum);
568
+ return real_sigaction(signum, act, oldact);
569
+ }
570
+ ```
571
+
572
+ See [patterns-runtime.md](patterns-runtime.md) for malware patching, multi-stage shellcode, timing/signal oracles, and CTF writeup techniques.