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

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

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

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

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

Категории

Все категории
Loading categories
cve-2026-69243-poc-aiohttp-smuggling — Воспроизводит контрабанду запросов CWE-444 в aiohttp через отклонённые WebSocket-апгрейды, с payload на Python/Rust и Docker-лабораторией, демонстрирующей обход контроля доступа прокси. | Kitploit
Инструменты/GitHubGitHub/jvbotelho/cve-2026-69243-poc-aiohttp-smuggling
Генерация полезной нагрузкиАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьФаззинг
GitHubjvbotelho/cve-2026-69243-poc-aiohttp-smuggling

cve-2026-69243-poc-aiohttp-smuggling

Воспроизводит контрабанду запросов CWE-444 в aiohttp через отклонённые WebSocket-апгрейды, с payload на Python/Rust и Docker-лабораторией, демонстрирующей обход контроля доступа прокси.

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

Популярное

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

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

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

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

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

CVE-2026-69243 — смешивание запросов (Request Smuggling) в aiohttp (CWE-444)

Смешивание запросов через отклонённый WebSocket-апгрейд в aiohttp < 3.14.2. Когда обратный прокси-сервер пробрасывает заголовки Connection: Upgrade + Upgrade: websocket, уязвимый парсер aiohttp пропускает тело запроса и трактует последующие байты как конвейерный (pipelined) запрос — обходя контроль доступа на периметре.

Исправлено в aiohttp 3.14.2 (коммит 6ae358f).

Автор: João Victor Botelho (JV Botelho) — https://glitchedcat.com

Запуск за 60 секунд

Скопируйте Python-версию (ноль зависимостей, только стандартная библиотека):

root@kitploit:~
curl -O https://raw.githubusercontent.com/JVBotelho/cve-2026-69243-poc-aiohttp-smuggling/main/poc.py
python3 poc.py <proxy-host> <proxy-port> <backend-host>

Или соберите Rust-версию (ноль зависимостей, только стандартная библиотека):

root@kitploit:~
git clone https://github.com/JVBotelho/cve-2026-69243-poc-aiohttp-smuggling
cd cve-2026-69243-poc-aiohttp-smuggling/poc
cargo build --release
./target/release/cve-2026-69243-poc <proxy-host> <proxy-port> <backend-host>

Готовые бинарники будут публиковаться в Releases через release-workflow.

Оба варианта генерируют побайтно идентичные payload'ы (это обеспечивается CI-тестом на идентичность). Если стенд запущен:

root@kitploit:~
python3 poc.py nginx-upgrade 80 backend-vuln

Ожидаемый результат: 1 HTTP-ответ (WebSocket upgrade rejected). Затем проверьте:

root@kitploit:~
# Backend processed 2 requests (/ws + smuggled /admin):
docker logs backend-vuln | grep -c '"path".*"/admin"'

# Nginx only logged 1 request (the /ws):
docker exec nginx-upgrade cat /logs/nginx-upgrade.access.log | grep -c '/admin'

Количество записей на бэкенде > 0 и в Nginx = 0 означает, что расщепление CWE-444 подтверждено. Этот PoC отправляет один TCP-сегмент — тело и есть внедрённый запрос; Nginx трактует его как тело, а aiohttp — как второй запрос.

Что это доказывает

  • Путаница в парсере: aiohttp 3.14.1 _http_parser.pyx возвращает 2 (пропустить тело) при обнаружении апгрейда до того, как тело потреблено (строка ~863). Байты тела остаются в _message_tail и снова подаются в парсер в finish_response из web_protocol.py (строка ~771).
  • Расщепление CWE-444: фронтенд видит 1 запрос с телом; бэкенд видит 2 конвейерных запроса. В логах — расхождение количества запросов.
  • Обход контроля доступа: когда в Nginx задано location /admin { deny all; }, внедрённый /admin всё равно достигает бэкенда, потому что решения о маршрутизации в Nginx принимаются только на основании внешнего запроса.
  • На уровне обработчика исправления нет: await request.read() возвращает 0 байт для апгрейд-запросов в 3.14.1 — тело удерживается ниже уровня обработчика. Примените патч или удаляйте апгрейд-заголовки на прокси для маршрутов, которые не должны переключать протокол.

Полный стенд

root@kitploit:~
git clone https://github.com/JVBotelho/cve-2026-69243-poc-aiohttp-smuggling
cd cve-2026-69243-poc-aiohttp-smuggling
docker compose up -d

# Run the PoC:
docker compose run --rm --entrypoint /app/poc attacker nginx-upgrade 80 backend-vuln

