¡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 Business Logic Flaws. 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!
Como nota inicial, este tipo de vulnerabilidades son MUY comunes en aplicaciones web reales. Hay que tener en cuenta que, para detectarlas, requieren conocer muy bien la aplicación, sus usos y que el analista vaya más allá intentando comportarse de forma que la aplicación no haya previsto inicialmente. Es decir, requiere pensamiento crítico y llevar la aplicación «un paso más allá». Pero esto, en definitiva, es el espíritu de cualquier especialista de seguridad ofensiva (o debería serlo… al menos). Por tanto, ponle mucho ojo a este post, ya que si desarrollas o mantiene aplicaciones web y te sientes identificado con las vulnerabilidades que explicaremos aquí, tienes un problema.
Lab1 (Apprentice) – Excessive trust in client-side controls
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, buy a «Lightweight l33t leather jacket».». En este laboratorio, lo que tenemos que hacer es identificar una vulnerabilidad en la lógica de la aplicación para poder comprar un producto sin disponer de dinero suficiente, lógicamente.
Lo primero de todo que tenemos que tener en cuenta es que este tipo de vulnerabilidades, como comentábamos, surgen de fallos en la lógica de la aplicación o situaciones en las que la aplicación se comporta de manera inesperada ante inputs o flujos aleatorios. Lo primero de todo, sería añadir el producto a la cesta, evaluando cuál es el proceso que sigue la aplicación:

Como se puede ver, en este caso los desarrolladores asumen que el cliente no va a inspeccionar las peticiones. Sin embargo, con Burp Suite Professional como proxy vemos que el precio, en realidad, es un parámetro recibido desde el mismo lado del cliente. Debido a ello, se puede manipular incluyendo el artículo en carrito a precio menor de 100$, que es el dinero disponible en la cuenta «wiener». Lo que se hará será vaciar el carrito y añadir de nuevo el producto deseado, pero esta vez enviándolo con el parámetro de precio a 99 (lo que hará que el precio sean 0.99$).


Tal como se ve en la figura anterior, el usuario puede modificar el precio. Esto es algo que se ve muy habitualmente en aplicaciones reales en producción. POR FAVOR, desarrolladores, NO CONFIÉIS NUNCA EL PRECIO DE LOS PRODUCTOS VENDIDOS AL LADO DEL USUARIO, ya que este puede manipularlo y haceros perder mucho dinero. Ahora que ya tenemos el producto añadido a un precio más bajo del que disponemos (y del que vale) podemos lanzar la orden, resolviendo el laboratorio.
Lab2 (Practicioner) – 2FA broken logic
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, access Carlos’s account page.». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de acceso a la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo con el usuario proporcionado como víctima (carlos). En este caso, eso sí, no conocemos su contraseña.
Empezamos visualizando el flujo de inicio de sesión con el usuario legítimo. Vemos que el flujo de autenticación tiene dos pasos lógicos fundamentalmente. En el primero, se envía una petición al recurso «/login» para comprobar el usuario y la contraseña, mientras que en el segundo paso se envía una petición al recurso «/login2» para verificar el doble factor. Tras ello, se redirige al usuario al recurso «/my-account?id=<usuario>» si todo tuvo éxito. Sin embargo, hay una sutil diferencia. En este caso, el segundo paso del flujo parece comprobar cuál fue el usuario que inició el flujo en base al valor de una cookie denominada «verify».


En estos casos, es fundamental que la lógica de la aplicación tenga sentido. ¿Qué queremos decir con esto? Sencillo, que en este caso, por ejemplo, que hay dos pasos bien diferenciados, la lógica de la aplicación debe comprobar que los dos pasos son generados por un mismo usuario y en un orden determinado. Hay flujos en los que no tiene sentido que un usuario genere un paso determinado sin haber completado uno anterior.
En este caso, la vulnerabilidad reside en que el flujo lógico no comprueba que el usuario que lanza la segunda fase de la autenticación multifactor sea el mismo que la inició. Por tanto, podemos iniciar un flujo de autenticación como «wiener» y seguir todo el flujo para loggear las peticiones. Tras ello, haremos un logout de la aplicación y retransmitiremos el flujo.
Para ello, se debe retransmitir la petición a «/login2» y cambiar la cookie, apuntando al usuario «carlos». Cogiendo primero la petición GET al endpoint «/login2», le estaremos enviando un token a «carlos» sin que él haya iniciado sesión. Tras ello, aunque no conocemos el MFA del usuario «carlos», podemos intentar hacerle fuerza bruta a la petición POST con Intruder. Las siguientes capturas muestran cómo hacer esto en este laboratorio. Debes acordarte, eso sí, que la cookie sea nueva.



