# Docker-лаборатория для воспроизведения CVE-2026-27541 — аутентифицированное повышение привилегий в WooCommerce Wholesale Prices Сравнивает уязвимые и исправленные сборки, включает PoC-скрипт и анализ первопричины.

Этот проект представляет собой локальный Docker-стенд для анализа и воспроизведения поведения CVE-2026-27541 в плагине WooCommerce Wholesale Prices / Wholesale Suite путём сравнения уязвимой и исправленной сборок бок о бок на одной машине.
Суть проблемы — нарушенный контроль доступа в следующей конечной точке REST API:
/wp-json/wwp/v1/admin/save
Судя по исходному коду, используемому в этом стенде, этот маршрут уже имеет permission_callback как в уязвимой, так и в исправленной сборках. Однако в затронутой версии используется проверка прав, слишком широкая для операции записи настроек администратора:
2.2.6) → current_user_can( 'manage_woocommerce' )2.2.7) → current_user_can( 'manage_options' )В этом стенде пользователь shopmgr с ролью shop_manager имеет manage_woocommerce=true, но не manage_options. В результате этот пользователь с низкими привилегиями может использовать действительную сессию входа плюс действительный X-WP-Nonce для вызова конечной точки сохранения настроек администратора в уязвимой сборке, тогда как исправленная сборка возвращает 403 rest_forbidden для того же запроса.
2.2.6): пользователь shopmgr может успешно вызвать POST /wp-json/wwp/v1/admin/save и изменить настройки плагина.2.2.7): тот же запрос от shopmgr отклоняется с кодом 403.403, что согласуется с тем, что это проблема повышения привилегий после аутентификации.wwp_see_wholesale_prices_replacement_text=PWNED_BY_POC, тогда как исправленная сборка по-прежнему возвращает See wholesale prices.vuln → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.6patched → WordPress + WooCommerce + WooCommerce Wholesale Prices 2.2.7db-vuln / db-patched → отдельные базы данных MariaDBseed-vuln / seed-patched → задания инициализации wp-cli, которые устанавливают WordPress, устанавливают плагин, создают пользователей и создают товар для тестированияhttp://localhost:8081 → уязвимыйhttp://localhost:8082 → исправленный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 — определяет уязвимый и исправленный стеки с отдельными базами данныхscripts/seed-wp.sh — устанавливает WordPress, WooCommerce, целевой плагин и создаёт тестовых пользователей и данные товараpoc.py — PoC с минимальным вредом для входа, извлечения nonce и вызова конечной точки RESTПосле готовности стека скрипт инициализации создаёт следующее:
admin / AdminPass!234shopmgr / ShopMgrPass!234lab-product10050WooCommerce: 10.6.0
WooCommerce Wholesale Prices:
2.2.62.2.7Скрипт также записывает lab-secrets.json в каждый контейнер WordPress, чтобы можно было проверить инициализированные данные и информацию о версиях.
Этот PoC не пытается захватить сайт, изменить роли, установить плагины или выполнить shell.
Он делает только следующее:
shopmgrwpApiSettings.noncewwp_see_wholesale_prices_replacement_text = PWNED_BY_POC
Эта настройка используется как наблюдаемый маркер для демонстрации того, что пользователь с низкими привилегиями может изменять конфигурацию, доступную только администратору.
POST /wp-json/wwp/v1/admin/saveХотя конечная точка требует действительную сессию и nonce, уязвимая версия всё равно позволяет пользователю с низкими привилегиями, такому как shopmgr с ролью shop_manager, вызывать конечную точку, которая должна быть доступна только администратору.
Это не уязвимость без аутентификации.
Если конечная точка вызывается напрямую без сессии входа, и уязвимая, и исправленная сборки отклоняют запрос. Ошибка заключается в авторизации после аутентификации, а не в самой аутентификации.
В уязвимой версии отсутствует не permission_callback. Недостаток в том, что она использует слишком широкую проверку прав (manage_woocommerce) для REST-действия, которое записывает настройки на стороне администратора.
Из исходного кода в includes/class-wwp-admin-settings.php:
POST /wp-json/wwp/v1/admin/savesave_registered_settings()permission_admin_check() в качестве 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', ... );
}
В этом стенде пользователь shopmgr с ролью shop_manager имеет manage_woocommerce=true, но не manage_options, поэтому он проходит уязвимую проверку, но не проходит исправленную.
Исправленная версия делает больше, чем просто меняет ответ с 200 на 403. Она меняет логику контроля доступа, ужесточая требование к правам с manage_woocommerce до manage_options.
Кроме того, путь сохранения в исправленной сборке дополнительно укреплён за счёт перехода от фильтрации на основе префиксов к явным спискам разрешений и более строгой санитизации.
PoC следует тому же потоку, что и реальный браузерный контекст:
shopmgrwpApiSettings.noncePOST /wp-json/wwp/v1/admin/saveПоскольку уязвимая сборка позволяет пользователям с manage_woocommerce вызывать эту операцию записи настроек, запрос успешен и приводит к постоянному изменению опции.
nonce помогает защитить от CSRF, но это не механизм авторизации.
Наличие действительной сессии и действительного nonce не означает, что пользователю должно быть разрешено выполнять действия администратора. Использование слишком широкой возможности на привилегированной конечной точке достаточно для создания обхода авторизации с низкими привилегиями.
docker compose up -d --build