Сервисы:

КонтейнерНазначение
backend-vulnaiohttp 3.14.1 (уязвимый), READ_BODY=false
backend-vuln-readaiohttp 3.14.1, READ_BODY=true (доказывает, что обработчик не поможет)
backend-patchedaiohttp 3.14.2 (исправлен)
nginx-upgradeПробрасывает апгрейд-заголовки (deny all на /admin)
nginx-defaultНе пробрасывает апгрейд-заголовки (нейтрализует уязвимость)
nginx-stripУдаляет Connection "" (нейтрализует уязвимость)
attackerRust-бинари: reproduce, fase2, poc

Полные результаты фаз 1-3 — в findings/.

Ограничения (честно)

  • Прокси обязан пробрасывать апгрейд-заголовки. Конфигурации Nginx, которые отправляют на бэкенд Connection: close или удаляют заголовки Connection/Upgrade, не уязвимы. Конфигурация, в которой проявляется расщепление, — это канонический фрагмент map для WebSocket из документации самого Nginx по проксированию.
  • Ответ на внедрённый запрос поглощается прокси. В продемонстрированной цепочке Nginx атакующий получает только внешний ответ /ws. Доказательства смешивания — в логах бэкенда, а не в ответе атакующему: в такой топологии это слепой, однонаправленный примитив. Другие топологии прокси не тестировались.
  • Chunked-фрейминг фактически специфичен для CL. Напрямую против aiohttp Transfer-Encoding: chunked НЕ смешивает запросы — строка с размером чанка (например, 3e) попадает в парсер как недопустимый метод, и соединение обрывается. Через Nginx это работает, но через нормализацию: Nginx снимает chunked-кодирование с тела и передаёт синтезированный Content-Length, так что бэкенд эксплуатируется тем же CL-путём. Флаг --chunked демонстрирует путь через прокси.
  • Нужна конечная точка, отклоняющая WebSocket-апгрейд. Обработчик должен возвращать не-WebSocketResponse. Большинство приложений, не использующих WebSocket на маршруте, отклоняют по умолчанию (фреймворк возвращает 404 или передаёт управление следующему обработчику).

Файлы

root@kitploit:~
poc/                       # Rust cargo project
├── Cargo.toml
├── src/main.rs            # CLI binary
├── src/lib.rs             # Library + unit tests
├── tests/parity.rs        # Cross-language payload parity test
└── fuzz/                  # cargo-fuzz targets
poc.py                     # Python PoC (copy-paste from blog)
attacker/ backend/ frontend/   # Docker lab services
docker-compose.yml         # 7-service lab
findings/                  # Research notes (Phase 1-3)
.github/workflows/
├── ci.yml                 # Build, test, clippy, parity, integration, fuzz
└── release.yml            # Cross-compile + GitHub Release

Обнаружение

Полный анализ — в findings/fase3-deteccao.md. Кратко, с оговорками, которые важны в продакшене:

  1. Расхождение количества запросов (бэкенд > фронтенд) на одном соединении. Учтите: бэкенд логирует IP прокси, а не клиента — для корреляции требуется нормализация X-Forwarded-For/Proxy Protocol либо логирование ID апстрим-соединения + последовательности запросов в рамках соединения. Только IP клиента + временное окно — слабый признак (NAT, keep-alive, конкурентность).
  2. Запрос на бэкенде без соответствия во фронтенде: ограниченный путь в логе бэкенда без соответствующей записи в access-логе фронтенда. Отфильтруйте внутренние подсети (health-проверки в обход прокси — ложное срабатывание).
  3. Отклонение апгрейда + другой путь от того же клиента в пределах ~100 мс. Средняя достоверность — легитимный pipelining даёт похожие интервалы; лабораторный логгер не записывает удалённый порт/ID соединения, поэтому «нет нового TCP-handshake» эти данные НЕ демонстрируют.
  4. Middleware удержанного тела (content_length против байт из request.read()): срабатывает на 3.14.1, молчит на 3.14.2. Обнаруживает, но не устраняет. Ограничьте область его применения (маршруты-кандидаты на апгрейд, небольшие тела, статусы, отличные от 101) — наивная версия буферизует каждое тело в памяти.
  5. Превышение reqlen на периметре над базовым уровнем заголовков на WebSocket-эндпоинтах — само по себе низкая достоверность (cookies/JWT/tracing-заголовки шумят), но единственный сигнал на периметре, когда клиент не отправляет Content-Length (chunked-трафик на входе).
Скачать инструмент