Finalmente, para resolver el laboratorio lanzamos una petición al recurso «/my-account?id=carlos» y la interceptamos para cambiar las cookies por la cookie que nos proporciona el Intruder en su respuesta 302. Es decir, «pasamos» la sesión del Intruder en la que ya el código MFA se validó previamente. Recuerda cambiar la cookie por la nueva cookie, si no el ataque no tiene sentido.

Lab3 (Apprentice) – High-level logic vulnerability
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, buy a «Lightweight l33t leather jacket».». En este laboratorio, lo que tenemos que hacer es identificar una vulnerabilidad en la lógica de la aplicación para poder comprar un producto sin disponer de dinero suficiente, lógicamente.
Lo primero de todo que tenemos que tener en cuenta es que este tipo de vulnerabilidades, como comentábamos, surgen de fallos en la lógica de la aplicación o situaciones en las que la aplicación se comporta de manera inesperada ante inputs o flujos aleatorios. Para empezar, sería añadir el producto a la cesta, evaluando cuál es el proceso que sigue la aplicación:

En este caso, como se puede ver, no se especifica el precio en la petición. Sin embargo, podemos intentar jugar con el parámetro «quantity» que especifica la cantidad de unidades del producto. Después de vaciar el carrito, añadimos el mismo producto pero, en este caso, interceptamos la petición e indicamos un número negativo. Como vemos, el producto se añade al carrito a un precio negativo, lo cual no tiene un sentido lógico.


Aunque lo anterior no tiene lógica, lo que se ve es que el subtotal a pagar es una cantidad negativa. Debido a ello, si emplazamos la orden no tendrá éxito. Al ser una cantidad menor que 0, la aplicación lo toma como algo no realizable.

Llegados a este punto, llegamos a la conclusión de que lo que necesitamos es añadir en la cesta un producto como el que deseamos (en este caso, la «jacket») y posteriormente, añadir cantidades negativas de productos hasta que el subtotal encaje con el balance del que disponemos (en este caso, 100$). Fíjate cómo en la imagen siguiente configuramos la cesta tal como se comenta (un producto «jacket» y varios productos con cantidades negativas) hasta encajar el subtotal en el balance del que disponemos (menor que 100$, porque ya habíamos hecho una orden anterior).

Finalmente, lanzamos la orden y… ¡¡Laboratorio resuelto!!
Lab4 (Practicioner) – Low-level logic flaw
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, buy a «Lightweight l33t leather jacket».». En este laboratorio, lo que tenemos que hacer es identificar una vulnerabilidad en la lógica de la aplicación para poder comprar un producto sin disponer de dinero suficiente, lógicamente.
Lo primero de todo que tenemos que tener en cuenta es que este tipo de vulnerabilidades, como comentábamos, surgen de fallos en la lógica de la aplicación o situaciones en las que la aplicación se comporta de manera inesperada ante inputs o flujos aleatorios. Para empezar, sería añadir el producto a la cesta, evaluando cuál es el proceso que sigue la aplicación.
En este caso, el flujo es idéntico a los anteriores, pero ninguna de las técnicas ya mostradas funciona. Sin embargo, podemos seguir intentando hacer cosas no esperables. ¿Qué ocurre, por ejemplo, si se añaden miles de productos a la cesta? Vamos a evaluarlo incluyendo 99 «jackets» 300 veces. Usamos para ello el Intruder.


