
Rilevatore non distruttivo per CVE-2026-64638 (XSS2Shell) — primitiva di riflessione XSS pre-autenticazione di WordPress
Rilevatore non distruttivo e senza dipendenze per la primitiva di riflessione CVE-2026-64638 ("XSS2Shell") in WordPress wp-login.php.
CVE-2026-64638 è una XSS riflessa pre-autenticazione nel core di WordPress, divulgata da PWN.AI il 2026-08-07 (CVSS 8.9, CWE-79) e corretta nella 7.0.3 con backport a tutti i rami mantenuti (6.9.6, 6.8.7, 6.7.6, 6.6.6, 6.5.9, …).
La causa principale è una differenza di parsing tra strip_tags() di PHP e il sanitizzatore KSES di WordPress:
strip_tags() rifiuta di riconoscere un tag quando uno spazio segue <, quindi un nome utente come < area id=x> sopravvive come testo semplice.<area id="x"> attivo all'interno del messaggio di errore di login.Questo produce un'iniezione DOM arbitraria con attributi id/class/href scelti dall'attaccante — la primitiva alla base della catena multi-stadio pubblicata (DOM clobbering → REST JSONP → furto delle Application Password → upload di plugin → RCE contro una vittima admin con sessione attiva).
Due sonde non distruttive (un login fallito con un nome utente marker casuale):
<b>marker</b> appare non escapato nella risposta di errore.< area id=marker> sopravvive a strip_tags() e riappare come elemento attivo/normalizzato (es. area id="marker") nella risposta.Nessun payload esegue nulla; lo strumento verifica soltanto se l'HTML dell'attaccante viene renderizzato come DOM attivo. Extra opzionali:
--version — fingerprint della versione del core tramite il tag <generator> del feed.--jsonp — verifica che l'envelope JSONP REST (_jsonp/_envelope) usato dalla catena pubblicata sia raggiungibile.python3 xss2shell_check.py https://example.com
python3 xss2shell_check.py --jsonp --verbose https://example.com
python3 xss2shell_check.py --version https://example.com
python3 xss2shell_check.py --json https://example.com
Python 3.6+, solo stdlib. Nessuna dipendenza.
| Codice | Significato |
|---|---|
| 0 | VULNERABILE (primitiva di riflessione presente) |
| 1 | CORRETTO / NON VULNERABILE |
| 2 | ERRORE (irraggiungibile, sfida WAF, risposta inattesa) |
<area id="…">). Il quoting degli attributi varia in base alla generazione di KSES (vecchio parser personalizzato: <area id=x>; DOMDocument: <area id="x"> / <area id="x" />), pertanto vengono riconosciute tutte le forme. Un passaggio grezzo di < area …> senza ri-analisi è testo inerte nel browser, non la primitiva — viene segnalato come RAW_TEXT_ONLY e non genera un falso positivo.login_errors personalizzato o una CDN/WAF riscrive le risposte, o se l'errore di login non riflette mai il nome utente.Solo test di sicurezza autorizzati. Questo strumento è destinato esclusivamente al test di sistemi di tua proprietà o per i quali disponi di esplicita autorizzazione scritta. I test non autorizzati sono illegali nella maggior parte delle giurisdizioni.
| Flag | Scopo |
|---|
--version | fingerprint della versione del core (tag generator del feed, fallback meta della homepage) |
--jsonp | verifica anche che l'envelope JSONP REST (_jsonp/_envelope) sia raggiungibile |
-v, --verbose | stampa estratti delle risposte delle sonde (prove per i report) |
--json | risultato JSON leggibile da una macchina (CI / automazione) |
| Comportamento osservato | Verdetto | Exit |
|---|
<b>marker</b> riflesso non escapato | RAW_HTML — vulnerabile | 0 |
< area id=marker> ri-analizzato in un <area id="marker"> attivo (qualsiasi quoting / forma void) | AREA_BYPASS — vulnerabile | 0 |
| Nome utente escapato in HTML | ESCAPED — non vulnerabile | 1 |
| Tag rimossi, il testo rimane | STRIPPED — non vulnerabile | 1 |
< area …> grezzo passa ma non viene mai ri-analizzato | RAW_TEXT_ONLY — testo inerte, non vulnerabile | 1 |
| Nessun echo | NOT_REFLECTED — non vulnerabile | 1 |
| Sonda bloccata (HTTP ≥ 400 / pagina di sfida) o target irraggiungibile | ERROR | 2 |