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,431 @@
1
+ # CTF Misc - Encodings & Media
2
+
3
+ ## Table of Contents
4
+ - [Common Encodings](#common-encodings)
5
+ - [Base64](#base64)
6
+ - [Base32](#base32)
7
+ - [Hex](#hex)
8
+ - [IEEE 754 Floating Point Encoding](#ieee-754-floating-point-encoding)
9
+ - [UTF-16 Endianness Reversal (LACTF 2026)](#utf-16-endianness-reversal-lactf-2026)
10
+ - [BCD (Binary-Coded Decimal) Encoding (VuwCTF 2025)](#bcd-binary-coded-decimal-encoding-vuwctf-2025)
11
+ - [Multi-Layer Encoding Detection (0xFun 2026)](#multi-layer-encoding-detection-0xfun-2026)
12
+ - [URL Encoding](#url-encoding)
13
+ - [ROT13 / Caesar](#rot13--caesar)
14
+ - [Caesar Brute Force](#caesar-brute-force)
15
+ - [QR Codes](#qr-codes)
16
+ - [Basic Commands](#basic-commands)
17
+ - [QR Structure](#qr-structure)
18
+ - [Repairing Damaged QR](#repairing-damaged-qr)
19
+ - [Finder Pattern Template](#finder-pattern-template)
20
+ - [QR Code Chunk Reassembly (LACTF 2026)](#qr-code-chunk-reassembly-lactf-2026)
21
+ - [QR Code Chunk Reassembly via Indexed Directories (UTCTF 2026)](#qr-code-chunk-reassembly-via-indexed-directories-utctf-2026)
22
+ - [Multi-Stage URL Encoding Chain (UTCTF 2026)](#multi-stage-url-encoding-chain-utctf-2026)
23
+ - [Esoteric Languages](#esoteric-languages)
24
+ - [Whitespace Language Parser (BYPASS CTF 2025)](#whitespace-language-parser-bypass-ctf-2025)
25
+ - [Custom Brainfuck Variants (Themed Esolangs)](#custom-brainfuck-variants-themed-esolangs)
26
+ - [Multi-Layer Esoteric Language Chains (Break In 2016)](#multi-layer-esoteric-language-chains-break-in-2016)
27
+ - [base65536 CJK Unicode Binary Encoding (IceCTF 2018)](#base65536-cjk-unicode-binary-encoding-icectf-2018)
28
+
29
+ See also: [encodings-advanced.md](encodings-advanced.md) - Verilog/HDL, Gray code, binary tree encoding, RTF custom tags, SMS PDU decoding, multi-encoding solvers, UTF-9, pixel binary encoding, hex Sudoku + QR, TOPKEK, MaxiCode
30
+
31
+ ---
32
+
33
+ ## Common Encodings
34
+
35
+ ### Base64
36
+ ```bash
37
+ echo "encoded" | base64 -d
38
+ # Charset: A-Za-z0-9+/=
39
+ ```
40
+
41
+ ### Base32
42
+ ```bash
43
+ echo "OBUWG32DKRDHWMLUL53TI43OG5PWQNDSMRPXK3TSGR3DG3BRNY4V65DIGNPW2MDCGFWDGX3DGBSDG7I=" | base32 -d
44
+ # Charset: A-Z2-7= (no lowercase, no 0,1,8,9)
45
+ ```
46
+
47
+ ### Hex
48
+ ```bash
49
+ echo "68656c6c6f" | xxd -r -p
50
+ ```
51
+
52
+ ### IEEE 754 Floating Point Encoding
53
+
54
+ Numbers that encode ASCII text when viewed as raw IEEE 754 bytes:
55
+
56
+ ```python
57
+ import struct
58
+
59
+ values = [240600592, 212.2753143310547, 2.7884192016691608e+23]
60
+
61
+ # Each float32 packs to 4 ASCII bytes
62
+ for v in values:
63
+ packed = struct.pack('>f', v) # Big-endian single precision
64
+ print(f"{v} -> {packed}") # b'Meta', b'CTF{', b'fl04'
65
+
66
+ # For double precision (8 bytes per value):
67
+ # struct.pack('>d', v)
68
+ ```
69
+
70
+ **Key insight:** If challenge gives a list of numbers (mix of integers, decimals, scientific notation), try packing each as IEEE 754 float32 (`struct.pack('>f', v)`) — the 4 bytes often spell ASCII text.
71
+
72
+ ### UTF-16 Endianness Reversal (LACTF 2026)
73
+
74
+ **Pattern (endians):** Text "turned to Japanese" -- mojibake from UTF-16 endianness mismatch.
75
+
76
+ **Fix:** Reverse the encoding/decoding order:
77
+ ```python
78
+ # If encoded as UTF-16-LE but decoded as UTF-16-BE:
79
+ fixed = mojibake.encode('utf-16-be').decode('utf-16-le')
80
+
81
+ # If encoded as UTF-16-BE but decoded as UTF-16-LE:
82
+ fixed = mojibake.encode('utf-16-le').decode('utf-16-be')
83
+ ```
84
+
85
+ **Identification:** Text appears as CJK characters (Japanese/Chinese), challenge mentions "translation" or "endian".
86
+
87
+ ### BCD (Binary-Coded Decimal) Encoding (VuwCTF 2025)
88
+
89
+ **Pattern:** Challenge name hints at ratio (e.g., "1.5x" = 1.5:1 byte ratio). Each nibble encodes one decimal digit.
90
+
91
+ ```python
92
+ def bcd_decode(data):
93
+ """Decode BCD: each byte = 2 decimal digits."""
94
+ return ''.join(f'{(b>>4)&0xf}{b&0xf}' for b in data)
95
+
96
+ # Then convert decimal string to ASCII
97
+ ascii_text = ''.join(chr(int(decoded[i:i+2])) for i in range(0, len(decoded), 2))
98
+ ```
99
+
100
+ ### Multi-Layer Encoding Detection (0xFun 2026)
101
+
102
+ **Pattern (139 steps):** Recursive decoding with troll flags as decoys.
103
+
104
+ **Critical rule:** When data is all hex chars (0-9, a-f), decode as **hex FIRST**, not base64 (which also accepts those chars).
105
+
106
+ ```python
107
+ def auto_decode(data):
108
+ while True:
109
+ data = data.strip()
110
+ if data.startswith('REAL_DATA_FOLLOWS:'):
111
+ data = data.split(':', 1)[1]
112
+ # Prioritize hex when ambiguous
113
+ if all(c in '0123456789abcdefABCDEF' for c in data) and len(data) % 2 == 0:
114
+ data = bytes.fromhex(data).decode('ascii', errors='replace')
115
+ elif set(data) <= set('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='):
116
+ data = base64.b64decode(data).decode('ascii', errors='replace')
117
+ else:
118
+ break
119
+ return data
120
+ ```
121
+
122
+ **Ignore troll flags** — check for "keep decoding" or "REAL_DATA_FOLLOWS:" markers.
123
+
124
+ ### URL Encoding
125
+ ```python
126
+ import urllib.parse
127
+ urllib.parse.unquote('hello%20world')
128
+ ```
129
+
130
+ ### ROT13 / Caesar
131
+ ```bash
132
+ echo "uryyb" | tr 'a-zA-Z' 'n-za-mN-ZA-M'
133
+ ```
134
+
135
+ **ROT13 patterns:** `gur` = "the", `synt` = "flag"
136
+
137
+ ### Caesar Brute Force
138
+ ```python
139
+ text = "Khoor Zruog"
140
+ for shift in range(26):
141
+ decoded = ''.join(
142
+ chr((ord(c) - 65 - shift) % 26 + 65) if c.isupper()
143
+ else chr((ord(c) - 97 - shift) % 26 + 97) if c.islower()
144
+ else c for c in text)
145
+ print(f"{shift:2d}: {decoded}")
146
+ ```
147
+
148
+ ---
149
+
150
+ ## QR Codes
151
+
152
+ ### Basic Commands
153
+ ```bash
154
+ zbarimg qrcode.png # Decode
155
+ zbarimg -S*.enable qr.png # All barcode types
156
+ qrencode -o out.png "data" # Encode
157
+ ```
158
+
159
+ ### QR Structure
160
+
161
+ **Finder patterns (3 corners):** 7x7 modules at top-left, top-right, bottom-left
162
+
163
+ **Version formula:** `(version * 4) + 17` modules per side
164
+
165
+ ### Repairing Damaged QR
166
+
167
+ ```python
168
+ from PIL import Image
169
+ import numpy as np
170
+
171
+ img = Image.open('damaged_qr.png')
172
+ arr = np.array(img)
173
+
174
+ # Convert to binary
175
+ gray = np.mean(arr, axis=2)
176
+ binary = (gray < 128).astype(int)
177
+
178
+ # Find QR bounds
179
+ rows = np.any(binary, axis=1)
180
+ cols = np.any(binary, axis=0)
181
+ rmin, rmax = np.where(rows)[0][[0, -1]]
182
+ cmin, cmax = np.where(cols)[0][[0, -1]]
183
+
184
+ # Check finder patterns
185
+ qr = binary[rmin:rmax+1, cmin:cmax+1]
186
+ print("Top-left:", qr[0:7, 0:7].sum()) # Should be ~25
187
+ ```
188
+
189
+ ### Finder Pattern Template
190
+ ```python
191
+ finder_pattern = [
192
+ [1,1,1,1,1,1,1],
193
+ [1,0,0,0,0,0,1],
194
+ [1,0,1,1,1,0,1],
195
+ [1,0,1,1,1,0,1],
196
+ [1,0,1,1,1,0,1],
197
+ [1,0,0,0,0,0,1],
198
+ [1,1,1,1,1,1,1],
199
+ ]
200
+ ```
201
+
202
+ ### QR Code Chunk Reassembly (LACTF 2026)
203
+
204
+ **Pattern (error-correction):** QR code split into grid of chunks (e.g., 5x5 of 9x9 pixels), shuffled.
205
+
206
+ **Solving approach:**
207
+ 1. **Fix known chunks:** Use structural patterns -- finder patterns (3 corners), timing patterns, alignment patterns -- to place ~50% of chunks
208
+ 2. **Extract codeword constraints:** For each candidate payload length, use QR spec to identify which pixels are invariant across encodings
209
+ 3. **Backtracking search:** Assign remaining chunks under pixel constraints until QR decodes successfully
210
+
211
+ **Tools:** `segno` (Python QR library), `zbarimg` for decoding.
212
+
213
+ ### QR Code Chunk Reassembly via Indexed Directories (UTCTF 2026)
214
+
215
+ **Pattern (QRecreate):** QR code split into numbered chunks stored in separate directories. Directory names encode the chunk index as base64 (e.g., `MDAx` → `001` → index 1).
216
+
217
+ **Solving approach:**
218
+ 1. Decode each directory name from base64 to get the numeric index
219
+ 2. Sort chunks by decoded index
220
+ 3. Arrange in a grid (e.g., 100 chunks → 10x10) and stitch into a single image
221
+ 4. Decode the reconstructed QR code
222
+
223
+ ```python
224
+ import os, base64, math
225
+ from PIL import Image
226
+
227
+ # 1. Decode directory names to get indices
228
+ chunks = []
229
+ for dirname in os.listdir('chunks/'):
230
+ index = int(base64.b64decode(dirname).decode())
231
+ tile = Image.open(f'chunks/{dirname}/tile.png')
232
+ chunks.append((index, tile))
233
+
234
+ # 2. Sort by index and arrange in grid
235
+ chunks.sort(key=lambda x: x[0])
236
+ n = len(chunks)
237
+ side = int(math.isqrt(n))
238
+ tile_w, tile_h = chunks[0][1].size
239
+
240
+ canvas = Image.new("RGB", (side * tile_w, side * tile_h), (255, 255, 255))
241
+ for i, (_, tile) in enumerate(chunks):
242
+ r, c = divmod(i, side)
243
+ canvas.paste(tile, (c * tile_w, r * tile_h))
244
+
245
+ canvas.save('reconstructed_qr.png')
246
+ # 3. Decode with zbarimg or pyzbar
247
+ ```
248
+
249
+ **Key insight:** Unlike the LACTF variant (shuffled chunks requiring structural analysis), indexed chunks just need sorting. The challenge is recognizing that directory names are base64-encoded indices. Check `base64 -d` on folder names when they look like random strings.
250
+
251
+ ---
252
+
253
+ ## Multi-Stage URL Encoding Chain (UTCTF 2026)
254
+
255
+ **Pattern (Breadcrumbs):** Flag is hidden behind a chain of URLs, each encoded differently. Follow the breadcrumbs across external resources (GitHub Gists, Pastebin, etc.), decoding at each hop.
256
+
257
+ **Common encoding layers per hop:**
258
+ 1. **Base64** → URL to next resource
259
+ 2. **Hex** → URL to next resource (e.g., `68747470733a2f2f...` = `https://...`)
260
+ 3. **ROT13** → final flag
261
+
262
+ **Decoding workflow:**
263
+ ```python
264
+ import base64, codecs
265
+
266
+ # Hop 1: Base64
267
+ hop1 = "aHR0cHM6Ly9naXN0Lmdp..."
268
+ url2 = base64.b64decode(hop1).decode()
269
+
270
+ # Hop 2: Hex-encoded URL
271
+ hop2 = "68747470733a2f2f..."
272
+ url3 = bytes.fromhex(hop2).decode()
273
+
274
+ # Hop 3: ROT13-encoded flag
275
+ hop3 = "hgsynt{...}"
276
+ flag = codecs.decode(hop3, 'rot_13')
277
+ ```
278
+
279
+ **Key insight:** Each resource contains a hint about the next encoding (e.g., "Three letters follow" hints at 3-character encoding like hex). Look for contextual clues in surrounding text (poetry, comments, filenames) that indicate the encoding type.
280
+
281
+ **Detection:** Challenge mentions "trail", "breadcrumbs", "follow", or "scavenger hunt". First resource contains what looks like encoded data rather than a direct flag.
282
+
283
+ ---
284
+
285
+ ## Esoteric Languages
286
+
287
+ | Language | Pattern |
288
+ |----------|---------|
289
+ | Brainfuck | `++++++++++[>+++++++>` |
290
+ | Whitespace | Only spaces, tabs, newlines (or S/T/L substitution) |
291
+ | Ook! | `Ook. Ook? Ook!` |
292
+ | Malbolge | Extremely obfuscated |
293
+ | Piet | Image-based |
294
+
295
+ ### Whitespace Language Parser (BYPASS CTF 2025)
296
+
297
+ **Pattern (Whispers of the Cursed Scroll):** File contains only S (space), T (tab), L (linefeed) characters — or visible substitutes. Stack-based virtual machine (VM) with PUSH, OUTPUT, and EXIT instructions.
298
+
299
+ **Instruction set (IMP = Instruction Modification Parameter):**
300
+ | Instruction | Encoding | Action |
301
+ |-------------|----------|--------|
302
+ | PUSH | `S S` + sign + binary + `L` | Push number to stack (S=0, T=1, L=terminator) |
303
+ | OUTPUT CHAR | `T L S S` | Pop stack, print as ASCII character |
304
+ | EXIT | `L L L` | Halt program |
305
+
306
+ ```python
307
+ def solve_whitespace(content):
308
+ # Convert to S/T/L tokens (handle both raw whitespace and visible chars)
309
+ if any(c in content for c in 'STL'):
310
+ code = [c for c in content if c in 'STL']
311
+ else:
312
+ code = [{'\\s': 'S', '\\t': 'T', '\\n': 'L'}.get(c, '') for c in content]
313
+ code = [c for c in code if c]
314
+
315
+ stack, output, i = [], "", 0
316
+
317
+ while i < len(code):
318
+ if code[i:i+2] == ['S', 'S']: # PUSH
319
+ i += 2
320
+ sign = 1 if code[i] == 'S' else -1
321
+ i += 1
322
+ val = 0
323
+ while i < len(code) and code[i] != 'L':
324
+ val = (val << 1) + (1 if code[i] == 'T' else 0)
325
+ i += 1
326
+ i += 1 # skip terminator L
327
+ stack.append(sign * val)
328
+ elif code[i:i+4] == ['T', 'L', 'S', 'S']: # OUTPUT CHAR
329
+ i += 4
330
+ if stack:
331
+ output += chr(stack.pop())
332
+ elif code[i:i+3] == ['L', 'L', 'L']: # EXIT
333
+ break
334
+ else:
335
+ i += 1
336
+
337
+ return output
338
+ ```
339
+
340
+ **Identification:** File with only whitespace characters, or challenge mentions "invisible code", "blank page", or uses S/T/L substitution. Try [Whitespace interpreter online](https://vii5ard.github.io/whitespace/) for quick testing.
341
+
342
+ ---
343
+
344
+ ### Custom Brainfuck Variants (Themed Esolangs)
345
+
346
+ **Pattern:** File contains repetitive themed words (e.g., "arch", "linux", "btw") used as substitutes for Brainfuck operations. Common in Easy/Misc CTF challenges.
347
+
348
+ **Identification:**
349
+ - File is ASCII text with very long lines of repeated words
350
+ - Small vocabulary (5-8 unique words)
351
+ - One word appears as a line terminator (maps to `.` output)
352
+ - Two words are used for increment/decrement (one has many repeats per line)
353
+ - Words often relate to a meme or theme (e.g., "I use Arch Linux BTW")
354
+
355
+ **Standard Brainfuck operations to map:**
356
+ | Op | Meaning | Typical pattern |
357
+ |----|---------|-----------------|
358
+ | `+` | Increment cell | Most repeated word (defines values) |
359
+ | `-` | Decrement cell | Second most repeated word |
360
+ | `>` | Move pointer right | Short word, appears alone or with `.` |
361
+ | `<` | Move pointer left | Paired with `>` word |
362
+ | `[` | Begin loop | Appears at start of lines with `]` counterpart |
363
+ | `]` | End loop | Appears at end of same lines as `[` |
364
+ | `.` | Output char | Line terminator word |
365
+
366
+ **Solving approach:**
367
+ ```python
368
+ from collections import Counter
369
+ words = content.split()
370
+ freq = Counter(words)
371
+ # Most frequent = likely + or -, line-ender = likely .
372
+
373
+ # Map words to BF ops, translate, run standard BF interpreter
374
+ mapping = {'arch': '+', 'linux': '-', 'i': '>', 'use': '<',
375
+ 'the': '[', 'way': ']', 'btw': '.'}
376
+ bf = ''.join(mapping.get(w, '') for w in words)
377
+ # Then execute bf string with a standard Brainfuck interpreter
378
+ ```
379
+
380
+ **Real example (0xL4ugh CTF - "iUseArchBTW"):** `.archbtw` extension, "I use Arch Linux BTW" meme theme.
381
+
382
+ **Tips:** Try swapping `+`/`-` or `>`/`<` if output is not ASCII. Verify output starts with known flag format.
383
+
384
+ ---
385
+
386
+ ### Multi-Layer Esoteric Language Chains (Break In 2016)
387
+
388
+ Challenges may stack multiple esoteric languages requiring sequential interpretation:
389
+
390
+ 1. **Piet:** Visual programming language using colored pixel blocks. Execute PNG images as code:
391
+ ```bash
392
+ npiet challenge.png # npiet interpreter
393
+ # Or: java -jar PietDev.jar challenge.png
394
+ ```
395
+
396
+ 2. **Malbolge:** Extremely difficult esoteric language. Decode output from previous layer:
397
+ ```bash
398
+ # Piet output → base64 decode → Malbolge source
399
+ echo "piet_output" | base64 -d > program.mal
400
+ malbolge program.mal # Or use online interpreter
401
+ ```
402
+
403
+ Common esoteric chains: Piet → base64 → Malbolge, Brainfuck → Ook → Whitespace, JSFuck → standard JS.
404
+
405
+ **Key insight:** When a PNG file doesn't contain obvious visual stego, try interpreting it as Piet code. Use `file` + visual inspection to identify the first layer, then decode sequentially.
406
+
407
+ ---
408
+
409
+ ## base65536 CJK Unicode Binary Encoding (IceCTF 2018)
410
+
411
+ **Pattern:** A blob that looks like a wall of Chinese characters (CJK Unified Ideographs) is actually a **base65536** encoding: each character carries two bytes of data, mapping 0x0000..0xFFFF to a picked subset of 65,536 Unicode codepoints. Detect by `file` reporting "Unicode text, UTF-8" with mostly CJK codepoints; decode with the `base65536` npm package or the Python port.
412
+
413
+ ```bash
414
+ # Node.js / npm path
415
+ npm install -g base65536
416
+ echo -n "宝䀈䀋..." | base65536 --decode > out.bin
417
+
418
+ # Python port
419
+ pip install base65536
420
+ python3 - <<'PY'
421
+ import base65536, sys
422
+ sys.stdout.buffer.write(base65536.decode(open("blob.txt").read()))
423
+ PY > out.bin
424
+
425
+ file out.bin
426
+ # common outcome: "Zip archive data" or "ELF 64-bit"
427
+ ```
428
+
429
+ **Key insight:** base64 expands 3 bytes → 4 chars; base65536 expands 2 bytes → 1 *Unicode codepoint*, and since a codepoint renders as 1–4 UTF-8 bytes the encoded stream actually *expands* by ~2× on disk — but visually it looks compact, which is the CTF trick. Any wall of Unicode that lacks variance across the Basic Multilingual Plane and is dominated by CJK, Hangul, or Tibetan is a candidate. Also check base1024 (BMP), base2048, base4096, and base32768 for related tricks.
430
+
431
+ **References:** IceCTF 2018 — Rabbit Hole, writeup 11421
@@ -0,0 +1,254 @@
1
+ # CTF Misc - Games, VMs & Constraint Solving (Part 2)
2
+
3
+ ## Table of Contents
4
+ - [Cookie Checkpoint Game Brute-Forcing (BYPASS CTF 2025)](#cookie-checkpoint-game-brute-forcing-bypass-ctf-2025)
5
+ - [Flask Session Cookie Game State Leakage (BYPASS CTF 2025)](#flask-session-cookie-game-state-leakage-bypass-ctf-2025)
6
+ - [WebSocket Game Manipulation + Cryptic Hint Decoding (BYPASS CTF 2025)](#websocket-game-manipulation--cryptic-hint-decoding-bypass-ctf-2025)
7
+ - [Server Time-Only Validation Bypass (BYPASS CTF 2025)](#server-time-only-validation-bypass-bypass-ctf-2025)
8
+ - [De Bruijn Sequence for Substring Coverage (BearCatCTF 2026)](#de-bruijn-sequence-for-substring-coverage-bearcatctf-2026)
9
+ - [Brainfuck Interpreter Instrumentation (BearCatCTF 2026)](#brainfuck-interpreter-instrumentation-bearcatctf-2026)
10
+ - [WASM Linear Memory Manipulation (BearCatCTF 2026)](#wasm-linear-memory-manipulation-bearcatctf-2026)
11
+ - [References](#references)
12
+
13
+ ---
14
+
15
+ ## Cookie Checkpoint Game Brute-Forcing (BYPASS CTF 2025)
16
+
17
+ **Pattern (Signal from the Deck):** Server-side game where selecting tiles increases score. Incorrect choice resets the game. Score tracked via session cookies.
18
+
19
+ **Technique:** Save cookies before each guess, restore on failure to avoid resetting progress.
20
+
21
+ ```python
22
+ import requests
23
+
24
+ URL = "https://target.example.com"
25
+
26
+ def solve():
27
+ s = requests.Session()
28
+ s.post(f"{URL}/api/new")
29
+
30
+ while True:
31
+ data = s.get(f"{URL}/api/signal").json()
32
+ if data.get('done'):
33
+ break
34
+
35
+ checkpoint = s.cookies.get_dict()
36
+
37
+ for tile_id in range(1, 10):
38
+ r = s.post(f"{URL}/api/click", json={'clicked': tile_id})
39
+ res = r.json()
40
+
41
+ if res.get('correct'):
42
+ if res.get('done'):
43
+ print(f"FLAG: {res.get('flag')}")
44
+ return
45
+ break
46
+ else:
47
+ s.cookies.clear()
48
+ s.cookies.update(checkpoint)
49
+ ```
50
+
51
+ **Key insight:** Session cookies act as save states. Preserving and restoring cookies on failure enables deterministic brute-forcing without game reset penalties.
52
+
53
+ ---
54
+
55
+ ## Flask Session Cookie Game State Leakage (BYPASS CTF 2025)
56
+
57
+ **Pattern (Hungry, Not Stupid):** Flask game stores correct answers in signed session cookies. Use `flask-unsign -d` to decode the cookie and reveal server-side game state without playing.
58
+
59
+ ```bash
60
+ # Decode Flask session cookie (no secret needed for reading)
61
+ flask-unsign -d -c '<cookie_value>'
62
+ ```
63
+
64
+ **Example decoded state:**
65
+ ```json
66
+ {
67
+ "all_food_pos": [{"x": 16, "y": 12}, {"x": 16, "y": 28}, {"x": 9, "y": 24}],
68
+ "correct_food_pos": {"x": 16, "y": 28},
69
+ "level": 0
70
+ }
71
+ ```
72
+
73
+ **Key insight:** Flask session cookies are signed but not encrypted by default. `flask-unsign -d` decodes them without the secret key, exposing server-side game state including correct answers.
74
+
75
+ **Detection:** Base64-looking session cookies with periods (`.`) separating segments. Flask uses `itsdangerous` signing format.
76
+
77
+ ---
78
+
79
+ ## WebSocket Game Manipulation + Cryptic Hint Decoding (BYPASS CTF 2025)
80
+
81
+ **Pattern (Maze of the Unseen):** Browser-based maze game with invisible walls. Checkpoints verified server-side via WebSocket. Cryptic hint encodes target coordinates.
82
+
83
+ **Technique:**
84
+ 1. Open browser console, inspect WebSocket messages and `player` object
85
+ 2. Decode cryptic hints (e.g., "mosquito were not available" → MQTT → port 1883)
86
+ 3. Teleport directly to target coordinates via console
87
+
88
+ ```javascript
89
+ function teleport(x, y) {
90
+ player.x = x;
91
+ player.y = y;
92
+ verifyProgress(Math.round(player.x), Math.round(player.y));
93
+ console.log(`Teleported to x:${player.x}, y:${player.y}`);
94
+ }
95
+
96
+ // "mosquito" → MQTT (port 1883), "not available" → 404
97
+ teleport(1883, 404);
98
+ ```
99
+
100
+ **Common cryptic hint mappings:**
101
+ - "mosquito" → MQTT (Mosquitto broker, port 1883)
102
+ - "not found" / "not available" → HTTP 404
103
+ - Port numbers, protocol defaults, or ASCII values as coordinates
104
+
105
+ **Key insight:** Browser-based games expose their state in the JS console. Modify `player.x`/`player.y` or equivalent properties directly, then call the progress verification function.
106
+
107
+ ---
108
+
109
+ ## Server Time-Only Validation Bypass (BYPASS CTF 2025)
110
+
111
+ **Pattern (Level Devil):** Side-scrolling game requiring traversal of a map. Server validates that enough time has elapsed (map_length / speed) but doesn't verify actual movement.
112
+
113
+ ```python
114
+ import requests
115
+ import time
116
+
117
+ TARGET = "https://target.example.com"
118
+
119
+ s = requests.Session()
120
+ r = s.post(f"{TARGET}/api/start")
121
+ session_id = r.json().get('session_id')
122
+
123
+ # Wait for required traversal time (e.g., 4800px / 240px/s = 20s + margin)
124
+ time.sleep(25)
125
+
126
+ s.post(f"{TARGET}/api/collect_flag", json={'session_id': session_id})
127
+ r = s.post(f"{TARGET}/api/win", json={'session_id': session_id})
128
+ print(r.json().get('flag'))
129
+ ```
130
+
131
+ **Key insight:** When servers validate only elapsed time (not player position, inputs, or movement), start a session, sleep for the required duration, then submit the win request. Always check if the game API has start/win endpoints that can be called directly.
132
+
133
+ ---
134
+
135
+ ## De Bruijn Sequence for Substring Coverage (BearCatCTF 2026)
136
+
137
+ **Pattern (Brown's Revenge):** Server generates random n-bit binary code each round. Input must contain the code as a substring. Pass 20+ rounds with a single fixed input under a character limit.
138
+
139
+ ```python
140
+ def de_bruijn(k, n):
141
+ """Generate de Bruijn sequence B(k, n): cyclic sequence containing
142
+ every k-ary string of length n exactly once as a substring."""
143
+ a = [0] * k * n
144
+ sequence = []
145
+ def db(t, p):
146
+ if t > n:
147
+ if n % p == 0:
148
+ sequence.extend(a[1:p+1])
149
+ else:
150
+ a[t] = a[t - p]
151
+ db(t + 1, p)
152
+ for j in range(a[t - p] + 1, k):
153
+ a[t] = j
154
+ db(t + 1, t)
155
+ db(1, 1)
156
+ return sequence
157
+
158
+ # For 12-bit binary codes: B(2, 12) has length 4096
159
+ seq = ''.join(map(str, de_bruijn(2, 12)))
160
+ payload = seq + seq[:11] # Linearize: 4096 + 11 = 4107 chars
161
+ # Every possible 12-bit code appears as a substring
162
+ ```
163
+
164
+ **Key insight:** De Bruijn sequence B(k, n) contains all k^n possible n-length strings over alphabet k as substrings, with cyclic length k^n. To linearize (non-cyclic), append the first n-1 characters. Total length = k^n + n - 1. Send the same string every round — it contains every possible code.
165
+
166
+ **Detection:** Must find arbitrary n-bit pattern as substring of limited-length input. Character budget matches de Bruijn length (k^n + n - 1).
167
+
168
+ ---
169
+
170
+ ## Brainfuck Interpreter Instrumentation (BearCatCTF 2026)
171
+
172
+ **Pattern (Ghost Ship):** Large Brainfuck program (10K+ instructions) validates a flag character-by-character. Full reverse engineering is impractical.
173
+
174
+ **Per-character brute-force via instrumentation:**
175
+ 1. Instrument a Brainfuck interpreter to track tape cell values
176
+ 2. Identify a "wrong count" cell that increments per incorrect character
177
+ 3. For each position, try all printable ASCII — pick the character that doesn't increment the wrong counter
178
+
179
+ ```python
180
+ def run_bf_instrumented(code, input_bytes, max_steps=500000):
181
+ tape = [0] * 30000
182
+ dp, ip, inp_idx = 0, 0, 0
183
+ for _ in range(max_steps):
184
+ if ip >= len(code): break
185
+ c = code[ip]
186
+ if c == '+': tape[dp] = (tape[dp] + 1) % 256
187
+ elif c == '-': tape[dp] = (tape[dp] - 1) % 256
188
+ elif c == '>': dp += 1
189
+ elif c == '<': dp -= 1
190
+ elif c == '.': pass # output
191
+ elif c == ',':
192
+ tape[dp] = input_bytes[inp_idx] if inp_idx < len(input_bytes) else 0
193
+ inp_idx += 1
194
+ elif c == '[' and tape[dp] == 0:
195
+ # skip to matching ]
196
+ ...
197
+ elif c == ']' and tape[dp] != 0:
198
+ # jump back to matching [
199
+ ...
200
+ ip += 1
201
+ return tape
202
+
203
+ # Brute-force: ~40 positions × 95 chars = 3800 runs
204
+ flag = []
205
+ for pos in range(40):
206
+ for c in range(32, 127):
207
+ candidate = flag + [c] + [ord('A')] * (39 - pos)
208
+ tape = run_bf_instrumented(code, candidate)
209
+ if tape[WRONG_COUNT_CELL] == 0: # No errors up to this position
210
+ flag.append(c)
211
+ break
212
+ ```
213
+
214
+ **Key insight:** Brainfuck programs that validate input character-by-character can be brute-forced without understanding the program logic. Instrument the interpreter to observe tape state, find the cell that tracks validation progress, and optimize per-character search. ~3800 runs completes in minutes.
215
+
216
+ ---
217
+
218
+ ## WASM Linear Memory Manipulation (BearCatCTF 2026)
219
+
220
+ **Pattern (Dubious Doubloon):** Browser game compiled to WebAssembly with win conditions requiring luck (e.g., 15 consecutive coin flips). WASM linear memory is flat and unprotected.
221
+
222
+ **Direct memory patching in Node.js:**
223
+ ```javascript
224
+ const { readFileSync } = require('fs');
225
+ const wasmBuffer = readFileSync('game.wasm');
226
+ const { instance } = await WebAssembly.instantiate(wasmBuffer, imports);
227
+ const mem = new DataView(instance.exports.memory.buffer);
228
+
229
+ // Patch game variables at known offsets
230
+ mem.setInt32(0x102918, 14, true); // streak counter = 14 (need 15)
231
+ mem.setInt32(0x102898, 100, true); // win chance = 100%
232
+
233
+ // One more flip → guaranteed win → flag decoded
234
+ const result = instance.exports.flipCoin();
235
+ ```
236
+
237
+ **Key insight:** Unlike WAT patching (modifying the binary), memory manipulation patches runtime state after loading. All WASM variables live in flat linear memory at fixed offsets. Use `wasm-objdump -x game.wasm` or search for known constants to find variable offsets. No need to understand the full game logic — just set the state to "about to win".
238
+
239
+ **Detection:** WASM game requiring statistically impossible sequences (streaks, perfect scores). Game logic is in `.wasm` file loadable in Node.js.
240
+
241
+ ---
242
+
243
+ ## References
244
+ - BYPASS CTF 2025 "Signal from the Deck": Cookie checkpoint game brute-forcing
245
+ - BYPASS CTF 2025 "Hungry, Not Stupid": Flask cookie game state leakage
246
+ - BYPASS CTF 2025 "Maze of the Unseen": WebSocket teleportation + cryptic hints
247
+ - BYPASS CTF 2025 "Level Devil": Server time-only validation bypass
248
+ - BearCatCTF 2026 "Brown's Revenge": De Bruijn sequence substring coverage
249
+ - BearCatCTF 2026 "Ghost Ship": Brainfuck instrumentation brute-force
250
+ - BearCatCTF 2026 "Dubious Doubloon": WASM linear memory state patching
251
+
252
+ ---
253
+
254
+ See also: [games-and-vms.md](games-and-vms.md) for WASM patching, Roblox reversing, PyInstaller, Z3, K8s RBAC, floating-point exploitation, custom assembly sandbox escape, and multi-phase crypto games.