Sploitus

Exploit for Interpretation Conflict in Wordpress

githubexploit Β· 2026-08-20

Exploit Code

README288 lines
## https://sploitus.com/exploit?id=C65E8753-E53D-588C-9EB7-3F4C50AF9469
# CVE-2026-63030 β€” wp2shell Lab

> **Pre-Authentication RCE in WordPress Core via REST API Batch Route Confusion + SQL Injection**

[![WordPress](https://img.shields.io/badge/WordPress-6.9.0–7.0.1-red?logo=wordpress)](https://wordpress.org)
[![CVE](https://img.shields.io/badge/CVE-2026--63030-critical)](https://nvd.nist.gov/vuln/detail/CVE-2026-63030)
[![CVSS](https://img.shields.io/badge/CVSS-9.8_Critical-red)](https://nvd.nist.gov)
[![License](https://img.shields.io/badge/License-MIT-blue)](LICENSE)
---

## Overview

**wp2shell** is a chain of two independently low-severity bugs in WordPress core that, when combined, allow an unauthenticated remote attacker to:

1. Reach an SQL injection sink with no credentials
2. Extract the admin password hash from the database
3. Create a new administrator account
4. Upload a webshell and achieve full Remote Code Execution

| Property | Detail |
|----------|--------|
| **CVEs** | CVE-2026-63030 + CVE-2026-60137 |
| **CVSS** | 9.8 Critical |
| **Auth required** | None (pre-authentication) |
| **Attack vector** | Network |
| **Affected versions** | WordPress 6.9.0–6.9.4 and 7.0.0–7.0.1 |
| **Patched versions** | 6.9.5 and 7.0.2 (released July 17, 2026) |

---

## The Two Bugs

### CVE-2026-63030 β€” REST API Batch Route Confusion
**File:** `wp-includes/rest-api/class-wp-rest-server.php`

`serve_batch_request_v1()` maintains two parallel arrays: `$matches[]` for handlers and `$validation[]` for results. When a sub-request fails with a `WP_Error` (broken path), it is pushed into `$validation[]` but **not** into `$matches[]`. This creates a +1 index shift β€” sub-request `i` gets dispatched with the handler for sub-request `i+1`.

```php
// VULNERABLE (7.0.1)
if ( is_wp_error( $route ) ) {
    $responses[] = envelope();
    continue; // $matches[] NOT pushed ← BUG
}

// PATCHED (7.0.2)
if ( is_wp_error( $route ) ) {
    $matches[]   = null; // ← FIX: keeps arrays in sync
    $responses[] = envelope();
    continue;
}
```

### CVE-2026-60137 β€” SQL Injection in WP_Query
**File:** `wp-includes/class-wp-query.php`

The `author__not_in` parameter expects an array of integers. When passed a string, `implode()` concatenates the raw value directly into the SQL `WHERE` clause β€” no escaping, no parameterization.

```php
// VULNERABLE (7.0.1)
$where .= ' NOT IN (' . implode(',', $q['author__not_in']) . ')';

// PATCHED (7.0.2)
$safe   = implode(',', array_map('absint', (array) $q['author__not_in']));
$where .= " NOT IN ($safe)";
```

---

## Attack Chain

```
Unauthenticated Attacker
        β”‚
        β–Ό
POST /?rest_route=/batch/v1          ← Outer batch
  sub-req 0: "///"   β†’ WP_Error β†’ index shift (+1)
  sub-req 1: POST /wp/v2/posts       ← dispatched under BATCH handler
  sub-req 2: POST /batch/v1          ← dummy
        β”‚
        β”‚  [Confusion #1 active]
        β–Ό
Inner batch (body of sub-req 1)      ← schema never validated
  inner 0: "///"    β†’ index shift (+1)
  inner 1: GET /wp/v2/posts?author_exclude=
           dispatched under posts get_items()
        β”‚
        β”‚  [Confusion #2 active]
        β–Ό
WP_Query: author__not_in = raw string
        β”‚
        β–Ό
SQL: NOT IN (0) UNION SELECT 999999,...,HEX(user_pass),...
        β”‚
        β–Ό
title.rendered = "||1|admin|$wp$2y$10$......||"
        β”‚
        β–Ό
Crack hash  OR  crack-free oEmbed technique
        β”‚
        β–Ό
POST /wp/v2/users β†’ new admin β†’ plugin upload β†’ webshell β†’ RCE
```

---

## Lab Setup

### Prerequisites

| Tool | Download |
|------|----------|
| **Docker Desktop** (Windows / macOS) | https://www.docker.com/products/docker-desktop |
| **Docker Engine** (Linux) | https://docs.docker.com/engine/install |
| **Git** | https://git-scm.com/downloads |
| **Burp Suite Community** (optional) | https://portswigger.net/burp/communitydownload |

---

### Step 1 β€” Clone the repository

```bash
git clone https://github.com/YOUR_USERNAME/cve-2026-63030-lab
cd cve-2026-63030-lab
```

You will see these files:

```
cve-2026-63030-lab/
β”œβ”€β”€ docker-compose.yml     ← defines WordPress + MySQL containers
β”œβ”€β”€ Dockerfile             ← custom image with Apache fix + wp-cli
β”œβ”€β”€ init.sh                ← configures permalink after install
└── fix-htaccess.ps1       ← Windows helper (run if Apache returns 404)
```

---

### Step 2 β€” Build and start the lab

```bash
docker compose up -d --build
```

This will:
- Build the custom WordPress 7.0.1 image (takes ~1–2 min on first run)
- Start a MySQL 8.0 database container
- Expose WordPress on **http://localhost:9090**

Verify both containers are running:

```bash
docker compose ps
```

Expected output:
```
NAME              STATUS
wp2shell-lab      running
wp2shell-db       running
```

---

### Step 3 β€” Complete WordPress installation

Open **http://localhost:9090** in your browser and fill in:

| Field | Suggested value |
|-------|----------------|
| Site Title | `CVE-2026-63030` |
| Username | `admin` |
| Password | any password |
| Email | `admin@lab.local` |

Click **Install WordPress**, then log in.

---

### Step 4 β€” Enable REST API routing (required)

Run this once after installation:

**Linux / macOS:**
```bash
docker exec wp2shell-lab bash -c "
  wp rewrite structure '/%postname%/' --allow-root --path=/var/www/html &&
  wp rewrite flush --allow-root --path=/var/www/html
"
```

**Windows PowerShell:**
```powershell
docker exec wp2shell-lab bash -c "wp rewrite structure '/%postname%/' --allow-root --path=/var/www/html && wp rewrite flush --allow-root --path=/var/www/html"
```

Expected output:
```
Success: Rewrite structure set.
Success: Rewrite rules flushed.
```

---

### Step 5 β€” Fix .htaccess (Windows only, if you get 404 on REST API)

```powershell
.\fix-htaccess.ps1
```

---

### Step 6 β€” Verify the lab is ready

```bash
curl -s http://localhost:9090/wp-json/ | python3 -m json.tool | head -5
```

If you see a JSON response with `"namespaces"` β€” the lab is ready.

---

### Teardown

```bash
# Stop and remove everything including database
docker compose down -v
```

---

## Exploitation (PoC)

> ⚠️ **For authorized security research and education only.**
> Only use against systems you own or have explicit written permission to test.

The full exploitation chain (detection β†’ SQLi β†’ admin creation β†’ webshell β†’ RCE) is implemented in:

**[github.com/Icex0/wp2shell-poc](https://github.com/Icex0/wp2shell-poc)**

```bash
git clone https://github.com/Icex0/wp2shell-poc
cd wp2shell-poc
pip install -r requirements.txt

# Step 1: Detection only (non-destructive)
python wp2shell.py check http://localhost:9090

# Step 2: Read database β€” extract users and hashes
python wp2shell.py read --preset users http://localhost:9090
```

---

## The Patch

Three files, fewer than 10 lines of PHP:

| File | Change |
|------|--------|
| `class-wp-rest-server.php` | `$matches[] = null` placeholder to keep arrays in sync |
| `class-wp-query.php` | `(array)` cast + `array_map('absint', ...)` |
| `class-wp-rest-posts-controller.php` | Same sanitization at the REST layer |

Update to **WordPress 6.9.5** or **7.0.2** to remediate.

---

## References

| Resource | Link |
|----------|------|
| GitHub Advisory (CVE-2026-63030) | `GHSA-ff9f-jf42-662q` |
| GitHub Advisory (CVE-2026-60137) | `GHSA-fpp7-x2x2-2mjf` |
| Public PoC | https://github.com/Icex0/wp2shell-poc |

---



Made with ❀️ by **[Black Security Team](https://blacksecurityteam.com/)**

[![Website](https://img.shields.io/badge/Website-blacksecurityteam.com-black?logo=google-chrome&logoColor=white)](https://blacksecurityteam.com/)
[![Telegram](https://img.shields.io/badge/Telegram-Black__Security-2CA5E0?logo=telegram&logoColor=white)](https://t.me/Black_Security)
[![LinkedIn](https://img.shields.io/badge/LinkedIn-Black_Security_Team-0A66C2?logo=linkedin&logoColor=white)](https://www.linkedin.com/company/black-security-team/)

> This repository is for **educational purposes and authorized security research only.**
> Do not test against systems you do not own or have explicit written permission to test.