wp2shell-poc
Independent proof-of-concept for the unauthenticated WordPress REST batch route-confusion
SQL injection associated with Searchlight Cyber's wp2shell advisory.
This repository is not Searchlight Cyber's official checker. check confirms the SQLi path,
read demonstrates database read, and shell opens a plugin-backed command shell either with
supplied administrator credentials or by first exercising the SQLi-to-admin bridge.
Detection / IoCs: Elastic Security Labs and Eye Security published detection guidance and indicators for this chain. See the Elastic write-up and the Eye Security defenders guide.
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 — non-destructive vulnerability check
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 an SQLi payload. Use `--confirm-sqli` when you
also want an active SQLi confirmation. The confirmation tries the UNION read primitive first and
falls back to paired timing probes if UNION reflection is unavailable.
The signals are independent: a version hint is only a hint, the marker pattern shows route
confusion, and `--confirm-sqli` shows a payload reached the database. A WAF can block the payload,
so a failed