Host Header Injection + DoS en Microsoft


¿Qué es Host Header Injection?
El HTTP Header "Host", es la cabecera encargada de decirle al Web Server, cual es el virtual host que debe resolver al recibir el request de un cliente. El siguiente ejemplo es un uso clásico del header en un request:
GET /reset HTTP/1.1
Host: example.com
En la práctica, muchos frameworks utilizan el "Host" para hacer redirects, formar urls o enlaces que luego son usados en funciones (password reset, verificación), callbacks OAuth/OIDC, CORS y generación de links públicos.
El problema de confiar en los Header
El problema con las implementaciones que confían en el Host para realizar alguna función, es que a veces se olvidan que el Host puede ser modificado desde el cliente. Y que ese header muchas veces, hace distintos saltos y puede pasar por un reverse proxy, load balancer o CDN que luego es reenviado (o normalizado). Una web vulnerable, al usar el valor de forma directa:
<a href= "https://_SERVER['HOST']/password-reset"
> Cambiar Contraseña
</a>
Un atacante puede inyectar algo como:
GET
/reset-password
HTTP/1.1
Host: attacker.com
Y obligar a la aplicación a escribir en su front, URLs hacia su dominio como en el ejemplo, pero también, interceptar las rutas de la aplicación o envenenar cachés (cache poisoning). En esencia, ese es el Host Header Injection... cuando una aplicación utiliza el Header Host y el atacante lo modifica antes de ser usado. Esto ocurre más a menudo de lo que parece.
En este post expongo un caso real de Host Header Injection avanzado, encontrado y explotado en Xandr, el servicio B2B de Microsoft Ads. Primero explico como logré un open redirect, y posteriormente como lo convertí en un Denial of Service que dejó la aplicación Inaccesible World Wide.
Vulnerability assesment
Como primer paso, forcé un Host header arbitrario para ver cómo reaccionaba la web, manteniendo el target real fijo en mi proxy (separando el Host header de la IP/puerto de destino para no “saltar” de servidor). Con el target apuntando al host legítimo, probé requests como:
GET /reset HTTP/1.1
Host: attacker.com
Si con un Host inesperado sigue funcionando la web, se puede inferir que hay un default/fallback virtual host y llega el momento de comenzar a observar qué hace el target con ese valor: ¿construye absolute URLs con Host?, ¿emite redirects basados en Host?, ¿altera routing o afecta caché?
Al momento de hacer cambio de "Host" puedes recibir inmediatamente "Invalid Host header" o su equivalente... Esto suele pasar cuando en la arquitectura hay reverse proxy / load balancer / CDN al frente de la web, en estos casos hay otras técnicas que te permiten cambiar el "Host" pero sin tener que cambiarlo directamente.
Explotación con Headers "Forwarded"
¿Qué es y por qué importa? La clave está en entender que estamos hablando de una vulnerabilidad que si bien impacta la aplicación web, se origina a nivel de protocolo. Las arquitecturas modernas casi siempre tienen saltos antes de llegar al backend real. Esto causa que el host a veces llegue modificado a su destino, esto puede ocurrir porque en algún "salto", algún asset del flujo, usa para la comunicación, un hostname local.
Dado que el backend en ocasiones requiere hacer un traceback y conocer el host original usado por el cliente, el protocolo HTTP ya ha implementado distintos headers que ayudan a realizar esta traza. Implementando esos headers, el backend sabe que host usar en las rutas.
X-Forwarded-Host (XFH) es un header que el edge (reverse proxy/CDN/load balancer) debería fijar para que el back-end conozca el host público que vio en el borde (por ejemplo, dashboard.vulnerable.com). Esto es útil cuando el edge reenvía los requests con un "Host" interno, pero el endpoint necesita construir absolute URLs correctas (redirects, password reset, enlaces públicos). La siguiente ilustración explica de manera más didáctica el comportamiento explotando un Open Redirect. Nota: NO es X-Forwarded-For (XFF).