Tal como se puede ver, ahora el carrito tiene un subtotal negativo. ¿Por qué? Pues porque hemos desbordado la variable que almacena dicho subtotal. Es decir, con el número de bits disponibles llega a un punto que no puede seguir incrementando el valor positivo y se desborda la variable, pasando a un valor negativo para volver a incrementarse (imagina que el rango es de -10 a 10 y añades 11 veces un producto de 1€, finalmente el subtotal será de -10€ porque llegará a 10€ y en la siguiente adición se desborda volviendo al punto inicial del rango).
Conocido esto, solamente nos queda añadir «jackets» hasta que el precio encaje en el balance disponible (en el caso anterior, unos 74€ al haber hecho ya una orden para pruebas). Haciendo cálculos básicos, tenemos que añadir un número determinado de «jackets», por lo que configuramos y volvemos a lanzar para ello el Intruder para lanzarse las veces que necesitamos y posteriormente ajustamos añadiendo algunos otros productos para encajar al balance disponible si fuera necesario:

Finalmente, para resolver el laboratorio, lanzamos la orden y… ¡Todo listo!
Lab5 (Practicioner) – Inconsistent handling of exceptional input
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, access the admin panel and delete the user carlos.». En este laboratorio, lo que tenemos que hacer es identificar una vulnerabilidad en la lógica de la aplicación para poder acceder al panel de administración y borrar el usuario «carlos».
Lo primero de todo que tenemos que tener en cuenta es que este tipo de vulnerabilidades, como comentábamos, surgen de fallos en la lógica de la aplicación o situaciones en las que la aplicación se comporta de manera inesperada ante inputs o flujos aleatorios. Para empezar, sería revisar el proceso de registro de usuarios y su flujo.

Después de muchas pruebas, se puede ver que si se incluye un correo demasiado largo, la aplicación no lo maneja de manera adecuada. Fíjate en el siguiente ejemplo, donde se incluye un correo con 300 caracteres y se usa el registro para crear la cuenta de usuario.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%40exploit-0af100130327e3de82db14ad013f000d.exploit-server.net
Tal como se puede ver en las siguientes figuras, el usuario se crea sin problema:


Sin embargo, fíjate cuál es el correo asociado al usuario que se ve en su panel de administración:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@exploit-0af10013
Tiene 255 caracteres. Por ello, se entiende que el parámetro asociado al correo se trunca a los primeros 255 caracteres. Asimismo, accediendo al endpoint «/admin» vemos que solamente los miembros de «@dontwannacry.com» tienen acceso a la administración. Blanco y en botella, debemos construir un correo anormalmente largo que al truncarse se quede como «@dontwannacry.com». Como esos caracteres suman 17, necesitamos incluir por delante 255-17 caracteres, es decir 238. Quedaría un correo tal que así:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@dontwannacry.com.exploit-0af100130327e3de82db14ad013f000d.exploit-server.net
Lanzamos el registro de usuario de nuevo utilizando ese correo y accedemos a la cuenta tras activarla con el mail:

Como vemos, lo hemos clavado. El correo se truncó y a la aplicación web «le parece» que nuestro correo es del dominio indicado. Ahora, simplemente, accede al panel de administración y borra el usuario «carlos» para completar el laboratorio.
Lab6 (Apprentice) – Inconsistent security controls
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, access the admin panel and delete the user carlos.». En este laboratorio, debemos explotar un fallo en la lógica de la aplicación para poder acceder al panel de administración y borrar el usuario «carlos».
En primer lugar, dado que necesitamos acceder a un panel de administración, asumimos que debemos registrarnos en la plataforma. Nos registramos usando un correo controlado por nosotros, revisando todas las peticiones en el Burp. En este caso, usaremos el cliente de correo que nos proporciona PortSwigger.

Como vemos, el registro de usuarios es normal, sin que existan a priori puntos donde la lógica de la aplicación pueda fallar, más allá del correo y comprobar longitudes como hemos hecho en anteriores laboratorios. Sin embargo, eso no funciona en este caso. Sí que debemos darnos cuenta que la propia web nos indica que si pertenecemos a «dontwannacry.com» usemos un correo corporativo. Accediendo a la web con el nuevo usuario creado, podemos ver que es posible actualizar el email registrado. En este caso, como pretendemos hacernos pasar por un empleado de «dontwannacry.com», cambiaremos el correo a «attacker@dontwannacry.com».

