← Writeups

Exploiting path delimiters for web cache deception

Web cache deception con delimitadores de path: ; convierte /my-account en un asset estático .js para la caché mientras el origin sigue sirviendo la página de cuenta, cacheando la API key de carlos.

Target Overview & Vulnerability Summary

El objetivo es obtener la API key de carlos. El origin server trata ; como un delimitador de path: /my-account;wcd.js resuelve a /my-account. El cache server, en cambio, clasifica la URL por su terminación .js (extensión de asset estático) y decide cachearla. La respuesta de la página de cuenta queda almacenada bajo la clave con ;wcd.js.

Campo Valor
Severidad Alta (exfiltración de datos autenticados vía caché pública)
Endpoint vulnerable /my-account (cacheado bajo /my-account;wcd.js)
Root cause Delimitador de path ; ignorado por la caché + cacheabilidad por extensión .js

Credenciales del laboratorio: wiener:peter. Se dispone de una lista de caracteres delimitadores.

Technical Breakdown & Exploitation Flow

1. Confirmación del delimitador

Probando con el delimitador ;:

/my-account;asdf.js

La respuesta sigue conteniendo la información del perfil (el origin ignora ;asdf.js y sirve /my-account), y se observa que la respuesta se cachea (extensión .js → asset estático para la caché).

2. Construcción del exploit

Se prepara un script para el exploit server que fuerza al usuario a navegar a la URL deceptiva:

<script>
    document.location = "https://0a6600ff0370fa4e80a9bc0000af0046.web-security-academy.net/my-account;wcd.js"
</script>

3. Resultado

  1. carlos visita el exploit server y su navegador navega a /my-account;wcd.js.
  2. El origin sirve /my-account (su página de cuenta con la API key).
  3. La caché guarda la respuesta bajo la clave /my-account;wcd.js por su extensión .js.
  4. El atacante solicita esa misma URL: la siguiente request a /my-account;wcd.js devuelve el perfil cacheado de carlos con su API key.

Root Cause Analysis

El origin server acepta ; como delimitador de parámetros de ruta (RFC 3986 los define como path parameters), de modo que el recurso efectivo es /my-account. El cache server ignora esa semántica y decide la cacheabilidad por la extensión final de la cadena completa: .js. La misma URL es una página dinámica para la app y un asset estático para la caché. El delimitador se convierte en el mecanismo para insertar una extensión estática en una ruta dinámica.

Secure Remediation

  • Rechazar o manejar explícitamente los parámetros de ruta (;) en los endpoints dinámicos: /my-account;* no debe resolver a /my-account.
  • Configurar la caché para decidir cacheabilidad después de aplicar la misma semántica de path que el origin (sin contar parámetros de ruta para la extensión).
  • Cachear solo extensiones de assets reales servidas por la app (lista blanca de extensiones + tipo de contenido) y nunca respuestas que incluyan cookies de sesión.
  • Añadir Cache-Control: private, no-store en páginas de cuenta y endpoints autenticados.