
# Lab Docker pour reproduire la CVE-2026-27541, une élévation de privilèges authentifiée dans WooCommerce Wholesale Prices. Compare les versions vulnérable et corrigée, inclut un script PoC et une analyse de la cause racine.

Ce projet est un laboratoire Docker local permettant d'analyser et de reproduire le comportement de CVE-2026-27541 dans le plugin WooCommerce Wholesale Prices / Wholesale Suite en comparant les versions vulnérable et corrigée côte à côte sur la même machine.
Le problème principal est un Contrôle d'accès cassé dans le point de terminaison d'API REST suivant :
/wp-json/wwp/v1/admin/save
D'après le code source utilisé dans ce laboratoire, cette route possède déjà un permission_callback dans les versions vulnérable et corrigée. Cependant, la version affectée utilise un contrôle de capacité trop large pour une action d'écriture des paramètres administrateur :
2.2.6) → current_user_can( 'manage_woocommerce' )2.2.7) → current_user_can( 'manage_options' )Dans ce laboratoire, l'utilisateur shopmgr, qui possède le rôle shop_manager, a manage_woocommerce=true mais pas manage_options. Par conséquent, cet utilisateur à faibles privilèges peut utiliser une session connectée valide ainsi qu'un X-WP-Nonce valide pour invoquer le point de terminaison d'enregistrement des paramètres administrateur sur la version vulnérable, tandis que la version corrigée renvoie 403 rest_forbidden pour la même requête.
2.2.6) : l'utilisateur shopmgr peut appeler avec succès POST /wp-json/wwp/v1/admin/save et modifier les paramètres du plugin.2.2.7) : la même requête de shopmgr est rejetée avec 403.403, ce qui est cohérent avec un problème d'élévation de privilèges post-authentification.wwp_see_wholesale_prices_replacement_text=PWNED_BY_POC, tandis que la version corrigée renvoie toujours See wholesale prices.vuln → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.6patched → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.7db-vuln / db-patched → bases de données MariaDB distinctesseed-vuln / seed-patched → tâches d'initialisation wp-cli qui installent WordPress, installent le plugin, créent les utilisateurs et créent un produit pour les testshttp://localhost:8081 → vulnérablehttp://localhost:8082 → corrigéwordpress:6.8.1-php8.2-apachemariadb:11.4.5wordpress:cli-php8.2.
├── docker-compose.yml
├── README.md
├── patched/
│ └── Dockerfile
├── vuln/
│ └── Dockerfile
├── scripts/
│ └── seed-wp.sh
└── poc.py
docker-compose.yml — définit les piles vulnérable et corrigée avec des bases de données distinctesscripts/seed-wp.sh — installe WordPress, WooCommerce, le plugin cible, et crée les utilisateurs de test et les données produitpoc.py — PoC à impact minimal pour la connexion, l'extraction du nonce et l'invocation du point de terminaison RESTUne fois la pile prête, le script d'initialisation crée les éléments suivants :
admin / AdminPass!234shopmgr / ShopMgrPass!234lab-product10050WooCommerce : 10.6.0
WooCommerce Wholesale Prices :
2.2.62.2.7Le script écrit également lab-secrets.json dans chaque conteneur WordPress afin que les données initialisées et les informations de version puissent être vérifiées.
Ce PoC ne tente pas de prendre le contrôle du site, de modifier les rôles, d'installer des plugins ou d'exécuter un shell.
Il fait uniquement ce qui suit :
shopmgrwpApiSettings.noncewwp_see_wholesale_prices_replacement_text = PWNED_BY_POC
Ce paramètre est utilisé comme marqueur observable pour démontrer qu'un utilisateur à faibles privilèges peut modifier une configuration réservée à l'administrateur.
POST /wp-json/wwp/v1/admin/saveBien que le point de terminaison exige une session et un nonce valides, la version vulnérable permet toujours à un utilisateur à faibles privilèges tel que shopmgr avec le rôle shop_manager d'invoquer un point de terminaison qui devrait être réservé à l'administrateur.
Il ne s'agit pas d'une vulnérabilité non authentifiée.
Si le point de terminaison est appelé directement sans session connectée, les versions vulnérable et corrigée rejettent toutes deux la requête. Le bug réside dans l'autorisation après authentification, pas dans l'authentification elle-même.
La version vulnérable ne manque pas de permission_callback. Le défaut est qu'elle utilise un contrôle de capacité trop large (manage_woocommerce) pour une action REST qui écrit des paramètres côté administrateur.
D'après le code source dans includes/class-wwp-admin-settings.php :
POST /wp-json/wwp/v1/admin/savesave_registered_settings()permission_admin_check() comme permission_callback2.2.6)if ( ! current_user_can( 'manage_woocommerce' ) ) {
return new WP_Error( 'rest_forbidden', ... );
}
2.2.7)if ( ! current_user_can( 'manage_options' ) ) {
return new WP_Error( 'rest_forbidden', ... );
}
Dans ce laboratoire, l'utilisateur shopmgr, qui possède le rôle shop_manager, a manage_woocommerce=true mais pas manage_options, il réussit donc le contrôle vulnérable mais échoue au contrôle corrigé.
La version corrigée fait plus que changer la réponse de 200 à 403. Elle modifie la logique de contrôle d'accès en resserrant l'exigence de capacité de manage_woocommerce à manage_options.
De plus, le chemin d'enregistrement dans la version corrigée est davantage renforcé en passant d'un filtrage basé sur les préfixes à des listes blanches explicites et une sanitisation plus forte.
Le PoC suit le même flux qu'un contexte de navigateur réel :
shopmgrwpApiSettings.noncePOST /wp-json/wwp/v1/admin/saveÉtant donné que la version vulnérable permet aux utilisateurs disposant de manage_woocommerce d'invoquer cette action d'écriture des paramètres, la requête réussit et entraîne une modification persistante d'option.
Un nonce aide à protéger contre le CSRF, mais ce n'est pas un contrôle d'autorisation.