Como se puede apreciar, nada más cambiar el correo electrónico ya se tiene acceso al panel de administración y, por tanto, ya es posible borrar el usuario «carlos» resolviendo el laboratorio.
Lab7 (Practicioner) – Weak isolation on dual-use endpoint
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, access the administrator account and delete the user carlos.». En este laboratorio, debemos explotar un fallo en la lógica de la aplicación para poder acceder al panel de administración y borrar el usuario «carlos».
Para evaluar este laboratorio, iniciamos sesión en primer lugar con las credenciales proporcionadas «wiener:peter». Yendo a «My account», se puede ver que existen dos formularios: uno para cambiar el correo y otro para cambiar la contraseña del usuario. Este segundo formulario será el que explotemos, ya que a priori la petición pide usuario, contraseña vieja y contraseña nueva, además de la confirmación, aunque como veremos no todos los parámetros son necesarios:

Como se comentó anteriormente, esta petición puede evaluarse eliminando valores de parámetros o incluso el parámetro al completo. Para comprometer la cuenta «administrator», se usará dicho usuario como valor del parámetro «username» y, dado que a priori no conocemos su contraseña, eliminamos el parámetro asociado a la contraseña actual de la petición.

Como se puede ver, la petición tuvo éxito y el backend cambió la contraseña del usuario «administrator». Para resolver el laboratorio, simplemente inicia sesión con las nuevas credenciales y borra el usuario «carlos».
Lab8 (Apprentice) – Password reset broken logic
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, reset Carlos’s password then log in and access his «My account» page.». En este laboratorio, lo primero que haremos será evaluar el flujo de recuperación de contraseñas con el usuario «wiener». Una vez sabemos cómo funciona, podemos hacernos a la idea de que cambiando el nombre de usuario en la petición POST enviada para resetear la contraseña podemos hacerlo para otros usuarios.
Tal como se indica, lo primero es pedir un cambio de contraseña para el usuario «wiener». Simplemente usando la aplicación podemos hacerlo de forma intuitiva. Esto generará un correo que podemos visualizar en el cliente de correo que nos proporciona PortSwigger en el cual se incluye una URL de reseteo con la siguiente apariencia:
https://0aea0017042b820c8145fcb900be00bb.web-security-academy.net/forgot-password?temp-forgot-password-token=mdlv8e0xplr84749tzkx8xojrdv7jrcx
De manera normal, un usuario hará click en la URL y se le pedirá en ella la nueva contraseña, así como una confirmación. Esto genera una petición POST que se puede visualizar en Burp Suite Professional. Fíjate cómo se incluye en esa petición un campo «username» que indica el usuario para el cual se resetea la contraseña:

Ahora, podemos tratar de cambiar el valor del campo «username» por «carlos» para ver si se le resetea la contraseña a dicho usuario. Dado que el formulario inicial a priori debería de estar expirado por haber sido utilizado, lanzaremos un nuevo proceso de recuperación de contraseña. Haremos click, incluiremos la nueva contraseña y en este punto interceptamos la petición con el nuevo token para cambiar el nombre de usuario de «wiener» a «carlos»:

Se lanza la petición y como vemos, nos devuelve un código 302. Esto indica que aparentemente la contraseña del usuario «carlos» se reseteó. Para comprobarlo, inicia sesión como «carlos» con la nueva contraseña y… Voilà! Laboratorio resuelto.
Lab9 (Apprentice) – 2FA simple bypass
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, access Carlos’s account page.». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de acceso a la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo con el usuario proporcionado como víctima (carlos:montoya).
Empezamos visualizando el flujo de inicio de sesión con el usuario legítimo. Vemos que el flujo de autenticación tiene dos pasos lógicos fundamentalmente. En el primero, se envía una petición al recurso «/login» para comprobar el usuario y la contraseña, mientras que en el segundo paso se envía una petición al recurso «/login2» para verificar el doble factor. Tras ello, se redirige al usuario al recurso «/my-account?id=<usuario>» si todo tuvo éxito.


