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,666 @@
1
+ # CTF Reverse - Compiled Language Reversing (Go, Rust)
2
+
3
+ ## Table of Contents
4
+ - [Go Binary Reversing](#go-binary-reversing)
5
+ - [Recognition](#recognition)
6
+ - [Symbol Recovery](#symbol-recovery)
7
+ - [Go Memory Layout](#go-memory-layout)
8
+ - [Goroutine and Concurrency Analysis](#goroutine-and-concurrency-analysis)
9
+ - [Common Go Patterns in Decompilation](#common-go-patterns-in-decompilation)
10
+ - [Go Binary Reversing Workflow](#go-binary-reversing-workflow)
11
+ - [Go Binary UUID Patching for C2 Client Enumeration (BSidesSF 2026)](#go-binary-uuid-patching-for-c2-client-enumeration-bsidessf-2026)
12
+ - [Rust Binary Reversing](#rust-binary-reversing)
13
+ - [Rust Recognition](#rust-recognition)
14
+ - [Symbol Demangling](#symbol-demangling)
15
+ - [Common Rust Patterns in Decompilation](#common-rust-patterns-in-decompilation)
16
+ - [Rust-Specific Analysis Tools](#rust-specific-analysis-tools)
17
+ - [Rust Lifetime Escape via Compiler Bug #25860 (Hack.lu 2018)](#rust-lifetime-escape-via-compiler-bug-25860-hacklu-2018)
18
+ - [Rust #[no_mangle] libc Override for seccomp Bypass (Hack.lu 2018)](#rust-no_mangle-libc-override-for-seccomp-bypass-hacklu-2018)
19
+ - [Rust xmmword Constant Extraction via IDAPython (Insomnihack 2019)](#rust-xmmword-constant-extraction-via-idapython-insomnihack-2019)
20
+ - [Nuitka-Compiled Python — Module Stub Injection (X-MAS CTF 2018)](#nuitka-compiled-python--module-stub-injection-x-mas-ctf-2018)
21
+ - [Swift Binary Reversing](#swift-binary-reversing)
22
+ - [Kotlin / JVM Binary Reversing](#kotlin--jvm-binary-reversing)
23
+ - [JVM Bytecode (Android/Server)](#jvm-bytecode-androidserver)
24
+ - [Kotlin/Native](#kotlinnative)
25
+ - [D Language Binary Reversing (CSAW CTF 2016)](#d-language-binary-reversing-csaw-ctf-2016)
26
+ - [Haskell Binary Reversing via STG Closures and hsdecomp (hxp CTF 2017, Codegate 2018)](#haskell-binary-reversing-via-stg-closures-and-hsdecomp-hxp-ctf-2017-codegate-2018)
27
+ - [Haskell Binary RE via GHC CMM Intermediate Language (N1CTF 2018)](#haskell-binary-re-via-ghc-cmm-intermediate-language-n1ctf-2018)
28
+ - [C++ Binary Reversing (Quick Reference)](#c-binary-reversing-quick-reference)
29
+ - [vtable Reconstruction](#vtable-reconstruction)
30
+ - [RTTI (Run-Time Type Information)](#rtti-run-time-type-information)
31
+ - [Standard Library Patterns](#standard-library-patterns)
32
+
33
+ ---
34
+
35
+ ## Go Binary Reversing
36
+
37
+ Go binaries are increasingly common in CTF challenges due to Go's popularity for CLI tools, network services, and malware.
38
+
39
+ ### Recognition
40
+
41
+ ```bash
42
+ # Detect Go binary
43
+ file binary | grep -i "go"
44
+ strings binary | grep "go.buildid"
45
+ strings binary | grep "runtime.gopanic"
46
+
47
+ # Go version embedded in binary
48
+ strings binary | grep "^go1\."
49
+ ```
50
+
51
+ **Key indicators:**
52
+ - Very large static binary (even "hello world" is ~2MB)
53
+ - Embedded `go.buildid` string
54
+ - `runtime.*` symbols (even in stripped binaries, some remain)
55
+ - `main.main` as entry point (not `main`)
56
+ - Strings like `GOROOT`, `GOPATH`, `/usr/local/go/src/`
57
+
58
+ ### Symbol Recovery
59
+
60
+ Go embeds rich type and function information even in stripped binaries:
61
+
62
+ ```bash
63
+ # GoReSym - recovers function names, types, interfaces from Go binaries
64
+ # https://github.com/mandiant/GoReSym
65
+ ./GoReSym -d binary > symbols.json
66
+
67
+ # Parse output
68
+ python3 -c "
69
+ import json
70
+ with open('symbols.json') as f:
71
+ data = json.load(f)
72
+ for fn in data.get('UserFunctions', []):
73
+ print(f\"{fn['Start']:#x} {fn['FullName']}\")
74
+ "
75
+ ```
76
+
77
+ **Ghidra with golang-loader:**
78
+ ```bash
79
+ # Install: Ghidra → Window → Script Manager → search "golang"
80
+ # Or use: https://github.com/getCUJO/ThreatIntel/tree/master/Scripts/Ghidra
81
+ # Recovers function names, string references, interface tables
82
+ ```
83
+
84
+ **redress (Go binary analysis):**
85
+ ```bash
86
+ # https://github.com/goretk/redress
87
+ redress -src binary # Reconstruct source tree
88
+ redress -pkg binary # List packages
89
+ redress -type binary # List types and methods
90
+ redress -interface binary # List interfaces
91
+ ```
92
+
93
+ ### Go Memory Layout
94
+
95
+ Understanding Go's data structures in decompilation:
96
+
97
+ ```c
98
+ # String: {pointer, length} (16 bytes on 64-bit)
99
+ # NOT null-terminated! Length field is critical.
100
+ struct GoString {
101
+ char *ptr; // pointer to UTF-8 data
102
+ int64 len; // byte length
103
+ };
104
+
105
+ # Slice: {pointer, length, capacity} (24 bytes on 64-bit)
106
+ struct GoSlice {
107
+ void *ptr; // pointer to backing array
108
+ int64 len; // current length
109
+ int64 cap; // allocated capacity
110
+ };
111
+
112
+ # Interface: {type_descriptor, data_pointer} (16 bytes)
113
+ struct GoInterface {
114
+ void *type; // points to type metadata (itab for non-empty interface)
115
+ void *data; // points to actual value
116
+ };
117
+
118
+ # Map: pointer to runtime.hmap struct
119
+ # Channel: pointer to runtime.hchan struct
120
+ ```
121
+
122
+ **In Ghidra/IDA:** When you see a function taking `(ptr, int64)` — it's likely a Go string. Three-field `(ptr, int64, int64)` is a slice.
123
+
124
+ ### Goroutine and Concurrency Analysis
125
+
126
+ ```bash
127
+ # Identify goroutine spawns in disassembly
128
+ strings binary | grep "runtime.newproc"
129
+ # newproc1 is the internal goroutine creation function
130
+
131
+ # In GDB with Go support:
132
+ gdb ./binary
133
+ (gdb) source /usr/local/go/src/runtime/runtime-gdb.py
134
+ (gdb) info goroutines # List all goroutines
135
+ (gdb) goroutine 1 bt # Backtrace for goroutine 1
136
+ ```
137
+
138
+ **Channel operations in disassembly:**
139
+ - `runtime.chansend1` → `ch <- value`
140
+ - `runtime.chanrecv1` → `value = <-ch`
141
+ - `runtime.selectgo` → `select { case ... }`
142
+ - `runtime.closechan` → `close(ch)`
143
+
144
+ ### Common Go Patterns in Decompilation
145
+
146
+ **Defer mechanism:**
147
+ - `runtime.deferproc` → registers deferred function
148
+ - `runtime.deferreturn` → executes deferred functions at function exit
149
+ - Deferred calls execute in LIFO order — relevant for cleanup/crypto key wiping
150
+
151
+ **Error handling (the `if err != nil` pattern):**
152
+ ```text
153
+ # In disassembly, this appears as:
154
+ # call some_function → returns (result, error) as two values
155
+ # test rax, rax → check if error (second return value) is nil
156
+ # jne error_handler
157
+ ```
158
+
159
+ **String concatenation:**
160
+ - `runtime.concatstrings` → `s1 + s2 + s3`
161
+ - `fmt.Sprintf` → formatted string building
162
+ - Look for format strings in `.rodata`: `"%s%d"`, `"%x"`
163
+
164
+ **Common stdlib patterns in CTF:**
165
+ ```go
166
+ // Crypto operations → look for these in strings/imports:
167
+ // "crypto/aes", "crypto/cipher", "crypto/sha256", "encoding/hex", "encoding/base64"
168
+
169
+ // Network operations:
170
+ // "net/http", "net.Dial", "bufio.NewReader"
171
+
172
+ // File operations:
173
+ // "os.Open", "io.ReadAll", "os.ReadFile"
174
+ ```
175
+
176
+ ### Go Binary Reversing Workflow
177
+
178
+ ```bash
179
+ 1. file binary # Confirm Go, get arch
180
+ 2. GoReSym -d binary > syms.json # Recover symbols
181
+ 3. strings binary | grep -i flag # Quick win check
182
+ 4. Load in Ghidra with golang-loader # Apply recovered symbols
183
+ 5. Find main.main # Entry point
184
+ 6. Identify string comparisons # GoString {ptr, len} pairs
185
+ 7. Trace crypto operations # crypto/* package usage
186
+ 8. Check for embedded resources # embed.FS in Go 1.16+
187
+ ```
188
+
189
+ **Go embed.FS (Go 1.16+):** Binaries can embed files at compile time:
190
+ ```bash
191
+ # Look for embedded file data
192
+ strings binary | grep "embed"
193
+ # Embedded files appear as raw data in the binary
194
+ # Search for known file signatures (PK for zip, PNG header, etc.)
195
+ ```
196
+
197
+ **Key insight:** Go's runtime embeds extensive metadata even in stripped binaries. Use GoReSym before any manual analysis — it often recovers 90%+ of function names, making decompilation dramatically easier. Go strings are `{ptr, len}` tuples, not null-terminated — Ghidra's default string analysis will miss them without the golang-loader plugin.
198
+
199
+ **Detection:** Large static binary (2MB+ for simple programs), `go.buildid`, `runtime.gopanic`, source paths like `/home/user/go/src/`.
200
+
201
+ ### Go Binary UUID Patching for C2 Client Enumeration (BSidesSF 2026)
202
+
203
+ **Pattern (see-two):** A Go-compiled C2 client has a UUID embedded via `-ldflags -X`. The C2 server uses mTLS for authentication. To enumerate other clients and their files, patch the UUID to register as a new client, then use the C2 API to list all clients and download their exfiltrated files.
204
+
205
+ **Approach:**
206
+ 1. Extract embedded UUID from Go build metadata: `go version -m client_binary`
207
+ 2. Binary-patch the UUID (simple byte replacement — Go strings have fixed-length backing arrays)
208
+ 3. Register with the C2 server using the patched binary (mTLS certs are embedded or in distfiles)
209
+ 4. Enumerate clients via API: `GET /api/clients` or iterate known endpoints
210
+ 5. List and download files from each client's GCS bucket or file store
211
+ 6. Grep downloaded files for the flag
212
+
213
+ ```bash
214
+ # Extract Go build info
215
+ go version -m ./client_binary | grep ldflags
216
+ # Output shows: -X main.clientUUID=<uuid>
217
+
218
+ # Patch UUID in binary (replace old UUID bytes with new UUID)
219
+ python3 -c "
220
+ import sys
221
+ data = open('client_binary', 'rb').read()
222
+ old_uuid = b'original-uuid-value-here'
223
+ new_uuid = b'attacker-uuid-value-here'
224
+ patched = data.replace(old_uuid, new_uuid)
225
+ open('client_patched', 'wb').write(patched)
226
+ "
227
+ chmod +x client_patched
228
+ ./client_patched --register
229
+ ```
230
+
231
+ **Key insight:** Go binaries embed string values from `-ldflags -X` directly in the binary data section. Since Go strings are `{ptr, len}` pairs pointing to backing byte arrays, replacing the UUID bytes (same length) produces a valid patched binary. The mTLS certificates authenticate the client to the server but don't bind to a specific UUID.
232
+
233
+ **References:** BSidesSF 2026 "see-two"
234
+
235
+ ---
236
+
237
+ ## Rust Binary Reversing
238
+
239
+ Rust binaries are common in modern CTFs, especially for crypto, systems, and security tooling challenges.
240
+
241
+ ### Rust Recognition
242
+
243
+ ```bash
244
+ # Detect Rust binary
245
+ strings binary | grep -c "rust"
246
+ strings binary | grep "rustc" # Compiler version
247
+ strings binary | grep "/rustc/" # Source paths
248
+ strings binary | grep "core::panicking" # Panic infrastructure
249
+ ```
250
+
251
+ **Key indicators:**
252
+ - `core::panicking::panic` in strings
253
+ - Mangled symbols starting with `_ZN` (Itanium ABI) — e.g., `_ZN4main4main17h...`
254
+ - `.rustc` section in ELF
255
+ - References to `/rustc/<commit_hash>/library/`
256
+ - Large binary size (Rust statically links by default)
257
+
258
+ ### Symbol Demangling
259
+
260
+ ```bash
261
+ # Rust uses Itanium ABI mangling (same as C++)
262
+ # rustfilt demangles Rust-specific symbols
263
+ cargo install rustfilt
264
+ nm binary | rustfilt | grep "main"
265
+
266
+ # Or use c++filt (works for most Rust symbols)
267
+ nm binary | c++filt | grep "main"
268
+
269
+ # In Ghidra: Window → Script Manager → search "Demangler"
270
+ # Enable "DemangleAllScript" for automatic demangling
271
+ ```
272
+
273
+ ### Common Rust Patterns in Decompilation
274
+
275
+ **Option/Result enum:**
276
+ ```text
277
+ # Option<T> in memory: {discriminant (0=None, 1=Some), value}
278
+ # Result<T, E>: {discriminant (0=Ok, 1=Err), union{ok_val, err_val}}
279
+
280
+ # In disassembly:
281
+ # cmp byte [rbp-0x10], 0 → check if None/Err
282
+ # je handle_none_case
283
+ ```
284
+
285
+ **Vec<T> (same as Go slice):**
286
+ ```c
287
+ struct RustVec {
288
+ void *ptr; // heap pointer
289
+ uint64 cap; // capacity
290
+ uint64 len; // length
291
+ };
292
+ ```
293
+
294
+ **String / &str:**
295
+ ```text
296
+ # String (owned): {ptr, capacity, length} — 24 bytes, heap-allocated
297
+ # &str (borrowed): {ptr, length} — 16 bytes, can point anywhere
298
+
299
+ # In decompilation, look for:
300
+ # alloc::string::String::from → String creation
301
+ # core::str::from_utf8 → byte slice to str
302
+ ```
303
+
304
+ **Iterator chains:**
305
+ ```text
306
+ # .iter().map().filter().collect() compiles to loop fusion
307
+ # In disassembly: tight loop with inlined closures
308
+ # Look for: core::iter::adapters::map, filter, etc.
309
+ ```
310
+
311
+ **Panic unwinding:**
312
+ ```bash
313
+ # Panic strings reveal source locations and error messages
314
+ strings binary | grep "panicked at"
315
+ strings binary | grep "called .unwrap().. on"
316
+ # These often contain file paths, line numbers, and variable names
317
+ ```
318
+
319
+ ### Rust-Specific Analysis Tools
320
+
321
+ ```bash
322
+ # cargo-bloat: analyze binary size by function
323
+ cargo install cargo-bloat
324
+ cargo bloat --release -n 50
325
+
326
+ # Ghidra Rust helper scripts
327
+ # https://github.com/DMaroo/GhidRust (Ghidra plugin for Rust binary analysis)
328
+ ```
329
+
330
+ **Key insight:** Rust panic messages are goldmines — they contain source file paths, line numbers, and descriptive error strings even in release builds. Always `strings binary | grep "panicked"` first. Rust's monomorphization means generic functions get duplicated per type — expect many similar-looking functions.
331
+
332
+ **Detection:** `core::panicking`, `.rustc` section, `/rustc/` paths, `_ZN` mangled symbols with Rust-style module paths.
333
+
334
+ ---
335
+
336
+ ## Swift Binary Reversing
337
+
338
+ See [platforms.md](platforms.md#swift-binary-reversing) for full Swift reversing guide including demangling, runtime structures, and Ghidra integration. Key quick reference:
339
+
340
+ ```bash
341
+ # Detect Swift binary
342
+ strings binary | grep "swift"
343
+ otool -l binary | grep "swift"
344
+
345
+ # Demangle Swift symbols
346
+ swift demangle 's14MyApp0A8ClassC10checkInput6resultSbSS_tF'
347
+ # → MyApp.MyAppClass.checkInput(result: String) -> Bool
348
+
349
+ # Key runtime functions: swift_allocObject, swift_release, swift_once
350
+ # String: small (≤15 bytes inline) or large (heap pointer + length)
351
+ # Protocol witness tables = dynamic dispatch (like vtables)
352
+ ```
353
+
354
+ **Detection:** `__swift5_*` sections in Mach-O, `swift_` runtime symbols, `s` prefix in mangled names.
355
+
356
+ ---
357
+
358
+ ## Kotlin / JVM Binary Reversing
359
+
360
+ Kotlin compiles to JVM bytecode or native (via Kotlin/Native). Common in Android and server-side CTF.
361
+
362
+ ### JVM Bytecode (Android/Server)
363
+
364
+ ```bash
365
+ # Detect Kotlin
366
+ strings classes.dex | grep "kotlin"
367
+ # Look for: kotlin.Metadata annotation, kotlin/jvm/internal/*
368
+
369
+ # Decompile
370
+ jadx classes.dex # Best for Kotlin bytecode
371
+ cfr classes.jar --kotlin # CFR with Kotlin mode
372
+ fernflower classes.jar output/ # IntelliJ's decompiler
373
+
374
+ # Kotlin-specific patterns in decompiled output:
375
+ # - Companion objects: ClassName$Companion
376
+ # - Data classes: copy(), component1(), component2(), toString()
377
+ # - Coroutines: ContinuationImpl, invokeSuspend, state machine
378
+ # - Null checks: Intrinsics.checkNotNull() everywhere
379
+ # - When expression: compiled as tableswitch/lookupswitch
380
+ # - Sealed classes: instanceof checks in chain
381
+ ```
382
+
383
+ **Kotlin coroutines in disassembly:**
384
+ ```text
385
+ # Coroutines compile to state machines:
386
+ # invokeSuspend(result) {
387
+ # switch (this.label) {
388
+ # case 0: this.label = 1; return suspendFunction();
389
+ # case 1: processResult(result); return Unit;
390
+ # }
391
+ # }
392
+ # Each suspend point becomes a state in the switch.
393
+ # Follow the state machine to understand async flow.
394
+ ```
395
+
396
+ ### Kotlin/Native
397
+
398
+ ```bash
399
+ # Kotlin/Native produces platform binaries (no JVM)
400
+ # Recognize by: konan, kotlin.native strings
401
+ strings binary | grep "konan"
402
+
403
+ # Much harder to reverse — no reflection metadata
404
+ # Uses LLVM backend, looks similar to C/C++ in disassembly
405
+ # Key functions: InitRuntime, DeinitRuntime, CreateStablePointer
406
+ # Memory management: automatic reference counting (not GC)
407
+ ```
408
+
409
+ **Detection:** `kotlin.Metadata` annotations (JVM), `konan` strings (Native), `kotlin/` package paths.
410
+
411
+ ---
412
+
413
+ ## D Language Binary Reversing (CSAW CTF 2016)
414
+
415
+ D language binaries have unique symbol mangling different from C++. Template instantiation at compile-time produces many function variants.
416
+
417
+ ```bash
418
+ # Recognition: D binaries use different mangling than C++
419
+ # Symbols contain "_D" prefix and numeric length-prefixed names
420
+ # Example: _D4mainQaFNaNbNfZv
421
+
422
+ # Symbol demangling:
423
+ # GDB: set language d
424
+ # Radare2: export names show demangled D symbols
425
+ # Online: dlang.org/phobos/core_demangle.html
426
+
427
+ # Common D binary patterns:
428
+ # - Templates instantiated at compile-time: enc!("111"), enc!("222"), ...
429
+ # - Garbage collector references (GC.malloc, GC.free)
430
+ # - Phobos standard library functions (_D3std...)
431
+ # - String processing: std.string, std.conv.to
432
+
433
+ # Reversing a D cipher (XOR with cycling key):
434
+ def reverse_d_cipher(encrypted, num_functions=500):
435
+ """D binaries may chain multiple transformation functions.
436
+ Each function XORs with key character, then XORs with key length.
437
+ Process in reverse order."""
438
+ result = encrypted[:]
439
+ for i in range(num_functions - 1, -1, -1):
440
+ key = str(i) * 3 # e.g., "499499499" for function enc!("499")
441
+ key_len = len(key)
442
+ for j in range(len(result)):
443
+ result[j] ^= key_len
444
+ result[j] ^= ord(key[j % key_len])
445
+ return bytes(result)
446
+ ```
447
+
448
+ **Key insight:** D binaries are rare in CTFs but identifiable by `_D` symbol prefixes and Phobos library references. The compile-time template system means D functions may be duplicated hundreds of times with different parameters — look for patterns like `enc!("N")` where N varies.
449
+
450
+ ---
451
+
452
+ ### Haskell Binary Reversing via STG Closures and hsdecomp (hxp CTF 2017, Codegate 2018)
453
+
454
+ GHC-compiled Haskell binaries use the STG (Spineless Tagless G-machine) execution model, making them notoriously difficult to reverse due to lazy evaluation, closures, and thunks. The STG machine turns everything into closure calls rather than direct function calls.
455
+
456
+ **Recognition:**
457
+ - Shared libraries: `libHSbase-*`, `libHSrts-*`
458
+ - Entry symbol: `hs_main` (replaces standard `main`)
459
+ - Mangled symbols use Z-encoding: `z` = prefix, `Z` = uppercase, `zd` = `.`, `zi` = `$`
460
+ - GHC calling convention register mapping: `rbx` = R1, `r14` = R2
461
+
462
+ **Closure structure:**
463
+ Closures are structs where the first qword points to the info table/code. The info table precedes the code pointer and contains metadata (closure type, layout info, SRT).
464
+
465
+ ```bash
466
+ # Identify Haskell binary
467
+ ldd ./binary | grep libHS
468
+ readelf -s ./binary | grep hs_main
469
+
470
+ # Decompile with hsdecomp (github.com/gereeter/hsdecomp)
471
+ # Recovers closure structure and pattern matching into pseudo-Haskell
472
+ python2 hsdecomp ./binary
473
+
474
+ # Compile reference for monkey-patching
475
+ ghc -O0 reference.hs -o reference
476
+ objcopy --dump-section .text=main_code reference
477
+ ```
478
+
479
+ **Monkey-patching technique:**
480
+ When decompilation fails or closures are opaque, compile a minimal Haskell program with the same GHC version, extract the compiled `Main_main_info` closure code, and patch it into the challenge binary. This forces evaluation of hidden closures and prints their results by replacing the main entry point with a known evaluator.
481
+
482
+ ```haskell
483
+ -- reference.hs: minimal program that evaluates and prints the target closure
484
+ module Main where
485
+ main :: IO ()
486
+ main = print targetClosure -- replace with the closure you want to evaluate
487
+ ```
488
+
489
+ **Key insight:** Haskell binaries are notoriously hard to reverse due to lazy evaluation, closures, and thunks. The STG machine turns everything into closure calls rather than direct function calls. `hsdecomp` recovers the closure structure and pattern matching. When decompilation fails, monkey-patching a known `Main_main_info` from a reference binary forces evaluation of hidden closures and prints results.
490
+
491
+ **Detection:** `libHSbase-*` shared libraries, `hs_main` entry, Z-encoded symbols (e.g., `MainZCmain`), GHC version strings.
492
+
493
+ **References:** hxp CTF 2017, Codegate 2018
494
+
495
+ ---
496
+
497
+ ### Haskell Binary RE via GHC CMM Intermediate Language (N1CTF 2018)
498
+
499
+ GHC-compiled Haskell binaries are nearly impossible to decompile with IDA due to the STG execution model. When a `.cmm` (C-- intermediate) file is available or recoverable, read it to understand thunks, closures, and lazy evaluation semantics. For exponentially-growing recursive structures, compute segment sizes with memoization and use binary search instead of materializing the full string.
500
+
501
+ **Pattern:** The binary builds a recursive string structure where `f(n) = s1 + f(n-1) + s2 + f(n-1) + s3`. Direct evaluation is `O(2^n)` in both time and space. Instead, compute the size of each recursion level with memoization, then binary-search for the target character index by walking the segment boundaries.
502
+
503
+ ```python
504
+ # Haskell recursive string: f(n) = s1 + f(n-1) + s2 + f(n-1) + s3
505
+ # Direct evaluation is O(2^n) -- use size memoization:
506
+ from functools import lru_cache
507
+
508
+ @lru_cache(maxsize=None)
509
+ def fsize(n):
510
+ if n == 0: return len(s0)
511
+ return len(s1) + fsize(n-1) + len(s2) + fsize(n-1) + len(s3)
512
+
513
+ def char_at(n, offset):
514
+ if n == 0: return s0[offset]
515
+ if offset < len(s1): return s1[offset]
516
+ offset -= len(s1)
517
+ if offset < fsize(n-1): return char_at(n-1, offset)
518
+ offset -= fsize(n-1)
519
+ if offset < len(s2): return s2[offset]
520
+ offset -= len(s2)
521
+ return char_at(n-1, offset)
522
+ ```
523
+
524
+ **Key insight:** GHC's CMM (C minus minus) intermediate representation preserves enough structure to identify algorithms. For recursive string constructions that double in size each level, compute segment sizes with memoization and binary-search for target indices instead of materializing the exponentially-growing string.
525
+
526
+ **Detection:** Haskell binary (see recognition above) with a `.cmm` file included in the challenge distribution. Look for recursive closure applications that produce string-like data with exponential growth.
527
+
528
+ **References:** N1CTF 2018
529
+
530
+ ---
531
+
532
+ ## C++ Binary Reversing (Quick Reference)
533
+
534
+ While C++ RE is well-covered by general tools, these patterns are CTF-specific:
535
+
536
+ ### vtable Reconstruction
537
+
538
+ ```text
539
+ # Virtual function tables (vtables):
540
+ # First 8 bytes of object → pointer to vtable
541
+ # vtable entries: [typeinfo_ptr, destructor, method1, method2, ...]
542
+ # In Ghidra: Data → Create Pointer at vtable address
543
+
544
+ # Identify polymorphic dispatch:
545
+ # mov rax, [rdi] # Load vtable from this pointer
546
+ # call [rax + 0x18] # Call 4th virtual method (0x18/8 = 3rd after typeinfo+dtor)
547
+ ```
548
+
549
+ ### RTTI (Run-Time Type Information)
550
+
551
+ ```bash
552
+ # If not stripped, RTTI reveals class hierarchy
553
+ strings binary | grep -E "^[0-9]+[A-Z]" # Mangled type names
554
+ c++filt _ZTI7MyClass # → typeinfo for MyClass
555
+
556
+ # In Ghidra: search for vtable references, follow typeinfo pointer
557
+ # typeinfo struct: {vtable_for_typeinfo, name_string, base_class_ptr}
558
+ ```
559
+
560
+ ### Standard Library Patterns
561
+
562
+ ```text
563
+ std::string (libstdc++):
564
+ SSO (Small String Optimization): inline buffer for ≤15 chars
565
+ Layout: {char* ptr, size_t size, union{size_t cap, char buf[16]}}
566
+
567
+ std::vector<T>:
568
+ {T* begin, T* end, T* capacity_end}
569
+
570
+ std::map<K,V>:
571
+ Red-black tree: each node has {left, right, parent, color, key, value}
572
+
573
+ std::unordered_map<K,V>:
574
+ Hash table: {bucket_array, size, load_factor_max, ...}
575
+ ```
576
+
577
+ ---
578
+
579
+ ### Rust Lifetime Escape via Compiler Bug #25860 (Hack.lu 2018)
580
+
581
+ **Pattern:** Rust compiler bug rust-lang/rust#25860 — higher-ranked lifetime variance was checked incorrectly, so a closure could "reborrow" a reference and unsoundly extend its lifetime to `'static`. In a Rust-only sandbox that runs safe code (no `unsafe` block) this bug yields a UAF primitive: alias a `Vec<u8>` heap buffer as a `(usize, usize, usize)` tuple and read/write past its end.
582
+
583
+ ```rust
584
+ // Triggering pattern — safe Rust only
585
+ fn extend<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }
586
+
587
+ fn bad<T>(v: T) -> &'static T {
588
+ // Closure infers 'a = 'static because of the variance bug
589
+ let f: fn(&'_ &'_ (), &'_ T) -> &'_ T = extend;
590
+ f(&&(), &v) // returned ref now outlives v
591
+ }
592
+
593
+ fn main() {
594
+ let aliased: &'static Vec<u8> = bad(vec![1u8, 2, 3]);
595
+ // Reinterpret the Vec as its raw header: (ptr, len, cap)
596
+ let header: &(usize, usize, usize) =
597
+ unsafe { std::mem::transmute(aliased) };
598
+ println!("ptr={:#x} len={} cap={}", header.0, header.1, header.2);
599
+ }
600
+ ```
601
+
602
+ **Key insight:** A single soundness bug in the borrow checker turns a sandboxed Rust playground into an arbitrary-read-write primitive — no `unsafe` required. When a Rust CTF bans `unsafe` and pins a specific compiler version, grep the rust-lang issue tracker for `soundness` bugs fixed after that version: each one is an exploitation candidate. Repro this family with `std::mem::transmute` only after you have a lifetime-extended reference; the alias is the hard part.
603
+
604
+ **References:** Hack.lu CTF 2018 — Rusty CodePad, writeup 11859
605
+
606
+ ---
607
+
608
+ ### Rust #[no_mangle] libc Override for seccomp Bypass (Hack.lu 2018)
609
+
610
+ **Pattern:** A sandboxed Rust binary calls `prctl(PR_SET_SECCOMP, ...)` early in `main`, then drops to user code. Because the sandboxed crate is *linked statically* alongside libc, defining an `extern "C"` function named `prctl` with `#[no_mangle]` shadows libc's symbol at link time. Returning `0` from the override disables seccomp, leaving every syscall reachable from the attacker's code.
611
+
612
+ ```rust
613
+ // User-supplied code — linked into the same binary as the sandbox harness
614
+ #[no_mangle]
615
+ pub extern "C" fn prctl(_a: i64, _b: i64) -> i64 {
616
+ 0 // pretend success, do not install any filter
617
+ }
618
+
619
+ // When main() calls prctl(PR_SET_SECCOMP, ...) it hits our override
620
+ fn main() {
621
+ // The real program runs without seccomp filtering
622
+ }
623
+ ```
624
+
625
+ **Key insight:** Rust's static-linking default means `extern "C"` + `#[no_mangle]` is effectively a dynamic hook at compile time — any libc symbol the sandbox harness calls (`prctl`, `chroot`, `seteuid`, `read`) can be redefined by attacker crate code that ships inside the same binary. Harden by routing syscalls through `libc::syscall(SYS_prctl, ...)` directly (which bypasses the symbol table) or by using `-Wl,-Bsymbolic` to prefer the intended definitions.
626
+
627
+ **References:** Hack.lu CTF 2018 — Rusty CodePad seccomp variant, writeup 11864
628
+
629
+ ### Rust xmmword Constant Extraction via IDAPython (Insomnihack 2019)
630
+
631
+ **Pattern:** Rust stores literal byte buffers (flag expected values, XOR tables) as 16-byte xmmword constants in `.rodata`. IDA parses these as `xmmword_xxxx` tokens. Walk the `.rodata` range in IDAPython, read each xmmword, reverse any simple obfuscation (e.g., `(dword >> 2) ^ 0xA`), and dump the plaintext.
632
+
633
+ ```python
634
+ import idc, idaapi
635
+ start, end = 0x4A1000, 0x4A1100
636
+ for ea in range(start, end, 4):
637
+ d = idc.get_wide_dword(ea)
638
+ print(chr((d >> 2) ^ 0xA), end='')
639
+ ```
640
+
641
+ **Key insight:** Rust binaries are hard to decompile but very easy to scan for literal data. Any check of the form `input == const_buf` leaves the expected value in `.rodata` untouched. Grep for `mov reg, xmmword [rip+offset]` to find the slot, then dump.
642
+
643
+ **References:** Insomnihack teaser 2019 — beginner_reverse, writeup 12910
644
+
645
+ ---
646
+
647
+ ## Nuitka-Compiled Python — Module Stub Injection (X-MAS CTF 2018)
648
+
649
+ **Pattern:** Nuitka turns Python sources into a monolithic native binary, but still uses the standard Python import machinery at runtime. Put a dummy `base64.py` / `midi.py` / `whatever_module.py` in the current working directory before executing the binary; the module system prefers CWD, so your stub is loaded instead of the embedded one. Log every attribute access and incrementally build a shim of the API the binary uses.
650
+
651
+ ```python
652
+ # base64.py next to the binary
653
+ class _Trace:
654
+ def __getattr__(self, name):
655
+ def f(*a, **k):
656
+ print(f'base64.{name}({a!r}, {k!r})')
657
+ return b''
658
+ return f
659
+ import sys; sys.modules[__name__] = _Trace()
660
+ ```
661
+
662
+ Run `./target_bin`; the printed calls reveal the algorithm without decompiling the Nuitka output.
663
+
664
+ **Key insight:** Any runtime that still resolves module names through `sys.path` (Nuitka, PyInstaller with `--onefile`, Py2Exe with `--bundle_files=1` off, frozen CPython) can be shimmed at import time with CWD stubs. Grep `strings` output for module names to pick good hook targets.
665
+
666
+ **References:** X-MAS CTF 2018 — A Christmas Carol, writeup 12667