Share
## https://sploitus.com/exploit?id=6B95C4C5-B5D0-5404-88E3-2391E2EB114A
# wp2shell_scanner

[![smoke](https://github.com/zi3lak/wp2shell_scanner/actions/workflows/smoke.yml/badge.svg)](https://github.com/zi3lak/wp2shell_scanner/actions/workflows/smoke.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
[![Python 3.7+](https://img.shields.io/badge/python-3.7%2B-blue.svg)](https://www.python.org/)
[![Mode: detection-only](https://img.shields.io/badge/mode-detection--only-brightgreen.svg)](#what-it-explicitly-does-not-do)
[![CVE-2026-63030 ยท CVE-2026-60137](https://img.shields.io/badge/CVE-2026--63030%20%C2%B7%202026--60137-C81E3A.svg)](https://github.com/advisories/GHSA-ff9f-jf42-662q)

**Non-intrusive detection scanner for the WordPress `wp2shell` pre-authentication RCE chain.**

`wp2shell_scanner.py` fingerprints a WordPress site's core version and reads its
publicly advertised REST API surface to decide whether the host is exposed to the
**wp2shell** chain โ€” **CVE-2026-63030 + CVE-2026-60137**. It **detects only**: no
exploit payload is ever sent. Single file, one dependency (`requests`), CI-friendly
exit codes, and client-ready HTML / JSON / e-mail reports.

> โš ๏ธ **Authorised use only.** Scan systems you own or are explicitly authorised (in
> writing) to test. The scanner sends an identifying `User-Agent` so blue teams can
> attribute the traffic โ€” it does not hide.

---

## The vulnerability

`wp2shell` is a chain of two WordPress **core** flaws that together yield
**unauthenticated remote code execution**:

| CVE | Weakness | Component | Role in the chain |
|-----|----------|-----------|-------------------|
| **CVE-2026-63030** | CWE-436 โ€” REST batch route confusion (Critical, CVSS 7.5, `GHSA-ff9f-jf42-662q`) | `WP_REST_Server::serve_batch_request_v1()` ยท `/wp-json/batch/v1` | **Entry point.** A route-confusion flaw lets an unauthenticated request reach an internal query path. |
| **CVE-2026-60137** | CWE-89 โ€” SQL injection | `WP_Query` โ€” `author__not_in` parameter | **Second link.** Unsanitised input reaches the database query; chained with the above โ†’ unauth RCE. |

| | |
|---|---|
| **Affected** | WordPress `6.9.0`โ€“`6.9.4` and `7.0.0`โ€“`7.0.1` |
| **Fixed in** | WordPress `6.9.5` and `7.0.2` |
| **First affected** | `6.9.0` (the batch-route weakness was introduced in 6.9) |

**Operationally important:** technical write-ups and a working PoC are already public.
Version detection is now the *absolute minimum* โ€” the priority is **patching**. And
note that updating closes the vulnerable path but **does not remove a backdoor planted
before the patch** โ€” hence the compromise-assessment step in the report.

---

## What the scanner does

- **Passive version fingerprint** via several independent vectors:
  - `` on the homepage
  - `/readme.html`
  - RSS / Atom feed `` tag
  - `/wp-links-opml.php` (OPML)
  - REST root `/wp-json/`
- **Passive REST-surface read** of `/wp-json/` to check whether the `batch/v1`
  namespace is registered (i.e. the vulnerable endpoint is reachable). **No batch
  request and no payload are sent** โ€” it only reads the advertised route list.
- **Verdict mapping** โ€” the detected version is compared against the affected/fixed
  ranges to produce a per-CVE verdict, plus:
  - a **client-ready HTML report** (print โ†’ PDF),
  - a **JSON record** (pipeline/EAV-friendly),
  - a **draft notification e-mail**.

### What it explicitly does **not** do

It does **not** exploit anything. No SQL-injection payload, no batch-route-confusion
request, no attempt to execute code or read data. Detection is version-based plus a
passive read of the publicly advertised API surface.

---

## Install

```bash
pip install requests
```

## Usage

```bash
# single target
python3 wp2shell_scanner.py -t https://site.example --authorized

# list of targets (one per line, # comments allowed)
python3 wp2shell_scanner.py -T scope.txt --authorized -o ./reports

# preview the output formats with synthetic data โ€” no network, no auth needed
python3 wp2shell_scanner.py --demo -o ./reports
```

### Flags

| Flag | Meaning |
|------|---------|
| `-t, --target` | Single target URL or host |
| `-T, --targets-file` | File with one target per line |
| `--demo` | Generate a **SAMPLE** report/e-mail from synthetic data (no network) |
| `-o, --output-dir` | Output directory (default `./wp2shell_reports`) |
| `--formats` | Comma list: `json,html,email` (default: all) |
| `--authorized` | **Authorisation gate** โ€” required for live scans |
| `--timeout` | HTTP timeout in seconds (default 12) |
| `--delay` | Seconds between targets (be polite; default 1.0) |
| `--insecure` | Do not verify TLS certificates |
| `--quiet` | Suppress the console summary |

The `--authorized` flag is an explicit authorisation gate โ€” live scans refuse to run
without it.

### Exit codes (CI-friendly)

| Code | Meaning |
|------|---------|
| `2` | At least one target **vulnerable** |
| `1` | At least one target **inconclusive** / error |
| `0` | Clean (patched / not affected / not WordPress) |

### Configuration

The notification e-mail recipient is the `CSSLTD_CONTACT` constant near the top of the
script (default `soc@cyberssl.co.uk`). Edit it to your own intake address.

---

## Verdicts

| Verdict | Meaning |
|---------|---------|
| `VULNERABLE` | Detected version falls inside an affected range โ€” patch immediately |
| `PATCHED` | On a fixed release; not exposed to this chain |
| `NOT_AFFECTED` | Version predates the flaw ( These are generated from fabricated data to illustrate the report format. They are
> **not** the result of scanning any real site.

---

## Remediation (as emitted in the report)

1. Take a verified backup (DB + full file tree) first.
2. Update WordPress core to **6.9.5 / 7.0.2** or later on the matching branch.
3. Confirm the site and admin still work.
4. **Assume compromise** if the host was exposed while vulnerable โ€” run a compromise
   assessment across themes, plugins, `uploads/`, `wp-config.php`, wp-cron, and admin
   accounts; run file-integrity checks against known-good core.
5. Add defence-in-depth at the edge (WAF rules, restrict `/wp-json/batch/v1`).
6. Rotate secrets (auth salts, admin/DB passwords, API keys) if compromise is suspected.
7. Re-scan to confirm the verdict now reads **Patched**.

---

## References

- [WordPress GitHub Security Advisory โ€” GHSA-ff9f-jf42-662q](https://github.com/advisories/GHSA-ff9f-jf42-662q)
- [WordPress releases (6.9.5 / 7.0.2)](https://wordpress.org/download/releases/)

---

## Disclaimer

This tool is for **authorised security testing** only. You are responsible for
ensuring you have permission to scan any target. Unauthorised scanning may be unlawful.
The authors accept no liability for misuse.