Methodological approach to find business logic bugs
3 min read
As cyberattacks rise everyday, so is the web applications’ security. This leads to two potential problems that developers can’t solve on their own. The first one is that the systems are much harder to break: even though they are aware of some of the most common security issues, the web applications systems’ potential bugs are much wider and more complicated to solve. The second problem is the modern frameworks. Even though they are secure by default, they can’t protect a system against logical bugs.
When developers don’t find it easy to find all execution paths that could lead to a logical bug ethical hackers enter the scene, making these findings very interesting and valuable.
In this blog post, I will explain the methodology I follow to find logical bugs as a certified ethical hacker. I will do this by explaining a real-life vulnerability from my latest pentest with Strike, and after that, I will summarize the steps you should follow to find logical bugs. These steps will be generic and can be used with any target, so let’s start.
How did I start?
At Strike I was assigned a pentest for an NFT marketplace. One of the areas that the customer wanted me to focus on was FIAT payments. Basically, FIAT is a fancy name for regular currency (like USD, EUR, etc), so the website allowed users to pay for NFTs using regular currency instead of cryptocurrency.
The website used a private name as its payment gateway. The customer provided me with a test environment that uses a sandbox to test payments, allowing me to use test credit card numbers and make payments without spending actual money.
Before we start, let’s explain how the company works. In summary, the seller - the NFT market in this case - generates a link and provides it to the user, who then uses it to pay using his credit card. Afterward, the company's servers will send a request to a callback endpoint hosted by the seller, so they can confirm that the payment was complete.
In order to be protected against potential attacks, the customer I was working for whitelisted the company's IPs to prevent any other IP from sending a request to the callback endpoint. This is highly effective because it prevents anyone from sending a fake payment confirmation.
Since I needed to hack their system, I tried everything to bypass the IP whitelisting but it was properly done: it was implemented both in the application and WAF, and providing headers like “X-Forwarded-For” didn’t work as well.
It seemed like the only solution was to somehow force the company's servers to send a bogus confirmation. However, this had to be done without hacking into its servers since that was out of scope and not controlled by the customer, so it was illegal to perform any ethical hacking against the company itself.
At this point I was a bit stuck, so I decided to create a sandbox account for the company myself. This way, I could have a full picture of what was going on behind the scenes and see the possibility of breaking the application logic without the need to bypass the IP whitelisting.
I started looking into the company's API documentation, and it turned out that they provided a postman API collection.
So of course, I downloaded postman and opened the collection. To use the APIs in the collection, I needed to set the values for "X-Login", "X-Trans-Key" and the "SecretKey" in the postman environment. Those values are available when you register a sandbox account from the company.
I started looking at the APIs and I discovered the API endpoint responsible for generating payment links in the postman collection under "Payings"->"Payments"->"Redirect"->"2 Steps Checkout (without payment_method_id)"
While looking at the JSON parameters for the endpoint I noticed two interesting parameters, the “order_id” parameter, and the “notification_url”. The “notification_url” is set to the callback endpoint so the application can confirm successful payments and “order_id” is set by the application to correlate the payment to the order.
Jackpot? Try harder
After seeing these two parameters, I knew exactly what I needed to do. I had the following attack scenario in mind: what if I use my own account from the company to generate the payment link and do the following?
- Use my sandbox account to generate a payment URL.
- In the “order_id” I will place the value of my order in the NFT marketplace.
- Set the “notification_url” to the callback URL from the NFT marketplace.
- Perform the payment. This way, the company will contact the NFT marketplace for me with the order id, effectively bypassing the IP whitelisting.
I tested the above attack scenario, and as I suspected, the developers only checked the order id but didn’t check the payment id. Sidenote: the payment id is sent by the company when performing the callback and it's also available when you generate the link in the first place.
The above scenario allowed me to bypass the IP whitelisting since the callback is coming from the company. Also, it allowed us to fully control the price, and even if we can’t control the price we are basically paying ourselves.
Based on the above scenario you will notice that there are some steps that you can repeat whenever you’re looking for logical bugs:
Understand the application logic. This means that you should use the application as a regular user.
Try to understand the technical details of the implementation. This usually requires reading the documentation for the technologies/APIs used by the target website.
You will need to write your own code that utilizes the same technology or API. This allows you to dive into the details and make sure you understood the documentation correctly, and it also helps later with the exploitation. While writing the code, try to focus on what could go wrong. For example: if you take into consideration what kind of checks you need to implement to prevent attacks, this will allow you to build a checklist that you can use in a black box pen-testing.
I hope you find this article useful. Happy hacking!