viernes, 16 de mayo de 2025

RootedCon 2025 - The Var Store

¡Hola a todos! He participado en la creación del CTF de Var Group en RootedCon2025, celebrada en marzo, con un reto web de dificultad difícil llamado The Var Store y en este post voy a enseñaros su resolución.

Al abrir la URL de la descripción del reto, encontramos un inicio de sesión que enlaza a un registro.

Panel de login.

Podemos crear un usuario y usar estas credenciales para iniciar sesión en la tienda.

Panel de registro.

En la respuesta de la petición de registro vemos que se devuelven los atributos del usuario: username y role.

 
Petición y respuesta del registro.

Al entrar con el usuario creado, podemos ver que hay disponible un formulario para introducir un cupón de descuento y la compra de la flag. Por ahora el intento de compra nos indica que el sistema de pagos está en mantenimiento y que sólo las compras gratis (con 100% de descuento) podrán ser procesadas.

 
Var Store.
  
Petición y respuesta del intento de compra.

Al intentar introducir un código de descuento aleatorio veremos que el servidor devuelve un mensaje de error, y si intentamos algún tipo de inyección, indicará igualmente que el código no es válido, por lo que aparentemente está bien sanitizado. 

Canjeo de código de descuento.

Ya que parece que no podemos avanzar en la parte autenticada, volvemos a revisar la petición de registro. 

Añadiendo un parámetro role, tal como devolvía el servidor en la respuesta legítima, comprobamos que la aplicación está usando el valor que enviamos.

Error debido a un rol incorrecto.

Con el error de la petición anterior podemos ver que se permiten los roles "ADMIN" y "USER", por lo que podemos intentar crear un administrador.

Error al crear un usuario administrador.

Los roles que pueden crearse son ADMIN y USER, y dado que al enviar "admin" hay un bloqueo, probamos a crear un usuario normal para comprobar que usa correctamente nuestro valor.

Registro correcto.

En base a las peticiones que hemos enviado, sabemos que:

  • La aplicación usa el parámetro role enviado.
  • Los roles se están validando.
  • Se asignan al usuario los roles USER y ADMIN, en mayúscula.
  • Los valores en minúscula son aceptados y validados.

Conociendo esto, una de las posibilidades del comportamiento del backend que podemos deducir es:

  1. Se recibe el parámetro role.
  2. Se valida que el valor no sea "admin", por ejemplo, con una expresión regular, con cualquier variación de mayúsculas y minúsculas (pudiendo comprobar esto enviando distintos valores como "Admin", "aDMin", etc) para poder bloquear la petición si la fuente no es confiable.
  3. Se convierte el valor a mayúscula.
  4. Se comprueba que es un rol existente.
  5. Se crea el usuario con el rol indicado.

Si esta hipótesis es correcta, el valor que introducimos se ve modificado al convertirlo a mayúscula, dando posibilidad a explotar una colisión de case mapping.

Esta técnica se basa en que dos caracteres distintos se convierten al mismo caracter al hacer un lower/upper (en este caso, upper). Hay herramientas para comprobar estas colisiones, como unicollider, con la que podemos generar una variación de "ADMIN".

Generación de payload.

Para confirmar que la hipótesis anterior es real, enviamos el rol "admin" sustituyendo la "i" normal por esta "i" en unicode. Se puede comprobar que la conversión se realiza correctamente con una ejecución en local. 

Ejecución en local.

Registro correcto como administrador.

Con el usuario que acabamos de crear, podemos iniciar sesión de nuevo y comprobar que ahora tenemos acceso a varios códigos de descuento que suman un 80%.

Códigos de descuento.

Dado que los códigos no suman el 100% necesario, podemos intentar explotar una race condition para canjear dos veces el mismo código, pero debido al rate limit y al comportamiento del backend, veremos que no es posible explotarla enviando las peticiones como secuencia o en paralelo mediante last-byte sinc

Primera petición del grupo.

Segunda petición del grupo.
 
Como vemos, con los métodos mencionados el servidor procesa las peticiones correctamente sin colisión, pero existe una opción propia de HTTP2 que consiste en el envío de ambas peticiones en un mismo paquete, lo que en este caso permitirá la correcta explotación.

Primera petición con el código aplicado.
 
Segunda petición con el código aplicado.

Ahora podemos comprobar en la web que se ha aplicado correctamente un descuento del 100% y que podemos comprar la flag.

Compra de la flag.

Si estuvisteis en Rooted y participasteis en el CTF, gracias por la participación y espero que lo disfrutaseis tanto como nosotros, y si no pudisteis estar, nos vemos en la siguiente edición ;)

No hay comentarios:

Publicar un comentario