Auditing a Payment Processing of a Booking Framework

This article is thanks to the collaboration with Rayco Betancor and his crazy ideas and deep knowledge of how a Payment processing works, and a lot of trying different requests, forcing errors and trying harder.

Note that this is a real scenario, but the back end is hidden and parameters modified trying to avoid some identification.

About the network

The booking framework network was in AWS service instance, that implies:

Packet Sniffing It is not possible for a virtual instance running in promiscuous mode to receive or sniff traffic that is intended for a different virtual instance. While customers can elect to place their interfaces into promiscuous mode, the hypervisor will not deliver any traffic to an instance that is not addressed to it. Even two virtual instances that are owned by the same customer located on the same physical host cannot listen to each other’s traffic. Additionally, attacks such as ARP cache poisoning do not work within Amazon EC2 and Amazon VPC. While Amazon EC2 does provide ample data protection between customers by default, as a standard practice it is best to always encrypt sensitive traffic.

A bunch of test couldn’t bee performed. The only thing we could do was enumerate but we haven’t found any interesting backend without doing the proper POST or GET request. Ports 8443, 9443 the rest was closed or doing some redirects to pages out of scope.

So, what to do now? Stop here the pentest? We can’t enumerate anything because we receive 404 NOT FOUND when we try to fuzz and any interesting port to exploit.

What to do next? Let’s try to simulate a real booking scenario to figure out how the booking and payment workflow works.

Understanding the workflow

It is important to understand the process since a customer does a booking until he/she pays, via online and he/she receives the booking confirmation. In this case, and generally in the payment process the workflow is the following.

Workflow

Forcing errors to retrieve information

When fuzzing parameters, we notice that there was some error with Stripe.

Response:

HTTP/1.1 200 OK Date: Wed, 03 Oct 2018 14:54:40 GMT Server: Apache-Coyote/1.1 X-Frame-Options: SAMEORIGIN Strict-Transport-Security: max-age=31536000; 
includeSubDomains; preload Content-Type: text/html;charset=UTF-8 Content-Language: en-US Cache-Control: max-age=604800 Expires: Wed, 10 Oct 2018 14:54:40 GMT Vary: 
Connection: close Content-Length: 948  
<html> <head><title>Stripes validation error report</title></head> <body style="font-family: Arial, sans-serif; font-size: 10pt;"> <h1>Stripes validation error report
</h1><p> Here's how it is. Someone (quite possibly the Stripes Dispatcher) needed to get the source page resolution. But no source page was supplied in the request, 
and unless you override ActionBeanContext.getSourcePageResolution() you're going to need that value. When you use a <stripes:form> tag a hidden field called '_sourcePage'
 is included. If you write your own forms or links that could generate validation errors, you must include a value  for this parameter. This can be done by calling 
 request.getServletPath(). </p><h2>Validation errors</h2><p> <div style="color:#b72222; font-weight: bold">Please fix the following errors:</div><ol><li style="color: 
 #b72222;">The value "VISA&quot;&lt;wow&gt;" is not a valid value for field Card Cardtype</li></ol></p></body></html>

Therefore, we know the payment process was using Stripe: Stripes validation error report

Stripe

According to Stripe:

Stripe is the best software platform for running an internet business. We handle billions of dollars every year for forward-thinking businesses around the world. Stripe builds the most powerful and flexible tools for internet commerce. Whether you’re creating a subscription service, an on-demand marketplace, an e-commerce store, or a crowdfunding platform, Stripe’s meticulously designed APIs and unmatched functionality help you create the best possible product for your users. Millions of the world’s most innovative technology companies are scaling faster and more efficiently by building their businesses on Stripe

More information Stripe.

To keep in mind, reading the documentation is the best way to understand what parameters mean and how to try to force the application to enter in an undesired state.

Vulnerabilities found

Reflected XSS after Booking Confirmation

When a user inputs his/her booking information, like username, last name, city, and the booking is confirmed. The user retrieves his/her information with the booking details. However, if a malicious user inputs a XSS Payload that bypass the sanitizer, when the confirmation is rendered, the javascript content would be executed. A malicious user could distribute the link of the confirmation to force the victim to execute the javascript code, letting steal of cookies, redirects, keylogging…

Input with XSS payload:

Payload

Reflection after submission:

Execution

Race condition causing a possible DOS Thread extenuation

There is a race condition when submitting various simultaneous requests in the payment process, the servers keeps the thread opened until process all the requests. Malicious user could submit several request trying to exhaust the thread pool, forcing the web server to deny all new requests.

Oficial stripe documentation indicates:

Instead of “You can use our API 1000 times a second”, this rate limiter says “You can only have 20 API requests in progress at the same time”. Some endpoints are much more resource-intensive than others, and users often get frustrated waiting for the endpoint to return and then retry. These retries add more demand to the already overloaded resource, slowing things down even more. The concurrent rate limiter helps address this nicely.

Vulnerabilities agains logic of the application

When confirming a booking, there is a form that requires the card information. A select menu is shown with the avaible types of card: VISA, Mastercard, American Express and UnionPay. Therefore, users could change the type of its card. This unexepected processing, would impact against business logic.

In Stripe API, the following configuration could be determined:

The brand parameter of the card object exposes whether the card brand is Visa, American Express, MasterCard, Discover, JCB or Diners Club. A card brand may be Unknown if we are unable to determine its brand.

Payment form:

Payment form

Editing the request changing the card type to “JCB”, the data would arrive to Stripe processing.

Edit Card

Note that in the response there is not an error causing for not supporting JCL, is an error for using a fake card. When an unexistent card type is used, the following error is showed:

Error card type