Lo más importante en este caso es que la cookie de sesión se inicializa por partida doble. En el primer paso, se inicializa un valor de la cookie, mientras que en el segundo paso, dicho valor cambia. La clave en estas situaciones es testear si el valor de la primera cookie es suficiente para dar por autenticado al usuario. En este caso, tenemos las credenciales del usuario «carlos», del cual no conocemos su MFA. Vamos en primer lugar a iniciar sesión con dicho usuario y, cuando estemos en la pantalla de introducir el MFA, simplemente navegaremos a través de la URL directamente a «/my-account?id=carlos».


Como vemos, la cookie de sesión inicializada en el primer paso del flujo de autenticación es ya válida por si misma, sin falta de introducir el segundo factor. Por ello, la navegación directa al enlace protegido es suficiente para bypassear este control. Cuidado con esto, dado que no es la primera vez que encontramos esta vulnerabilidad en sistemas reales.
Lab10 (Practicioner) – Insufficient workflow validation
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, exploit this flaw to buy a «Lightweight l33t leather jacket».». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de compra en la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo para comprar un producto de manera fraudulenta.
En primer lugar, haremos una compra para evaluar el workflow seguido. Como vemos, en primer lugar se añade el producto a la cesta. Tras ello, accedemos a la cesta y emplazamos la orden y, finalmente, se envía una petición de confirmación de la compra.

La última petición «GET» es la importante. ¿Qué ocurre si la enviamos sin haber hecho el checkout? Es un flujo que, a priori, no tiene sentido. Sin embargo, si añadimos el producto «Lightweight l33t leather jacket» a nuestra cesta y, posteriormente, hacemos la petición de checkout de manera directa, se generará una orden de pedido con el producto señalado, resolviendo así el laboratorio:


Lab11 (Practicioner) – Authentication bypass via flawed state machine
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, exploit this flaw to bypass the lab’s authentication, access the admin interface, and delete the user carlos.». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de inicio de sesión en la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo para acceder como administradores y borrar el usuario «carlos».
Lo primero que debemos hacer es visualizar el flujo completo de inicio de sesión. Vamos a fijarnos en las peticiones y en cómo la aplicación maneja el login de un usuario:



Como vemos, es un inicio de sesión en 3 fases:
- En primer lugar, petición POST al endpoint «/login» con usuario y contraseña -> Nos devuelve una cookie de sesión
- En segundo lugar, petición GET al endpoint «/role-selector» con la cookie de sesión anterior -> Nos devuelve nueva cookie de sesión
- En tercer lugar, petición POST al endpoint «/role-selector» con la cookie de sesión del paso 2 -> Nos devuelve cookie final
Todo parece correcto, pero como siempre, debemos evaluar qué ocurre si no se sigue el flujo. Para resolver este laboratorio, basta con que la aplicación no sepa qué rol debe asignar al usuario, ya que por defecto asignará el rol de administrador. Por ello, basta simplemente con hacer login con el usuario «wiener», eliminar la petición 2 (GET a «/role-selector») y navegar directamente a la raíz de la web.
Al realizar la ruptura del flujo, se muestra el panel de administración y se puede borrar al usuario «carlos» sin más que hacer un drop de dicha petición, ya que la máquina de estado de la aplicación web no sabe qué rol asignar y asigna el de por defecto. Te recomendamos que hagas todo esto con Burp Suite Professional y su intercepción en el proxy.
Lab12 (Apprentice) – Flawed enforcement of business rules
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, exploit this flaw to buy a «Lightweight l33t leather jacket».». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de compra en la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo para comprar un producto de manera fraudulenta.
Lo primero que vemos, es un código de descuento para nuevos usuarios «NEWCUST5». Sin embargo, en la aplicación web vemos abajo un formulario para darse de alta en la newsletter de la web. Probamos a darnos de alta y obtenemos un nuevo cupón «SIGNUP30».

Si intentamos aplicar un cupón varias veces, la lógica de la aplicación falla de manera segura, indicando que el código ya está aplicado. Sin embargo, si usamos los códigos obtenidos de manera alternativa, podemos usarlos varias veces sin restricción. Para resolver el laboratorio, por tanto, añadimos los cupones de forma alternativa hasta que el precio encaje en nuestro balance:

