Share
## https://sploitus.com/exploit?id=D6F23CC9-BAAE-5294-B251-745FCD61488F
# wp2shell-poc

Independent proof-of-concept for the unauthenticated WordPress REST batch route-confusion
SQL injection associated with Searchlight Cyber's wp2shell advisory.

The unauthenticated primitive reaches the injection through a single endpoint:
`POST /wp-json/batch/v1`.

This repository is not Searchlight Cyber's official checker and does not claim to reproduce
undisclosed wp2shell internals. `check` confirms the SQLi path, `read` demonstrates database
read, and `shell` is an optional post-authentication helper that requires valid administrator
credentials before uploading a plugin webshell.

## Affected versions

Searchlight Cyber's advisory lists these wp2shell RCE exposure ranges:

| Version range | Status |
| ------------- | ------ |
|   [options]
```

Or `pip install .` to get a `wp2shell` command on your `PATH`.

### check โ€” confirm the vulnerability (safe)

Prints passive WordPress markers and public version hints first, then sends a benign batch marker
probe. A vulnerable batch implementation returns HTTP 207 with the route-confusion marker pattern
`parse_path_failed`, `block_cannot_read`, and `rest_batch_not_allowed`.

The marker probe is based on the WordPress core fix. The malformed `///` request creates
`parse_path_failed`; a `/wp/v2/posts` request acts as a batch-allowed spacer; the
`/wp/v2/block-renderer/...` route is not batch-allowed but returns `block_cannot_read` if its
handler is reached anonymously; `/batch/v1` gives `rest_batch_not_allowed`. On vulnerable builds
the parse error shifts the batch handler arrays out of step, so the spacer request is dispatched
under the block-renderer handler. Fixed builds keep the arrays aligned, so this exact all-three
pattern should not appear for the crafted probe.

By default, `check` stops there and does not send a SQL timing payload. Use `--confirm-sqli` when
you also want the active paired timing confirmation. The timing step reads no data and changes
nothing; it sends three baseline/delayed pairs by default and decides on the median delta.

Treat the signals separately: an affected public version is strong triage evidence, the batch
marker pattern confirms the vulnerable route-confusion behavior, and timing confirmation proves the
SQLi path reached the database. A WAF or edge rule can block the timing payload, so a failed timing
check does not override a positive marker probe.

```
./wp2shell.py check http://target
```

### read โ€” extract data (blind SQL injection)

```
./wp2shell.py read http://target                      # server fingerprint
./wp2shell.py read http://target --preset users       # user logins and password hashes
./wp2shell.py read http://target --query "SELECT @@version"
```

### shell โ€” post-auth plugin webshell helper

Optional post-exploitation helper. This is not a pre-authentication RCE step: it requires valid
administrator credentials. If `read --preset users` recovers a password hash, supply the recovered
plaintext here after offline cracking.

```
./wp2shell.py shell http://target --user admin --password '' --cmd id
./wp2shell.py shell http://target --user admin --password '' -i   # interactive shell
```

`shell` uploads a plugin webshell (locked behind a random path and a per-run token) and prints its
path. Remove it when finished.

## Options

| Option              | Applies to | Description                                                           |
| ------------------- | ---------- | -------------------------------------------------------------------- |
| `--rest-route`      | all        | Use `/?rest_route=/batch/v1` (for sites without pretty permalinks).  |
| `--proxy URL`       | all        | Route traffic through an HTTP proxy (for example, Burp).             |
| `--timeout N`       | all        | Request timeout in seconds.                                          |
| `--sleep N`         | check      | Delay used with `--confirm-sqli`.                                    |
| `--samples N`       | check      | Timing pairs used with `--confirm-sqli` (default 3).                 |
| `--confirm-sqli`    | check      | Also send the active SQL timing confirmation payload.                |
| `--preset`          | read       | `fingerprint` or `users`.                                            |
| `--query`           | read       | A scalar SQL expression to read.                                     |
| `--prefix`          | read       | Database table prefix (default `wp_`).                               |
| `--max-length N`    | read       | Maximum characters read per value (default 128).                     |
| `--user` / `--password` | shell  | Admin credentials (plaintext, recovered from the hash).             |
| `--cmd`             | shell      | Command to run (omit when using `-i`).                               |
| `-i` / `--interactive` | shell   | Open an interactive shell after deploying.                           |

## Remediation

Update to WordPress 7.0.2, or 6.9.5 if the site is on the 6.9 branch. Until then,
block both `/wp-json/batch/v1` and the `rest_route=/batch/v1` query parameter at
the edge, or require authentication for the batch endpoint via the
`rest_pre_dispatch` filter.

## Legal

For authorized security testing only. Use it exclusively against systems you own or have explicit
written permission to test. No warranty is provided and no liability is accepted for misuse.

## References

- WordPress 7.0.2 release announcement โ€” 
- Searchlight Cyber wp2shell advisory โ€”