While security professionals pay significant attention to technical vulnerabilities such as SQL Injection, CSRF and Cross-Site Scripting, modern applications are just as susceptible to business logic flaws. Business logic flaws defy easy categorization and the skill of discovering them can be more art than science.
In this post, we will discuss business constraint bypass vulnerabilities (a unique case of business logic vulnerability) and give AppSec people & pen testers a few tips on how to test for this type of vulnerability.
Business Constraint Bypass can seem simple and harmless at first but can lead to a series of serious problems. Impacts can vary from getting data the user should not have access to, to application-based DoS attacks.
Why is this specific attack important, and how can it impact your business?
Let’s take for example a website that will provide information on the best software for Application Security Testing. The free version of the application returns only the top three results, and if you want to see the whole list, you have to pay. Or maybe you want to see the top ten visited websites from a certain category. With the free version you can make only three requests, and if you need more than those three requests, you have to pay.
Business constraint bypass attacks exist because of applications like these. It will try to bypass the constraint and get as much data as possible for free.
Even if data is not accessed unlawfully, this attack might cause a small application based DoS attack, or if the attacker is able to distribute the request, a full-blown DDoS.
What I like to do first is to find a parameter that might be modifiable to return more data than necessary. This is done usually while going through the application and looking at all of its possibilities. If I see a page that only shows something like 10 results of a certain data and the only way to get more is to click “Next page” I flag that as a possible candidate for constraint bypass attack.
Once I have my candidate I check what requests take place while that page is being loaded. What usually happens in modern applications is that an API request is called for n values of that data.
The next step is trying to cURL that API call and if that works, we’re all set to start attacking.
Let’s say we have this API call that we want to attack
/api/v1/get_books/10/site/all_books. This call gets 10 books on page “All books”.
What we want to attack is the integer value of 10 and we want more books. How do we do that? I usually follow these steps when generating this attack:
First, you would execute the API call to see if you can get the JSON/YAML of the items you want (in our case its books). This can be done easily by executing the request in the browser itself in a new tab or if you’re feeling like a hacker you can use cURL.
Once we confirm that we can return the data we want we can continue to the next step, increasing the number of items.
This is really simple, we just change the number
10 in the call with a
100, and if it returns 100 items (books) we’ve succeeded in an attack.
The next step is trying to see if we can get a 1000 or even more items.
What if we have a call that’s almost the same as the previous one but it has one more parameter in it. Like this:
/api/v1/get_books/10/site/all_books?hash=abcd-12fa-be34-c45d. What does this change for us? This specific hash probably refers to some type of session that the application is using so you wouldn’t abuse the same API call and it’s valid for a short timeframe.
What I usually do in this case is prepare an API call that I want to call but not execute it (so something like this
/api/v1/get_books/100/site/all_books?hash= and then record a regular API request but take the hash from it and plug it into our own call with a modified number of items.
This will usually do the trick in scenarios like these.
Another thing I’ve seen is duplicated parameters, so an API call ends up looking something like this:
As you can see every parameter is being duplicated and if they obfuscate the names to something weird or shorten them you might end up seeing something like the following:
There are a couple of ways to proceed in such cases. , First, we need to analyze the situation to figure out which parameter we’re actually attacking.
- If we execute this and get 10 items, it’s pretty obvious we’re attacking the parameter
- If there are multiple different parameters with different names but the same values we would need to manually check all of them to see which ones are actually the ones that are required by us.
- Once we know which parameters we’re attacking (in our case
b) we can proceed to modify it.
One way to modify is to change both values and see if it gets you the number of items you want, so the API call might end up looking something like this:
And if this works, great, we have a way of getting more items, if it doesn’t work it means there is some weird check in the background.
Another way to do this is to remove the duplicated parameters and see if the API call still works, this can get a bit complicated since you might need to remove some specific double parameters but leave others, so you would need to play around with the call itself.
If you want to get the maximum number of items allowed it’s probably best to use something like a modified binary search (
O(log n)). Since we don’t know the max value we can return we can do something like this:
- If a regular call is for 10 items, and we know that we can get a hundred, for example, we need to increase it a lot more. Go for something a bit more absurd like 10.000 items
- If 10.000 items work you would increase this even further but it will be a bit harder to both verify the amount of data and your browser might act a bit weird with a large JSON so be careful about those things.
- Let’s say 10.000 doesn’t work but we know that 100 does. The next step is as a binary search goes to check the half point of those two.
- We make a request for 5.000 items. And depending on if this works or not we have two possible paths.
- First is if it works, we take another half-point between 5.000 and 10.000, which is 7.500 items. And repeat the previous step.
- Second is if it doesn’t work, we take a half-point between 5.000 and a 100, and that would be 2.500 items. And repeat the previous step.
- We do this until we get to the number of items we want and we know work
If you can’t get the API request to work, and it looks something like this
/api/v1/books/10/page/all_books. The issue could be in the additional parameter that we’re not actually using, page.
What we can do is try removing it and see if that works, our API call ends up with something like
This can be applied to any parameter that isn’t the one we’re attacking, try removing it and see how the API responds. This is a lot of trial and error until you get it to work but it can make your life a lot easier.
Always check the amount of data being requested via an API call. Just because the API is made to be invisible to the user, doesn’t mean it’s actually invisible to everyone.
If you need the API to be dynamic, make sure to either limit it by user or use-case, including the session in the request itself.
Never trust that an API call that’s available from the internet won’t be used or abused by anyone other than your application.
Bright and Business Constraint Bypass
Business Logic Attacks represent a major issue in modern applications.
While a vulnerability like Business Constraint Bypass is easy to find, most automated AST tools are not able to detect it.
Bright is the only DAST solution capable of detecting Business Logic Constraint vulnerabilities in applications and APIs. Simply initiate a scan (using GUI or CLI) and among other vulnerabilities, Bright will also test for business constraint bypass. The resulting report comes completely false-positive free, with remediation guidelines for you and your team. Integrate Bright with Jira, Slack, or any other issue tracking tool and assign any finding as a ticket to your colleagues.
To see these and many other features of Bright in action, request a demo – https://brightsec.com/request-a-demo