Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2023-6553 — Эксплойт proof-of-concept и техническое описание уязвимости CVE-2023-6553 — неаутентифицированная уязвимость включения PHP-файлов, позволяющая удалённое выполнение кода в плагине WordPress Backup Migration версии <=1.3.7. | Kitploit
Инструменты/GitHubGitHub/dungsocool/cve-2023-6553
Анализ уязвимостейАнализ КодаЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и Образование
GitHubdungsocool/cve-2023-6553

CVE-2023-6553

Эксплойт proof-of-concept и техническое описание уязвимости CVE-2023-6553 — неаутентифицированная уязвимость включения PHP-файлов, позволяющая удалённое выполнение кода в плагине WordPress Backup Migration версии <=1.3.7.

Репозиторий
81 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2023-6553

Включение PHP-файлов, приводящее к RCE — плагин Backup Migration

Плагин: Backup Migration (backup-backup) ≤ 1.3.7

CVSS: 9.8 (критический)

CWE: CWE-98 — Некорректный контроль имени файла для оператора Include/Require

Требование аутентификации: Отсутствует

Воздействие: Удалённое выполнение кода


1. Что это за уязвимость?

Backup Migration — довольно популярный плагин WordPress (более 90 000 активных установок), который помогает пользователям создавать резервные копии. В процессе резервного копирования плагин запускает в фоне файл с именем backup-heart.php — он получает информацию о конфигурации через HTTP-заголовки, чтобы узнать, какой каталог необходимо скопировать, где находится файл конфигурации и т. д.

Проблема в том, что этот файл полностью доверяет HTTP-заголовкам, отправленным клиентом: он напрямую подставляет значение заголовка в путь к файлу, а затем использует require_once() для загрузки файла по этому пути. Атакующему достаточно отправить заголовок Content-Dir, указывающий на каталог с вредоносным PHP-кодом, — и сервер автоматически подключит и выполнит его.

Стоит отметить, что файл backup-heart.php не требует аутентификации — он проверяет только, является ли метод запроса POST, без проверки nonce или прав пользователя. Любой пользователь интернета может отправить к нему запрос.

⇒ Это уязвимость типа zero-click.

АтрибутЗначение
CVE IDCVE-2023-6553
Оценка CVSS9.8 (критический)
Плагинbackup-backup (Backup Migration) ≤ 1.3.7
АутентификацияНе требуется
Взаимодействие с пользователемНет (zero-click)
ИсправленоВерсия 1.3.8

2. Предварительные сведения

Включение файлов в PHP

В PHP есть функции include(), require(), require_once(), используемые для включения других PHP-файлов в работающую программу. Когда путь к файлу, передаваемый в эти функции, поступает из пользовательского ввода без проверки, атакующий может заставить сервер подключить любой нужный ему файл:

  • LFI (Local File Inclusion): загружает существующий файл на сервере — например, файл журнала, «отравленный» PHP-кодом.
  • RFI (Remote File Inclusion): загружает файл с внешнего сервера — требует allow_url_include=On (обычно отключено по умолчанию).

Этот CVE относится к категории LFI — атакующий контролирует путь, передаваемый в require_once(), который указывает на PHP-файл, размещённый атакующим на сервере.

Почему HTTP-заголовки опасны?

Многие разработчики считают HTTP-заголовки «внутренними» метаданными, известными только серверу и клиенту. В действительности атакующий контролирует 100% содержимого заголовков — он может задать любое имя и значение заголовка. Доверять заголовкам так же опасно, как доверять данным форм, — их необходимо проверять.

define() и константы PHP

define('NAME', $value) создаёт константу, используемую во всём приложении. Будучи однажды определённой через define(), константа не может быть изменена. Если $value поступает от атакующего, то все места, где используется эта константа, оказываются под угрозой.

3. Анализ исходного кода — где берёт начало уязвимость?

Шаг 1: Поиск sink

Я начал с поиска по всем выражениям require и include в плагине с помощью grep:

grep -rn "require\|include" includes/

image.png

