Intro
This post/writeup is all about the Business Logic Vulnerabilities.
I’ll be using primarily Portswigger Web Academy Labs, but i do intent do throw other labs and writeups here as well.
Business logic vulnerabilities are flaws in the design which usually get discovered by using the web application in a way that was not intended to be used. E.g., process from checking what is in the cart to the payment.
TOC
- Intro
- Excessive trust in client-side controls - define the price from the client
- High-level logic vulnerability - Set product quantity in negative
- Low-level logic flaw - Integer Overflow
- Inconsistent handling of exceptional input - email address gets trimmed after 255 characters while registering
- Inconsistent security controls - change email address to gain access to internal admin panel
- Weak isolation on dual-use endpoint - Removal of current-password parameters while changing password
- Insufficient workflow validation
- Authentication bypass via flawed state machine - exploiting default behaviour
- Flawed enforcement of business rules - alternating coupon codes
- Infinite money logic flaw
- Authentication bypass via encryption oracle
Excessive trust in client-side controls - define the price from the client
This lab doesn’t adequately validate user input. You can exploit a logic flaw in its purchasing workflow to buy items for an unintended price. To solve the lab, buy a “Lightweight l33t leather jacket”.
You can log in to your own account using the following credentials:
wiener:peter
This is the jacked that we’re supposed to buy, i’ve alrady put it into the cart. Who doesn’t want a “l33t” jacked, right? I’ve also logged in using wiener:peter
.
This is the request and aparently price is getting sent from the client
I’ll remove the jacked from my cart and put a number 5000
in there, making it cost 50 Bucks: productId=1&redir=PRODUCT&quantity=1&price=5000
Now let’s buy the l33t
Jacket and solve the lab.
High-level logic vulnerability - Set product quantity in negative
This lab doesn’t adequately validate user input. You can exploit a logic flaw in its purchasing workflow to buy items for an unintended price. To solve the lab, buy a “Lightweight l33t leather jacket”.
You can log in to your own account using the following credentials:
wiener:peter
Now we have to buy the l33t
jacket again. I’ve logged in and clicked on Add to Cart
When we send the product to the cart, POST Request to /cart
will be sent with following parameters/values in the body: productId=1&redir=PRODUCT&quantity=1
.
What happens if we change quantity
to -1
?
We should recieve some money for buying the jacket! But that doesn’t happen. We recieve an error instead: Cart total price cannot be less than zero
. Let’s add the jacket and drive the total price above 0 with another product!
Lab has been solved!
Low-level logic flaw - Integer Overflow
This lab doesn’t adequately validate user input. You can exploit a logic flaw in its purchasing workflow to buy items for an unintended price. To solve the lab, buy a “Lightweight l33t leather jacket”.
You can log in to your own account using the following credentials:
wiener:peter
Procedure is the same. Login and put the jacked in the cart.
Maximum amount of quantity that we can add to the cart is set to 99
.
Let’s try intruder and start adding jackets to the cart. Do not put any positions:
Check the cart at 6040 items:
at 17236
From here the price starts falling.
Solution #1 - simple Intruder and manual browser check
Now we just need to make sure to stop the intruder before we hit 0 again. We wan’t to end up with the Total price between $0
and $100.00
.
Lab has been solved.
Solution #2 - Intruder with consequent request to check total price
We can also get results like this:
To make that work i’ve used Project Options and added a Macro:
And everything else in Intruder Settings stays the same exept extract grep
.
It’s not faster or anything like that, this solution just presents the total price in the Intruder itself!
Inconsistent handling of exceptional input - email address gets trimmed after 255 characters while registering
This lab doesn’t adequately validate user input. You can exploit a logic flaw in its account registration process to gain access to administrative functionality. To solve the lab, access the admin panel and delete Carlos.
So it’s about registering a user. This is how registration form looks like:
We also have an email client
We should use the email shown in the email client for registration!
If we register we’ll recieve a Email that looks like this:
1
2
3
4
5
6
7
8
Hello!
Please follow the link below to confirm your email and complete registration.
https://0a3300aa04c4cf72c0d6d01200e4006e.web-security-academy.net/register?temp-registration-token=TQCEaSvNMlQZXucS22Lgj5Kkzkpv1tGf
Thanks,
Support team
If we try to re-register carlos
we get following message: An account already exists with that username
So we’ve hit the bottom of this rabbit hole, so what else we have:
- During registration we’ll see following message
If you work for DontWannaCry, please use your @dontwannacry.com email address
. - If we do basic directory enumeration we’d find a
/admin
directory.
If we go to that page, we’d find Admin interface only available if logged in as a DontWannaCry user
. So we need a DontWannaCry
user.
This part is weird, as i’m not sure why such an Email would be sent in a first place but perhaps it has been made this way to make the lab not to hard.
If we register Email longer than 255 characters, the email will trim on the backend.
E.g. let’s use python to generate long Email address above 255 characters:
1
2
3
4
5
lukaosojnik@Yokai ~ % python3 -c "print('a'*250 + 'attacker@exploit-0a2e00bc04962b4bc025167101ea00bf.exploit-server.net')"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaattacker@exploit-0a2e00bc04962b4bc025167101ea00bf.exploit-server.net
lukaosojnik@Yokai ~ % python3 -c "print(len('a'*250 + 'attacker@exploit-0a2e00bc04962b4bc025167101ea00bf.exploit-server.net'))"
318
So our Email is now 318 characters long. If we register it, that’s what’s shown in the backend after logging in:
Our email has got trimmed. And it’s exactly 255 characters long:
1
2
lukaosojnik@Yokai ~ % python3 -c "print(len('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaattac'))"
255
Now let’s try to have it trimmed in a way so our Email ends with @dontwannacry.com
.
Start with attacker@dontwannacry.com
continued with our address. (after trial an error, i’ve had to remove a @ from our address otherwise email would not get accepted!)
1
2
lukaosojnik@Yokai ~ % python3 -c "print(len('attacker@dontwannacry.com'))"
25
We’re at 25 Bytes, we need to divide that from 255 and that’s our filler
1
2
3
4
5
lukaosojnik@Yokai ~ % python3 -c "print(len('a'*230 + 'attacker@dontwannacry.com'))"
255
lukaosojnik@Yokai ~ % python3 -c "print('a'*230 + 'attacker@dontwannacry.com' + 'attacker@exploit-0a2e00bc04962b4bc025167101ea00bf.exploit-server.net')"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaattacker@dontwannacry.comattacker@exploit-0a2e00bc04962b4bc025167101ea00bf.exploit-server.net
Now register and login!
We can now go to /admin
and delete Carlos
and solve the lab
Inconsistent security controls - change email address to gain access to internal admin panel
This lab’s flawed logic allows arbitrary users to access administrative functionality that should only be available to company employees. To solve the lab, access the admin panel and delete Carlos.
This lab also involves admin panel which has been found in the previous lab /admin
. We’ve used Feroxbuster to find it, but it’s obviously easily guessable as well ;). If we visit it we see same message Admin interface only available if logged in as a DontWannaCry user
.
We have Email client
to our disposal, so let’s grab the email there and register an account:
We then recieve an Email that we have to confirm.
We can change the email after login:
See the Admin panel
?
Go to /admin
and delete carlos
to solve the lab
Weak isolation on dual-use endpoint - Removal of current-password parameters while changing password
This lab makes a flawed assumption about the user’s privilege level based on their input. As a result, you can exploit the logic of its account management features to gain access to arbitrary users’ accounts. To solve the lab, access the administrator account and delete Carlos.
You can log in to your own account using the following credentials:
wiener:peter
We have a normal page where we can log in. Let’s do that using provided wiener:peter
This is the request that goes out if we change the password:
We can obviously change the password without knowing one just by removing current-password
from the POST Body.
And this works for administrator
as well.
Log in as administrator
go to Admin panel
and delete carlos
in order to solve the lab!
Insufficient workflow validation
This lab makes flawed assumptions about the sequence of events in the purchasing workflow. To solve the lab, exploit this flaw to buy a “Lightweight l33t leather jacket”.
You can log in to your own account using the following credentials:
wiener:peter
This lab is about buying the l33t
leather jacket again. Let’s try to do that, but login first!
After having done all that, this is the cart:
We cannot afford it as Not enough store credit for this purchase
This is the request in Burp. Notice the consquent /cart?err=INSUFFICIENT_FUNDS
.
If we buy a product and we do have sufficient funds, the next consequent request would be /cart/order-confirmation?order-confirmation=true
If we send this GET Request to /cart/order-confirmation?order-confirmation=true
our order would be completed and lab would be solved!
Authentication bypass via flawed state machine - exploiting default behaviour
This lab makes flawed assumptions about the sequence of events in the login process. To solve the lab, exploit this flaw to bypass the lab’s authentication, access the admin interface, and delete Carlos.
You can log in to your own account using the following credentials: wiener:peter
There’s not many options what to do here. Let us login
After logging in we can select a role. We can choose from User
and Content creator
.
If we choose any one of them we cannot get administrator privileges, even if we use role=admininstrator
or role=admin
as parameter. What is default behaviour anyways. What happens if we intercept and drop the request after login?
We can open /admin
and see that our role has defaulted to adminstrator
Delete carlos
to solve the lab.
Flawed enforcement of business rules - alternating coupon codes
This lab has a logic flaw in its purchasing workflow. To solve the lab, exploit this flaw to buy a “Lightweight l33t leather jacket”.
You can log in to your own account using the following credentials:
wiener:peter
There we are buying the l33t
jacket all over again. This is the website when the lab starts:
There’s a coupon code that we can use. Let’s put the jacket to the cart and copy the coupon code.
Heck, we just get a 5$ reduction and we cannot re-apply the coupon as we get Coupon already applied
message.
If we scroll to the bottom in the shop, we can sign up for newsletter
.
We get an alert with a new coupon code: SIGNUP30
:
We can apply that coupon to.
We cannot apply two same coupons at one, we can however alternate them, buy the jacked and solve the lab!
Infinite money logic flaw
This lab has a logic flaw in its purchasing workflow. To solve the lab, exploit this flaw to buy a “Lightweight l33t leather jacket”.
You can log in to your own account using the following credentials:
wiener:peter
If we login using provided credentials we see that we can redeem gift cards
We also have an Email client
and there’s newsletter sign-up
. Let’s copy our email adress wiener@exploit-0a72005b03bfa152c1f90627018c00df.exploit-server.net
and use it for newsletter.
We get an alert (not sure if we need an email - probably not)
We should not the coupon code SIGNUP30
.
If we check the shop we can buy Gift Cards for 10$.
Now,.. we can buy gift card for 10$ and use coupon code to reduce 30% (3$) and redeem it again.
There’s code that we need to redeem:
… and there we see that we’ve earned 3$.
Now we have to automate this using Macros as there’s CSRF Token that is being sent along!
We basically need all POST Requests from sending Giftcard to the card and applying the gift-card
.
We can now do test run
It has worked until buying the card, however gift-card value has to be changed dynamicaly as i’m seeing 400 Invalid gift card
. I will apply the bought gift-card
manually and check the settings for 5th request.
The 5th request should now be using Derive from previous response
. (Response 4)
In 4th Request we will need to define new gift-card
parameter so it will be used in the last 5th request:
If everything went well we should see 302 status after 5th request and 3$ should have been added to our account.
Now it’s time to send this to intruder or Turbo Intruder.
Make sure to define scope. I’ll use Turbo Intruder
so i’ve chosen Extender only.
I’ve used simple script which just issues 200 requests:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=1,
pipeline=False,
engine=Engine.BURP
)
i = 0
while i < 400:
engine.queue(target.req)
i = i + 1
def handleResponse(req, interesting):
# currently available attributes are req.status, req.wordcount, req.length and req.response
if req.status != 404:
table.add(req)
The funds should go up with every request:
With sufficent funds we can buy the l33t
jacket and solve the lab.
Authentication bypass via encryption oracle
This lab contains a logic flaw that exposes an encryption oracle to users. To solve the lab, exploit this flaw to gain access to the admin panel and delete Carlos.
You can log in to your own account using the following credentials:
wiener:peter