Finalmente, emplazando la orden… ¡¡¡Laboratorio resuelto!!!
Lab13 (Practicioner) – Infinite money logic flaw
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, exploit this flaw to buy a «Lightweight l33t leather jacket».». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de compra en la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo para comprar un producto de manera fraudulenta.
Lo primero que vemos es que, de nuevo, si hacemos sign-up en la newsletter, nos aparece el código de descuento SIGNUP30. Además, dado que existe un artículo denominado «Gift card» cuyo valor es de 10$, la propia lógica nos dice que si podemos comprar tarjetas de 10$ con un 30% de descuento (7$), podemos incrementar nuestro saldo de manera artificial. Para ello, en primer lugar, emplazamos una orden para comprar 14 «Gift card» con el descuento del 30%, siendo el total 98$.


Como vemos, ahora tenemos 14 tarjetas regalo de 10$ (es decir, 140$) que nos han costado 98$. Hemos aumentado el balance de la cuenta en 42$ de manera artificial, siempre y cuando hagamos «redeem» de dichos códigos. Para no realizar este proceso de manera manual, lo que haremos será generar un script en Python que inicie sesión como «wiener», compre 14 tarjetas regalo aplicando el código de descuento y posteriormente las incluya en su cuenta. Cada vez que lo hagamos, aumentaremos el saldo en 42$. Por tanto, repitiendo dicho proceso 40 veces tenemos dinero más que suficiente para comprar el artículo. El código usado es el siguiente (con el laboratorio reiniciado, fíjate que tras lanzar el script tu cuenta debe tener más de 1500$).
import requests
from bs4 import BeautifulSoup
import os
BASE_URL = "https://0ad700b003bda92a80803afe00420037.web-security-academy.net/"
REDEEMED_FILE = "redeemed.txt"
# Leer códigos redimidos con stripping para evitar espacios y líneas vacías
if os.path.exists(REDEEMED_FILE):
with open(REDEEMED_FILE, "r") as f:
redeemed_codes = set(line.strip() for line in f if line.strip())
else:
redeemed_codes = set()
print(f"Códigos redimidos cargados: {redeemed_codes}")
def is_code_already_redeemed(code, redeemed_codes):
for redeemed in redeemed_codes:
if code in redeemed or redeemed in code:
return True
return False
for i in range(1, 41):
print(f"\n=== EJECUCIÓN {i}/40 ===\n")
session = requests.Session()
# LOGIN
login_url = f"{BASE_URL}/login"
login_page = session.get(login_url)
soup = BeautifulSoup(login_page.text, "html.parser")
csrf_token = soup.find("input", {"name": "csrf"})["value"]
login_data = {
"csrf": csrf_token,
"username": "wiener",
"password": "peter"
}
session.post(login_url, data=login_data)
# AGREGAR PRODUCTO AL CARRITO
cart_url = f"{BASE_URL}/cart"
session.post(cart_url, data={
"productId": 2,
"quantity": 14,
"redir": "CART"
})
# APLICAR CUPÓN
cart_page = session.get(cart_url)
soup = BeautifulSoup(cart_page.text, "html.parser")
cart_csrf = soup.find("input", {"name": "csrf"})["value"]
coupon_url = f"{BASE_URL}/cart/coupon"
session.post(coupon_url, data={
"csrf": cart_csrf,
"coupon": "SIGNUP30"
})
# CHECKOUT
cart_page = session.get(cart_url)
soup = BeautifulSoup(cart_page.text, "html.parser")
checkout_csrf = soup.find("input", {"name": "csrf"})["value"]
checkout_url = f"{BASE_URL}/cart/checkout"
checkout_response = session.post(checkout_url, data={
"csrf": checkout_csrf
})
# EXTRAER TOKENS
soup = BeautifulSoup(checkout_response.text, "html.parser")
table = soup.find("table", {"class": "is-table-numbers"})
if not table:
print("No se encontró la tabla de tokens.")
continue
codes = [td.text.strip() for td in table.find_all("td")]
print("Tokens obtenidos:")
for code in codes:
print(f"'{code}'") # para verificar si hay espacios u otros caracteres
for code in codes:
if is_code_already_redeemed(code, redeemed_codes):
print(f"{code}: Ya redimido anteriormente. Saltando.")
continue
# Obtener CSRF de /my-account
account_url = f"{BASE_URL}/my-account"
account_page = session.get(account_url)
soup = BeautifulSoup(account_page.text, "html.parser")
csrf_input = soup.find("input", {"name": "csrf"})
if not csrf_input:
print(f"{code}: No se pudo obtener el CSRF.")
continue
csrf_token = csrf_input["value"]
# Redimir gift card
giftcard_url = f"{BASE_URL}/gift-card"
gift_data = {
"csrf": csrf_token,
"gift-card": code
}
response = session.post(giftcard_url, data=gift_data)
soup = BeautifulSoup(response.text, "html.parser")
message = soup.find("div", class_="message")
result = message.text.strip() if message else f"Respuesta HTTP {response.status_code}"
print(f"{code}: {result}")
# Guardar código para no probarlo más (independientemente del resultado)
redeemed_codes.add(code)
with open(REDEEMED_FILE, "a") as f:
f.write(code + "\n")
El código no es el más limpio ni rápido del mundo pero al menos, funciona para el propósito del laboratorio. En caso de que quieras refinarlo, la opción está ahí. Finalmente, para resolver el laboratorio una vez tengas el dinero suficiente, compra el artículo deseado.
Lab14 (Practicioner) – Authentication bypass via encryption oracle
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, exploit this flaw to gain access to the admin panel and delete the user carlos.». Sabemos, pues, que tenemos un usuario básico para visualizar el flujo de uso de la aplicación web (wiener:peter). Tras ello, intentaremos abusar dicho flujo para eliminar un usuario.
Este laboratorio es, en mi opinión, de los más difíciles de resolver en la plataforma. Y no tanto por el nivel técnico que como veremos no es tampoco sencillo, sino porque darse cuenta de este tipo de vulnerabilidades de «encryption oracle» en aplicaciones reales es bastante complejo. Pero vamos a ello.
En principio, lo que evaluamos es la funcionalidad de inicio de sesión. Como vemos, al iniciar sesión indicando «Stay logged in», se genera una cookie que aparece cifrada:

