Race Conditions Uncovered: A Practical Guide

Yaseen Zubair
2 min readJul 30, 2024

--

A race condition occurs when two or more threads attempt to execute the same process simultaneously, leading to unintended consequences.

If not properly managed, this can create significant issues for stakeholders, such as:
1. Bypassing numerical limitations on a website.
2. Transferring funds beyond the allowed limit.
3. Transferring more funds than available in an account.

Example Use Cases:

To test for race conditions, consider the following examples. Note that this list is not exhaustive:

  1. User Addition Limitation: Imagine a trial account that allows only one user to be added. If the application is misconfigured, it might be possible to add multiple users simultaneously due to race conditions.
  2. Transaction Limits: In a banking application that permits transfers of up to 50,000 per day, a misconfigured application could allow a malicious user to bypass this limit by initiating multiple transactions concurrently through different threads.
  3. Insufficient Funds: If a user with 500 rupees attempts to transfer 600 rupees, the application should notify them of insufficient funds. However, if the application is vulnerable to race conditions, an attacker might exploit this flaw to transfer more than 500 rupees.

For case 3, look at the figure below:

Since each thread checks the available funds and sees that there is 600 rupees, all transactions are approved. Consequently, a total of 900 rupees could be transferred, resulting in an available balance of -300 rupees after all transactions are completed.

Testing for Race Condition:

To test for race conditions, you can use any tool that replays requests at high speed. A common tool for this purpose is Burp Suite’s Intruder. (Turbo Intruder can also be used, but Intruder is typically sufficient for most proof-of-concept tests.)

  1. Capture the request where the action occurs (e.g., the transfer funds request).
  2. Send the intercepted request to Intruder and select a parameter that won’t affect the request outcome. I prefer choosing “q=0.5” within the Accept-Language header.
  3. Set Intruder to send at least 10 requests concurrently.
  4. Apply your desired payloads, such as numerical values from 1 to 10 (e.g., q=0.1, q=0.2, etc.).
  5. Initiate the attack.
  6. Check the available funds after the transactions to observe any discrepancies.

I will upload another article where I was able to exploit these use cases in real life web applications.

See you later, Adios.

--

--

No responses yet