Business Logic Vulnerability: Payment bypass
Who doesn’t like coffee? One day my friends took me to the Cafe for a treat, it was new for me and also an expensive one (cafe like Starbucks). We were deciding what to order as all the names were new to me 😛! After deciding the order I discovered Cafe has a mobile app & if I order from an application I can get a discount on order.
After placing the order from the app I observed that the cafe has a reward system against each order & this can be redeemed in the next order. While we were having fun & enjoying its ambience one of my friends challenged me to Hack into the cafe. As I did not have my laptop with me, I told my friend let’s visit again with a laptop.
I was unable to find time for weeks but eventually, I made a plan for the weekend and visited that cafe along with my laptop. Took a corner sit & started my work.
And decided to target their Android application, I quickly set up my proxy and I was good to go as SSL Pinning was not in place.
As a first step, I captured the login flow, it is an OTP-based login, I tried multiple scenarios to bypass the login such as Brute Forcing, Response Manipulation attacks, etc. however, none of them worked. I intended to place an order for free. So without spending time, I jumped on the Payment functionality.
The coffee shop has their own wallet, users can add money into it via multiple ways such as Cards, UPI, Wallets, etc. & can make payments through it. I tried to add money into the wallet via PhonePe got all the flow in the Burp History tried to play with it manipulated many parameters, and performed race condition attacks but couldn’t find any vulnerability.
Moving ahead, I added a few items to the cart & tried to place the order, while doing that I observed one POST API call ‘/cart/session’ having only one parameter i.e. cartID & it has 6 digit value for example cartID=123456, I checked the response of this request and observed that it has all user details including phone number and email address. Immediately I decided to brute force this parameter, sent the request in the Intruder and tried to brute force the last 4 digits. I was surprised by checking the results, this parameter was vulnerable to the IDOR and I got all the user details who tried to make a payment in the past hour.
For some requests, I observed ‘this cart ID is expired’ error message. As per my understanding server was assigning a unique cart ID to the user while customers tried to initiate payment and this cart ID is only valid for one hour. Well, this one is a High Severity issue but my aim was to find a business logic issue so I continued with my testing.
I observed myself on the checkout page. It was time to make the payment but as I mentioned in the beginning about reward points, I was having 100 reward points which equals ₹100. When I applied for this discount using these reward points application performed the following HTTP request.
It didn’t seem to be interesting but just to check its response I intercepted it too. From now things are getting interesting, I observed discounted price in the response. So I updated it with Zero and forwarded the response. The modified price of the order reflected in the app was i.e. Zero. At first, I thought this was just a client-side change and if I tried to place this order I might need to pay the actual amount.
As the order amount was Zero in the app, to test it I tried to place this order and surprisingly order was placed successfully.
For confirmation, I went to the counter and asked the salesperson to check whether they received the order or not. While speaking with the salesperson I understand that the cafe has two Dashboards one for Shop Sale (Primary Dashboard) and the other is something like Universal Sale (Secondary Dashboard).
When a customer places an order after selecting a cafe branch the order comes under the shop sales dashboard. But the order that I placed wasn’t visible on the Shop Sales dashboard. From this behavior, I got to know that whatever amount is paid by the customer belongs to that particular cafe branch. As I haven’t paid for it there was no transaction trail so my order was not listed under the primary dashboard, but it was available in the secondary dashboard. The salesperson thought this was because of some technical issue and I got my order. As a POC I took one picture of myself while enjoying the Coffee. 😜
Earlier in the blog I mentioned about reward points, as soon as I placed this order I got reward points which were 10% of the order amount. That means I can use these reward points in the next order. So my next order will be the genuine order. This means I can place genuine orders using the reward points which I got against the malicious/fake order.
What was the problem?
As per my observations, when a customer uses the reward points equal to the order amount (which makes the order amount zero) then instead of redirecting customers to the payment gateway server directly placing the order which means there was no server-side validation in place to verify it. This behavior of applications leads to severe business logic vulnerability.
It took almost an hour to discover this vulnerability. After enjoying my coffee I immediately reported this issue to the respective authorities by connecting them over LinkedIn and email. Even though this Cafe was not hosting any bug bounty program they have rewarded me for this vulnerability.
After a few days, I discovered two exploitable SQL Injections over the same target one of them was blind & other was an error based along with another IDOR which was leaking the other user’s wallet information.
I would like to thank my friend Anuja Chaudhari for taking me to this Cafe, although the treat was mine. 😝
Total vulnerabilities reported:
1 Business logic issue — Critical Severity
2 SQL Injections — Critical Severity
2 IDORs — High severity