Claro, parece lógico que si conseguimos saber cómo cifrar estos datos (y descifrarlos), podremos forjar cookies arbitrarias. Para ello, si nos fijamos, a la hora de poner un comentario en cualquier elemento del blog, si se incluye un correo inválido se genera en primer lugar una cookie denominada «notification» que posteriormente se envía a otro endpoint para que la descifre como un mensaje «Invalid email address (…)»:


Y aquí es donde tenemos el «encryption oracle». Como vemos, la petición de posteo de comentario cifra el email cuando es inválido y la petición de mostrar el mensaje lo descifra, todo ello a través de la cookie «notification». Por ello, incluimos ahora un comentario con el valor de la cookie «stay-logged-in» que obtuvimos previamente para ver su contenido descifrado:

Como vemos, la cookie se compone del usuario y un timestamp. Sabiendo esto, podemos forjar una cookie cuyo valor sea:
administrator:<timestamp>
Probamos a hacerlo usando el mismo timestamp que para «wiener». Para ello, lanzamos la publicación de un comentario «falso» cuyo email es el valor anterior y obtenemos la cookie «notification». Para asegurarnos de que está bien, la desciframos:


Y… Como vemos… ¡¡Error!! Porque el valor que nos proporciona el comentario del blog incluye el string «Invalid email address: «, que debemos eliminar si queremos que nuestra cookie sea válida. Para eliminarlo, vamos a eliminar los 23 primeros bytes que se corresponden con esos caracteres, usando Burp Decoder (muy útil en estos casos):

Ahora, lanzamos de nuevo el descifrado del nuevo valor resultante. A priori debería de ser la cookie deseada pero… Como vemos… ¡¡Nuevo error!!

