miércoles, 26 de octubre de 2022

Una Al Mes - Frasco de galletas

¡Hola a todos (después de tanto tiempo otra vez, sí 😅)! El post que os traigo hoy es la resolución del reto "Frasco de galletas", el reto de este mes de Una Al Mes (valga la redundancia). 

La información del reto la tenemos en la plataforma de UAM, así que partimos de ahí para ver la URL donde ir y las indicaciones que nos dan.


 

Accedemos a la URL y vemos la web que nos muestran.

 


En el menú superior tenemos varias opciones y si seleccionamos la segunda, "timeline", vemos que no tenemos acceso.



Si interceptamos la petición con Burp podemos ver algo interesante.



Esto que tenemos en "Cookie" es un JWT, algo de lo que ya hemos hablado en el blog, concretamente en la publicación del "MoonCTF" del año pasado. Básicamente, es un token formado por tres partes distintas separadas por puntos y cada una de ellas en base64. La primera parte contendrá el algoritmo y tipo de token, la segunda los datos almacenados y la tercera es la firma. La segunda cookie "is_admin" no hace nada si la ponemos como "True" sin modificar la primera.



El dato que almacena el JWT es el rol del usuario, por lo que vamos a modificarlo a admin y a probar suerte de que el servidor no esté realizando una buena comprobación de la firma.



Para comprobar si el token que acabamos de generar funciona tenemos que reemplazarlo por el original. También cambiaremos la cookie "is_admin" a True.



Como veis, hemos completado la primera parte del reto y hemos obtenido la primera flag y parte del código de la web. Si revisamos el código que nos dan, podemos ver algo raro en la definición del error 404.



Cuando devuelve el HTML este se forma metiendo la variable "referrer" que es el valor de la cabecera "Referer" pasando por unos filtros. Podemos observar varias limitaciones:

  • La longitud total de la URL (usa el valor de la cabecera Host y no la IP y puerto donde mandamos la petición).
  • Que el referer no esté vacío.
  • Que la función valid_url declarada más abajo devuelva True.

Vamos a revisar la función valid_url para saber qué más tener en cuenta.

 


Esta función está comprobando que el valor de la cabecera Referer coincida con el valor del host (el valor que devuelve request.host_url será la cabecera Host añadiendo "http://" al inicio y "/" al final), por lo que sabemos que si nuestra cabecera Host es "a", la cabecera Referer debe de empezar con "http://a/". También nos indican que la diferencia de longitud no debe de ser mayor de 16.

Sabiendo esto, podemos empezar a probar. La vulnerabilidad que buscamos explotar es SSTI (Server Side Template Injection), una vulnerabilidad que permite injectar en una plantilla un payload que se interpretará en el servidor. En este caso estamos ante una web hecha con Flask y el motor de plantillas que usará será Jinja2. Comprobaremos la existencia de esta vulnerabilidad mandando en la cabecera Referer un "{{7*7}}".

 

 

Como veis, el resultado de la operación aparece en la respuesta, por lo que el servidor está interpretando lo que hemos introducido.

Si queremos enviar un payload largo vamos a ver que como decía el código hay una limitación de 16 caracteres, por lo que modificaremos el valor de la cabecera Host para que tenga el mismo valor que el payload que vamos a introducir en el Referer, donde pondremos el payload justo después del "http://". Es posible aprovechar que el servidor interpreta lo que introducimos para ejecutar comandos en el servidor, por ejemplo, de la siguiente manera:

 

 

El servidor ha ejecutado el comando introducido, "id", y nos indica que somos root, por lo que ya podríamos leer la flag. Como también tenemos una limitación de longitud en la URL completa (90 caracteres), vamos a coger el valor del comando a ejecutar de un sitio distinto, por ejemplo, de una cabecera llamada "a".



De esta forma podemos ejecutar comandos de igual forma sólo modificando una cabecera que el servidor no está teniendo en cuenta, por lo que podemos introducir comandos de la longitud que queramos y leer ya la flag, por supuesto.



Con esto hemos terminado el reto. Es el primer reto que hago de UAM aunque había escuchado hablar de la iniciativa hace mucho tiempo y la verdad es que me ha parecido interesante de hacer, posiblemente traiga otro aquí en un futuro ¡Muchas gracias a todos por pasaros por aquí una vez más!

3 comentarios: