
Hola a todos, hoy os traigo una vulnerabilidad diferente, no es el típico XSS ni tampoco un bypass que ocurra todos los días.
A principios de agosto encontré una vulnerabilidad de lógica de negocio que me permitió saltarme el pago de un pedido durante el proceso de compra en una tienda online. Este tipo de fallos son especialmente interesantes porque no se detectan con escáneres automáticos ni con payloads clásicos, hay que entender el flujo de la aplicación y buscar el momento exacto en el que la lógica se rompe.
Las imágenes que se muestran a continuación son de ejemplo y han sido generadas con IA para evitar mostrar la identidad real del sitio.
Reproducción de la vulnerabilidad
El primer paso era añadir un artículo al carrito. Como ejemplo voy a poner una camiseta que cuesta 25€. Una vez llegamos a la parte final del checkout, seleccionamos como método de pago PayPal y podemos ver el resumen del pedido con el importe total que vamos a pagar.

Antes de continuar, hay que capturar la petición que se encarga de modificar la cantidad de productos en el carrito. Para ello, aumentamos la cantidad a 2 unidades, internamente el carrito pasaría a ser de 50€.

Justo antes de pulsar en pagar, en este momento el carrito de la tienda contiene 2 camisetas (50€), mientras que PayPal sigue teniendo autorizado únicamente el importe original de 25€.

Ahora sí, pulsamos en el botón «Pagar» que se ve en la imagen y, como el importe autorizado por PayPal ya no coincide con el total real del carrito, la operación falla y la tienda nos muestra un error. Viendo ese error, lo primero que piensas es que el ataque no ha funcionado y que la tienda está validando correctamente el importe. Pero realmente sí funcionó, y es aquí donde está el detalle interesante.
Aquí estaba la vulnerabilidad
Si te fijas bien en las peticiones, la que contiene el mensaje de error fue enviada por PayPal a la tienda a través de un parámetro en la URL codificado en Base64, lo que dificulta darse cuenta de la vulnerabilidad a simple vista. La mayoría de gente vería el error en pantalla, cerraría la pestaña y seguiría con su vida.
Si decodificamos el payload de la URL, vemos que aparecen dos variables:
- Una variable error con el endpoint al que se redirige al usuario cuando el pago falla.
- Una variable ok con el endpoint al que redirige la tienda cuando el pago se realiza correctamente.
En este caso la web mostraba el mensaje de error, pero lo que hice fue coger el endpoint de la variable ok y acceder directamente al enlace.

Después de acceder a este endpoint, el pedido fue marcado como pagado y aparecía en la sección de Mis Pedidos sin haber pagado un céntimo.
Por qué ocurre esto
El problema está en que el endpoint que finaliza el pedido confía únicamente en que le llegue un identificador válido asociado a la sesión, sin volver a preguntarle a PayPal si realmente se ha cobrado el importe correcto. En otras palabras, la tienda asume que si se está llamando a ese endpoint es porque el pago ha ido bien, cuando en realidad ese enlace se le entrega al cliente incluso en el flujo de error.