Поиск вернул множество вызовов require/include. При их просмотре выяснилось, что большинство — это вызовы include_once в banner/misc.php и banner/views/index.php; они относятся к коду отрисовки административного интерфейса с жёстко заданными путями, поэтому использовать их нельзя.

Однако моё внимание привлекли две строки в backup-heart.php:

includes/backup-heart.php:64:   define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');
includes/backup-heart.php:118:  require_once BMI_INCLUDES . '/bypasser.php';

В строке 118 используется require_once с константой BMI_INCLUDES — если бы эта константа была жёстко задана, всё было бы безопасно. Но если посмотреть на строку 64, видно, что BMI_INCLUDES формируется из другой константы — BMI_ROOT_DIR. Значит, нужно проследить дальше: где константа BMI_ROOT_DIR получает своё значение?

Я снова использовал grep, чтобы проследить её:

grep -n "BMI_ROOT_DIR" includes/backup-heart.php

Результат:

image.png

Line 62: define('BMI_ROOT_DIR', $fields['content-dir']);
Line 64: define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');

Строка 62 показывает, что BMI_ROOT_DIR берёт значение из $fields['content-dir']. Это переменная, а не фиксированное значение, — нужно открыть файл и посмотреть, что содержит $fields.

Шаг 2: Изучение исходного кода — откуда берётся $fields?

Я открыл backup-heart.php в VS Code на строке 62:

// Line 62
define('BMI_ROOT_DIR', $fields['content-dir']);

// Line 64
define('BMI_INCLUDES', BMI_ROOT_DIR. 'includes');

image.png

Отчётливо видно, что $fields['content-dir'] напрямую попадает в define(). Теперь нужно определить, где присваивается переменная $fields:

// Lines 7-9: Only checks POST method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit;
}

// Lines 30-33: Reads ALL HTTP headers from the request
if (isFunctionEnabled('getallheaders')) {
    $fields= getallheaders();
}

// Lines 42-46: Lowercases header names
foreach ($fieldsas $key=> $value) {
    $buffer= $value;
    unset($fields[$key]);
    $fields[strtolower($key)] = $value;
}

image.png

image.png

На этом этапе первопричина становится абсолютно ясной: $fields содержит все HTTP-заголовки, полученные через getallheaders() и полностью контролируемые клиентом. Здесь нет ни wp_verify_nonce(), ни current_user_can(), ни проверки корректности пути — код лишь проверяет метод POST и напрямую считывает заголовки.

Шаг 3: Краткое описание хода атаки

Attacker sends POST request with header Content-Dir: /path/to/attacker/
    ↓
getallheaders() reads raw headers → $fields['content-dir'] = "/path/to/attacker/"
    ↓
define('BMI_ROOT_DIR', "/path/to/attacker/")   ← no validation
    ↓
define('BMI_INCLUDES', "/path/to/attacker/includes")
    ↓
require_once "/path/to/attacker/includes/bypasser.php"   ← executes PHP
    ↓
Attacker code runs with www-data privileges → RCE

Кратко о первопричине: HTTP-заголовок → define() → require_once() — и между ними ни одного шага проверки.

Шаг 4: Отладка с помощью Xdebug

Я использовал Xdebug + VS Code, чтобы наглядно подтвердить ход атаки. Я установил две точки останова — на строке 62 и строке 118 в backup-heart.php, после чего отправил эксплойт-запрос с помощью curl.

Точка останова 1 — строка 62:

Отладчик остановился прямо на define('BMI_ROOT_DIR', $fields['content-dir']). Раскрыв переменную $fields на панели Variables, я увидел массив из 22 элементов — все HTTP-заголовки, отправленные клиентом. А именно:

  • content-dir = "/tmp/bmi/" — это ровно то значение, которое было отправлено в заголовке и напрямую присвоено константе BMI_ROOT_DIR.
  • content-abs = "/var/www/html/", content-configdir = "/tmp/bmi/", content-backups = "/tmp/bmi/back..." — всё это контролируется атакующим.

Никаких шагов проверки или фильтрации к content-dir перед передачей в define() не применяется.

Скачать инструмент