OPEN REDIRECT
Cualquier lógica del endpoint que construye absolute URLs terminó emitiendo enlaces basados en "Host":
- Password reset hijack (links de reset hacia mi dominio).
- Open redirect en flujos que dependen de absolute URLs.
- Cache poisoning si hay caches que indexan por host.
- Potencial SSRF en callbacks que confían en el host resultante.
Denial of Service - Incorrect Host Parsing
En este momento es donde se pone más interesante el hallazgo. Para que el Host Header Injection tenga un impacto importante, debe ser o muy específico y encontrarlo en un endpoint como los antes mencionados o sencillamente debe ser adherida a otra vulnerabilidad.
Cuando explotas un Host Header Injection, así como en SSRF u Open Redirect, casi siempre hay en el backend, un parser que no está funcionando de forma adecuada. Este caso, no fue la excepción. Durante las pruebas que realicé, encontré que si el valor de X-Forwarded-Host contenía ciertos caracteres con URL encode, la aplicación (Backend) generaba un error y el Edge contestaba con un Error 502.

Cuando enviaba el payload correcto para explotar la vulnerabilidad, el dominio completo de la aplicación de Microsoft, quedaba Off con un error 502 en el index. De hecho, el DoS duraba mayor cantidad de tiempo según el payload que se ponía como valor, en algunos casos por cada request enviado, el portal reflejaba a nivel mundial Error 502 Service Unavailable hasta por 30 segundos.
- X-Forwarded-Host: %2e%2Fattacker.com (~10 segundos de DoS por request)
- X-Forwarded-Host: %2e%2Fattacker.com%3A123 (~30 seconds de DoS por request)

Para subir el impacto de la aplicación hice un pequeño script en python que basicamente enviaba requests con el payload específico en el header X-Forwarded-Host de manera automática y mientras el exploit estaba en ejecución, el portal se veía con error 502 World Wide.
Buenas práticas y snippets
Para que puedan practicar la vulnerabilidad y en caso tengan una aplicación vulnerable, les dejo un pequeño snippet de código explicando como se ve la vulnerabilidad desde el código fuente. Desde los headers.
# Se confia en el X-Forwarded-Host y lo usamos como host "público"
host = request.headers.get( "X-Forwarded-Host" , request.host)
#también confía en el scheme y aumenta muchísimo el riesgo.
scheme = request.headers.get( "X-Forwarded-Proto" , request.scheme)
return f" {scheme} :// {host} "
def go ():
# Redirect que construye el destino absoluto, con el URL base vulnerable
dest = f" {get_base_url_vulnerable()} /dashboard"
# Location quedará controlado por XFH si el edge/cliente lo fija
return redirect(dest, code= 302 )
(Referencial) - Recomendaciones:
- No uses headers del cliente para el BASE_URL. Define el BASE_URL por entorno y consúltala desde un config file.
- Si necesitas leer Host/X-Forwarded-Host, valida contra una allowlist y solo confía en headers seteados por tu reverse proxy/CDN (limpia los headers entrantes).
- En el edge, no establezcas XFH → Host y fuerza canonical host (301/308) si llega uno no permitido.
Conclusiones
El caso presentado evidencia cómo una vulnerabilidad aparentemente menor, como confiar en el header "Host" puede convertirse en un vector crítico al interactuar con balanceadores, CDNs y parsers mal implementados. Lo que inició como un simple open redirect, aumentó considerablemente su impacto al escalar hasta un DoS global.
La lección que quisiera destacar es que la seguridad web no solo depende del código de la aplicación, también depende de cómo los distintos componentes de la arquitectura interactuan entre ellos y con los protocolos. Validar y controlar los headers entrantes, junto con una configuración segura en el edge, es indispensable para evitar que un detalle, se pueda transformar en un ataque de gran impacto. El hacking web moderno ya no es solo aplicación, también son protocolos.
Todos los Pentest realizados por el equipo de Deep Security, son ejecutados con un nivel técnico avalado por la experiencia de un equipo que reporta vulnerabilidades a las empresas más grandes del mundo.
Si necesitas un Pentest profesional y acompañamiento continuo para mantener segura la superficie en internet de tu compañía, escríbenos y nuestro equipo comercial te contactará.
.




