Envenenamiento de caché mediante una cabecera no incluida en la clave
El CDN dejaba una cabecera fuera de la clave de caché y el origen la reflejaba. Una petición envenenada alcanzaba a los siguientes visitantes.
Resumen
El origen construía las URL absolutas de sus recursos a partir de una cabecera de reenvío enviada por el cliente. El CDN no incluía esa cabecera en la clave de caché: dos peticiones que solo se diferenciaban en ella se consideraban la misma.
Un atacante podía combinar las dos condiciones y dejar en caché una copia de la página con las referencias apuntando a un dominio suyo. Esa copia se servía después a todos los visitantes de ese nodo.
Detalles técnicos
La cabecera se reflejaba en la respuesta
El origen copiaba ese valor sin validarlo en las URL absolutas del documento:
GET / HTTP/2
Host: [REDACTED]
X-Forwarded-Host: [DOMINIO CONTROLADO]
HTTP/2 200 OK
<script src="https://[DOMINIO CONTROLADO]/assets/app.js"></script>La cabecera no formaba parte de la clave
Comprobamos que la respuesta quedaba almacenada y se servía a peticiones que ya no llevaban la cabecera:
GET / HTTP/2 # sin la cabecera
HTTP/2 200 OK
X-Cache: HIT
Age: 47
<script src="https://[DOMINIO CONTROLADO]/assets/app.js"></script>
[!] La respuesta envenenada se sirve a otros visitantesVentana de exposición
El tiempo de vida configurado determinaba cuántos visitantes recibían la versión envenenada antes de que expirase:
Cache-Control: public, max-age=600
Vary: Accept-Encoding # la cabecera de reenvío no aparece
[+] Diez minutos por nodo y por envenenamiento
[+] Renovable con una petición periódicaApuntamos la cabecera a un dominio del equipo, que no servía ningún fichero. La comprobación se hizo sobre un único nodo de borde acordado con el cliente. Purgamos la entrada envenenada al terminar.
Impacto que sustenta la severidad 8.3
- Carga de scripts desde un dominio controlado por el atacante en el navegador de cualquier visitante del nodo afectado
- Robo de sesión de cualquier usuario autenticado que cargue la página
- Difusión por nodo: una sola petición alcanza a los visitantes que lleguen después, hasta que la entrada expira
- Suplantación de la marca: la página envenenada se sirve desde el dominio legítimo
- Detección tardía: las peticiones servidas desde caché no llegan a los registros del origen
Remediación
- No construir URL absolutas a partir de cabeceras del cliente. Usar la dirección canónica configurada en el servidor.
- Incluir en la clave de caché toda cabecera que altere la respuesta, o dejar de aceptarla en el borde.
- Rechazar las cabeceras de reenvío no esperadas en el CDN, antes de que lleguen al origen.
- Declarar correctamente
Varypara las cabeceras que sí deban diferenciar respuestas. - Purgar la caché tras desplegar la corrección: las entradas ya envenenadas se siguen sirviendo hasta que expiran.
Referencias
Más análisis
Comprueba si este vector afecta a tus sistemas
Cuéntanos qué activos quieres auditar. Respondemos en menos de 24 horas.