## https://sploitus.com/exploit?id=CDF6EDA8-47D8-5314-B20C-22DEF689703D
# wp2r00t - WordPress REST Batch Route-Confusion SQLi PoC
A self-contained proof-of-concept for the unauthenticated blind SQL injection
reachable through the WordPress REST batch endpoint (`/wp-json/batch/v1`). It is
an independent implementation built from the published vulnerability mechanics -
not a copy of any third-party repository.
---
Author: _J4ck3LSyN_
---
> [!WARNING]
> **This code is provided AS IS for educational and research purposes only.**
> **Do not use this PoC on production systems, shared environments, or any unauthorized targets.**
> - Running or hosting this code may trigger antivirus detections, security monitoring alerts, or legal consequences if misused.
> - The authors and repository maintainers assume **no liability** for any damage, misuse, or illegal activity resulting from this code.
> - Use exclusively in isolated lab environments with proper authorization.
> **Intended for defensive research, vulnerability analysis, and blue-team testing only.**
---
## Affected Versions
| Branch | Affected Versions | Fixed In |
|----------|----------------------------|-------------|
| 6.9.x | 6.9.0 - 6.9.4 | 6.9.5 |
| 7.0.x | 7.0.0 - 7.0.1 | 7.0.2 |
See the official WordPress security releases for details.
---
## 1. Vulnerability Mechanics
The batch endpoint dispatches several sub-requests in one call, validating and
permission-checking each independently. When a sub-request path fails
`wp_parse_url()`, it is appended to the validation array but **not** to the
matched-handler array. The two arrays fall out of step, and a later sub-request
is dispatched under a *different* sub-request's handler. That is the route confusion.
This PoC nests the primitive twice:
1. **Outer desync.** A `POST /wp/v2/posts` request that carries a `requests`
body is dispatched under the batch handler itself. Having been validated as a
posts request, its inner `requests` list is never re-checked against the
batch schema, so the inner sub-requests may use `GET` (method allow-list
bypass).
2. **Inner desync.** Inside that inner batch, a `GET /wp/v2/users` request
carrying `author_exclude=...` is dispatched under `posts get_items()`. The
users collection schema has no `author_exclude` parameter, so the value
passes validation untouched. `posts get_items()` maps `author_exclude` to
the WP_Query `author__not_in` query var, which vulnerable builds interpolate
into SQL as a raw string.
The net sink is a pre-authentication boolean / time-based blind SQL injection:
```
... post_author NOT IN () ...
```
A value of `0) -- -` closes the `IN()` list and appends arbitrary SQL.
---
## 2. Safety Model
The PoC is fail-closed. Three runtime gates prevent accidental or out-of-scope
execution. All are enforced in `modules/exploit.py`; the CLI in `poc.py` only
threads them through.
| Flag | Scope | Effect when absent |
|-------------------|------------------------|---------------------------------------------|
| `--authorized` | All network I/O | `AuthorizationError` before any send |
| `--noop` | All subcommands | Builds/prints payloads; no network contact |
| `--max-requests` | `BatchClient` | Hard request budget |
| `--r00t` | `shell` subcommand | Post-auth RCE capabilities withheld |
- `AuthorizationError` is raised in `BatchClient._ensure_authorized()`, `AdminSession._ensure_authorized()`, and `AdminSession._ensure_r00t()`.
- `BatchClient._count()` enforces `--max-requests` *before* the socket opens.
- `--r00t` is the capability separator: a build shipped without it cannot deploy or execute a webshell.
Credential handling for `shell`: admin username/password resolve from `--user` /
`--password`, or environment variables / a secure file.
---
## 3. Installation
```bash
git clone https://github.com/J4ck3LSyN-Gen2/CVE-2026-63030-wp2r00t.git
cd CVE-2026-63030-wp2r00t
python3 -m py_compile modules/exploit.py poc.py # basic sanity check
```
**Requirements**: Python 3.11+, standard library only (no pip dependencies).
---
## 4. CLI
```
python3 poc.py [flags]
```
**Common flags** (all subcommands):
```
--authorized Assert you own / are authorized to test . Required to send.
--noop Build/validate payloads without sending (no network contact).
--max-requests N Hard cap on requests to the target.
--rest-route Use /?rest_route=/batch/v1 instead of /wp-json/batch/v1.
--timeout FLOAT Request timeout (default 30).
--proxy URL HTTP(S) proxy.
--insecure Disable TLS certificate verification.
```
### Available Commands
- **`check`** - Confirm vulnerability (non-destructive)
- **`read`** - Blind SQL extraction
- **`shell`** - Post-auth webshell helper (requires `--r00t`)
- **`validate`** - Passive identifier
**Quick Reference**
| Goal | Command |
|-----------------------------------|-------|
| Preview probe payloads | `python3 poc.py check --noop` |
| Confirm vulnerability | `python3 poc.py check --authorized` |
| Active timing proof | `... check --authorized --confirm-sqli` |
| Preview SQLi payloads | `python3 poc.py read --noop --query "SELECT @@version"` |
| Extract data | `python3 poc.py read --authorized --query "SELECT @@version"` |
| Preview webshell artifact | `python3 poc.py shell --noop --r00t --cmd "id"` |
| Deploy + execute (authorized) | `python3 poc.py shell --authorized --r00t --user admin --cmd "id"` |
| Passive scan | `python3 poc.py validate --authorized` |
Full command documentation is available in the original detailed sections (or run `python3 poc.py --help`).
---
## 5. Architecture & OPSEC
(Keep the original architecture, modules, and OPSEC sections here - they were already strong.)
The post-exploitation modules and `r00t.py` implant chain are intentionally excluded from shared builds.
## 6. License
This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for details.
**Disclaimer**: Use only on systems you own or are explicitly authorized to test. The authors assume no liability for any misuse.