Home Business Logic Vulnerabilities
Post
Cancel

Business Logic Vulnerabilities

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

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.

picture 161

This is the request and aparently price is getting sent from the client

picture 162

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.

picture 163

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

picture 164

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?

picture 165

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!

picture 166

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.

picture 167

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:

picture 168

Check the cart at 6040 items:

picture 169

at 17236

picture 170

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.

picture 171

Lab has been solved.

picture 172

Solution #2 - Intruder with consequent request to check total price

We can also get results like this: picture 173

To make that work i’ve used Project Options and added a Macro:

picture 174

And everything else in Intruder Settings stays the same exept extract grep.

picture 175

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:

picture 176

We also have an email client

picture 177

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.

picture 178

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:

picture 179

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!

picture 180

We can now go to /admin and delete Carlos and solve the lab

picture 181

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:

picture 182

We then recieve an Email that we have to confirm.

picture 183

We can change the email after login:

picture 184

See the Admin panel?

picture 185

Go to /admin and delete carlos to solve the lab

picture 186

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

picture 187

This is the request that goes out if we change the password:

picture 188

We can obviously change the password without knowing one just by removing current-password from the POST Body.

picture 189

And this works for administrator as well.

picture 190

Log in as administrator go to Admin panel and delete carlos in order to solve the lab!

picture 191

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:

picture 193

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.

picture 194

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!

picture 195

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

picture 196

After logging in we can select a role. We can choose from User and Content creator.

picture 197

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?

picture 199

We can open /admin and see that our role has defaulted to adminstrator

picture 200

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:

picture 201

There’s a coupon code that we can use. Let’s put the jacket to the cart and copy the coupon code.

picture 202

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

picture 203.

We get an alert with a new coupon code: SIGNUP30:

picture 204

We can apply that coupon to.

picture 205

We cannot apply two same coupons at one, we can however alternate them, buy the jacked and solve the lab!

picture 206

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

picture 207

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)

picture 208

We should not the coupon code SIGNUP30.

If we check the shop we can buy Gift Cards for 10$.

picture 209

Now,.. we can buy gift card for 10$ and use coupon code to reduce 30% (3$) and redeem it again.

picture 210

There’s code that we need to redeem:

picture 211

… and there we see that we’ve earned 3$.

picture 212

Now we have to automate this using Macros as there’s CSRF Token that is being sent along!

picture 213

We basically need all POST Requests from sending Giftcard to the card and applying the gift-card.

We can now do test run

picture 214

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)

picture 218

In 4th Request we will need to define new gift-card parameter so it will be used in the last 5th request:

picture 219

If everything went well we should see 302 status after 5th request and 3$ should have been added to our account.

picture 217

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.

picture 220

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:

picture 221

With sufficent funds we can buy the l33t jacket and solve the lab.

picture 222

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

This post is licensed under CC BY 4.0 by the author.