What is a Race Condition? Exploitations and Security Best Practices

With a good Internet connection and high-performance hardware, users can have the impression that their actions on a web page are instantaneous or almost.

However, it should not be forgotten that a server takes time to process requests. Even if it is a matter of milliseconds, this delay may be of interest to an attacker. These are known as race condition attacks.

In this article, we present an overview of race conditions, their principles and exploitation techniques, as well as security best practices and measures to implement to counter the risks of attack.

What is a Race Condition?

Race condition attacks exploit the timing of the simultaneous sending of several requests.

The aim is to take advantage of the fact that servers can manage several threads, i.e. process requests in parallel. By sending simultaneous requests attempting to modify the same data, the attacker seeks to provoke an unexpected state in the server, not anticipated in its normal operation.

These attacks often occur because of a time lag between the moment when the application checks a security condition and the moment when it modifies the state of an object.

This type of vulnerability is known as a TOCTOU (Time Of Check, Time Of Use) flaw.

Let’s take the example of an e-commerce site that allows users to post a review of a product only after purchasing it, and only once.

When the user sends a request to post a review, the server first checks that no other review has already been posted by this user.

If the condition is met, the review is saved and the number of reviews for that user is updated to 1, preventing him/her from posting any more. However, this process does not take place instantaneously, but in the space of a few milliseconds.

An attacker could take advantage of this short delay to send several requests before the variable is updated to 1, allowing him to post several reviews.

How to Exploit a Race Condition Vulnerability?

This category of vulnerabilities is generally difficult to exploit for several reasons. In-depth knowledge of the application is often required, and specialised tools are needed for successful exploitation.

In addition, an external factor to take into account is the state of the network over which requests are sent. A simple slowdown when sending a request can be enough to cause the attack to fail.

Server latency can also influence the attacker’s attempts, but this element is beyond his control and is often negligible compared to network latency.

It is also important to understand that not all attempts will succeed. It may be necessary to make several attempts before obtaining a successful result.

Research was carried out to find methods of getting around the randomness of the network. One of the first techniques, called ‘last-byte sync’, was based on the HTTP/1.1 protocol.

Web servers only process the data they receive once all the bytes of the request have been transmitted. The idea is therefore to send several requests without their last byte, then to finish them by sending this last byte in parallel.

This has less impact on network latency, as only a few bytes are transmitted at the end.

This technique has been improved with the ‘single-packet’ attack, which uses the HTTP/2 protocol. This protocol offers a feature called multiplexing, which allows two complete HTTP requests to be sent in a single TCP packet.

However, sending just two requests may not be enough, so the ‘last-byte sync’ technique is also used to send the last byte at the end.

The results obtained with this method are quite efficient. It allows up to 20 requests to be sent in parallel, all arriving at the server within around 1 millisecond.

These two techniques are integrated into Burp, making them easy to use.

In the ‘Repeater’ tab, create a group of requests.

There are several options for sending a group of requests. You can choose to send them via one or more connections, or in parallel using the last-byte synchronisation technique.

Example of Race Condition Exploitation

Let’s look at an example of exploiting a race condition encountered during a pentest.

The response time of an application can provide information about its data, even if the response seems identical. A common example concerns the password reset functionality on sites with an authentication system.

A first request is sent to request a reset email for an existing account. A second request is made for a non-existent account. Very often, a significant difference in response time is observed, sometimes of the order of a second. This is explained by the time taken by the server to send the email. On the other hand, no email is sent for an invalid account, which reduces the calculation time.

You can then try to list valid accounts with a list of emails. All you have to do is look at the application’s response time, looking for requests that take longer than others.

If the time difference is smaller, the single-packet attack technique (described above) can be used to virtually eliminate the latency caused by the network.

This leakage of information has little impact on most platforms unless it is very sensitive and the publisher absolutely does not want anyone to know who is registered on it.

Furthermore, e-commerce platforms are particularly vulnerable to race conditions, with consequences far more significant than simply discovering a valid email. These flaws are often to be found in the payment and use of discount coupons.

During an audit, we tried to apply the same discount code several times to significantly reduce the amount in the shopping basket, without success. However, it was possible to apply two different coupons to the same basket, even though these coupons could not normally be combined.

When we tried to apply these two coupons successively, the second one was not taken into account in the basket.

Request:

POST /redeem_coupon HTTP/1.1
Host: redacted.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0

Coupon=Holidays20

Response:

HTTP/1.1 200 OK
Date: Wed, 02 Oct 2024 15:17:50 GMT
Server: Apache/2.4.29 (Ubuntu)
Set-Cookie: PHPSESSID=prtcdvcds93vrad85nqfhk7fl3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: shop.php
Content-Length: 1127

Coupon applied.

Request:

POST /redeem_coupon HTTP/1.1
Host: redacted.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0

Coupon=Christmas10

Response:

HTTP/1.1 500 Internal servor error 
Date: Wed, 02 Oct 2024 15:17:50 GMT
Server: Apache/2.4.29 (Ubuntu)
Set-Cookie: PHPSESSID=prtcdvcds93vrad85nqfhk7fl3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: shop.php
Content-Length: 1127

One coupon already applied.

If you delete the coupon that has already been applied, and send the 2 previous requests in a very short time (still using the single-packet attack technique), the attack works. The 2 coupons are then applied simultaneously.

These requests modify the database in a very short space of time. The server checks that no coupons are applied to the basket. However, when the second request is processed, the variable counting the number of coupons applied has not yet had time to be incremented.

How to Prevent Race Condition Vulnerabilities?

Several approaches can be considered to prevent race conditions:

  • Avoid using multiple data stores, which could lead to consistency problems.
  • The application’s sensitive functions should be carried out using atomic queries at database level. These systems manage query concurrency.
  • The use of a programming principle present in many languages is recommended: the mutex. This prevents shared resources from being modified simultaneously. Other similar concepts can be used: semaphores and monitors.
  • Ensure that critical functions are thread-safe during development, i.e. that they can be used by several threads without any risk of conflicts.

Author : Julien BRACON – Pentester @Vaadata