En este caso, como vemos, el error ya no es del propio texto, sino que se trata de un error a la hora de descifrar el payload. Y, como ya sabréis si habéis trabajado con cifrados, este error se debe al alineamiento de los bytes y es que tenemos que rellenar (hacer «padding») para que el número de bytes cuadre con el algoritmo. Como hemos eliminado 23 caracteres y realmente el algoritmo se basa en cadenas de 16 (a juzgar por el error), lo que haremos será usar un payload con 9 caracteres de relleno para cumplir con el alineamiento. Es decir:
xxxxxxxxxadministrator:<timestamp>
Lanzamos de nuevo el cifrado de la cadena, el descifrado y la eliminación de 32 bytes (en este caso son 32, no 23 lógicamente) en Burp Decoder. Mostramos solo este último paso, ya que el resto están más que demostrados anteriormente cómo hacerlos. Fíjate que aunque en el anterior caso no fue necesario decodificar en Base64, aquí sí debido a la presencia de caracteres como el slash:

Comprobamos ahora si este valor es el adecuado para la cookie descifrándolo:

¡¡Lo tenemos!! Ahora simplemente debemos hacer un «Pass-The-Cookie» para lograr resolver el laboratorio. Esto es, interceptar una petición al login no autenticada, meterle la cookie «stay-logged-in» y se debería iniciar la sesión sola, pudiendo borrar al usuario «carlos».
Lab15 (Expert) – Bypassing access controls using email address parsing discrepancies
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, exploit this flaw to register an account and delete carlos.». Sabemos, pues, que tenemos que logar registrarnos en la aplicación web para eliminar un usuario.
Este laboratorio se basa en el estudio, paper y exposición hecha por Gareth Heyes del equipo de investigación de PortSwigger. El artículo lo puedes leer aquí y te recomendamos que lo hagas, pues si no no entenderás lo que ocurre por debajo a la hora de validar correos.
La primera prueba que haremos, será a registrar un correo del dominio proporcionado por el laboratorio en su «Email client». Lanzamos la prueba y vemos que nos da error, lo cual es esperable porque nos dicen que solamente los usuarios de «ginandjuice» deben poder iniciar sesión.

Bien, leyendo el paper, lo que está claro es que un correo electrónico puede formarse de muchas maneras. De hecho, se pueden usar codificaciones y combinaciones de codificaciones. Fíjate en los siguientes payloads, todos ellos son el mismo correo en realidad: abcfoo@ginandjuice.com:
=?iso-8859-1?q?=61=62=63?=foo@ginandjuice.shop
=?utf-8?q?=61=62=63?=foo@ginandjuice.shop
=?utf-7?q?&AGEAYgBj-?=foo@ginandjuice.shop
Parece increíble, pero es cierto, todos esos correos son «abcfoo@ginandjuice.com». Fíjate que si intentas registrar los 3, el único que te funcionará es el que tiene la combinación UTF-7 y Base64, ya que el resto de charsets están filtrados. Registraremos, pues, un usuario con el siguiente correo:
=?utf-7?q?attacker&AEA-exploit-0adc007b04a298cc8223326501780046.exploit-server.net&ACA-?=@ginandjuice.shop
Parece magia, pero en realidad hemos puesto la negrita por algo. El string «&AEA-» es la codificación de la «@», mientras que el string «&ACA-» es la codificación del espacio. Por tanto, el correo nos quedará decodificado tal que así:
attacker@exploit-0adc007b04a298cc8223326501780046.exploit-server.net @ginandjuice.shop
Es importante el espacio, aunque en el código anterior no lo ves. Asimismo, como veremos, esto funcionará y llegará un correo a «attacker@exploit-0adc007b04a298cc8223326501780046.exploit-server.net», ya que el backend en ese punto creerá que es el correo que estamos registrando. Sin embargo, a la hora de chequear los permisos, ese otro punto del backend tendrá seguramente en cuenta el final del string completo «ginandjuice.com» y, por tanto, obtenemos acceso de administración.



Como vemos, laboratorio resuelto. Un caso este muy curioso y que nos deja pie a probarlo en entornos reales. Aunque nunca hemos encontrado aplicaciones que discriminen por dominio, esto puede resultar muy muy interesante.
~km0xu95