Web application race conditions: It’s not just for binaries.

How would you feel if you could get free money in your bank account?

Race conditions are usually found in binaries, and are rarely something that a pentester thinks whenever they are performing an assessment. The usual bugs that one finds are more like XSSs, SQLis, business flow bypasses, etc.

This story however happened during a three week assessment of the home banking application of an important bank, which of course shall remain nameless, lest they come from my head.

Home bankings are always crucial applications, and any critical findings means that the application owner and their developers are in a lot of trouble, which usually means that these applications are heavily tested and mature.

This means that after three weeks of pentesting, I was pretty much out of ideas. So, I had to scrape the bottom of the barrel for findings, and suddenly I found gold.

For obvious reasons, I’m going to show this in an application I created myself, to illustrate the vulnerability:

Example application

The transfer process on a big bank is usually very complex, however this application emulates the steps which have to be followed during a transfer:

  1. Check if the parameters received are valid.
Parameter checking.

This includes checking if the parameters are present, that they are of the expected type; in this case the “from” and the “to” should be integers and the amount should be a float. And finally, check if the amount is greater than 0. This is very important, otherwise we could transfer a negative amount, and “create” infinite money.

2. Check if the “from” account exists and get its balance

Get the balance of the account

This queries the database for the account, and returns its balance or null on error:

The “get_balance” function

3. Check if the account has sufficient money for the transfer. Here is where the vulnerability lies. This is called a TOCTOU (Time Of Check to Time Of Use), in which the balance check operation and the transfer operation are not performed atomically (ie. in one single operation).

The vulnerable snippet

The sleep is to simulate the delay between the balance check and the transfer, otherwise it is difficult to trigger the vulnerability locally.

The transfer function.

So, how do we exploit this?

For simplicity, we are going to use Burp’s intruder.
First, we capture a normal transfer request:

A normal request

Then we send it to Intruder and we add a bogus header, so we can control the number of requests that we are going to send:

Intruder configuration

Then we configure the number of threads and the number of requests:

The number of requests to send
The number of threads

And finally, we send the requests:

Intruder attack

And, once we go back to see the accounts balance:

Final result

Here’s a video of the full attack in action:

The attack in action

So, what happened here?

The main problem with this code, is that the operation “check balance” and the operation “transfer” are not performed atomically, which means that they are not performed as one single operation.

Usually this is not a problem, however if we send multiple threads, the following can happen:

Step 1:

Thread 1: Has the source account enough balance? Yes. Proceed to the next step.

Thread 2: Has the source account enough balance? Yes. Proceed to the next step.

Thread 3: Has the source account enough balance? Yes. Proceed to the next step.

Step 2:

Thread 1: Transfer: Add 1000 to the target account and subtract 1000 from the source account.

Thread 2: Transfer: Add 1000 to the target account and subtract 1000 from the source account.

Thread 3: Transfer: Add 1000 to the target account and subtract 1000 from the source account.

This leads to the target account being added 3000 and the source account being subtracted 3000.

Final notes: This type of vulnerability is usually not tested in applications, because it’s mostly associated with binary vulnerabilities. However, we always have to analyze and learn about the business processes, to see if a race condition could provide leverage for an attacker.


References:

Code:

2 thoughts on “Web application race conditions: It’s not just for binaries.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s