When multiple application threads work on the same data concurrently, there is a risk of data inconsistency or data collisions. Database engineers have tackled this problem since the early days of database engines by introducing “atomic” transactions. However, web applications remain vulnerable to an attack known as a “race condition”.
What is a race condition attack?
In the world of web applications, we often observe a flow that users follow to complete a given action. During this flow, the application is in a certain state at each step. For example, in an e-commerce app, a user can redeem a coupon code on the checkout page. The application accepts the code and changes its state to “coupon applied.” If the same coupon is applied twice, a “coupon has already been used” message is usually shown.
A race condition attack attempts to squeeze multiple redeem requests into the time window between code validation and marking the code as “used.” This allows the application to apply the discount twice before it recognizes the code has been utilized and marks it as such.
Real-world scenario
In a recent security assessment, we discovered a race condition issue in a voting system. If two HTTP requests were made concurrently, two votes were registered on behalf of one voter. During the tests, we used Burp Suite Professional to perform this attack. The process looks as follows:
1. Intercept the HTTP request in the application that places the vote, but instead of forwarding it, drop it and pass it to Repeater. This allows us to interact with the requests.
2. Duplicate the request in Repeater, so now there are two identical ones. They both have a structure like below:
3. Add both requests to a group (just to send them “together”):
4. Burp Suite offers multiple methods of sending groups of requests. Here we will choose “Send group in parallel (last-byte sync)”:
5. Send the group using “Send group (parallel)” button.
Both tabs in Repeater reported success and indeed, the application reported two votes in the voting result protocol. But if we tried now to place another vote using the same user, simply repeating the request, this would fail as the user is already marked as one “placed the vote”:
Preventing race condition attacks
Securing your application against such attacks is not straightforward—it depends on the specific case. If your application has any flow that could be exploited to your detriment, each step should be carefully checked. The functionality of blog comments might not be your biggest worry, but stacking discounts or inconsistencies in legal votes can pose a serious problem. Some general countermeasures include:
• Use atomic database transactions when dealing with sensitive data.
• Understand how your ORM works and how does it deal with transactions.
• Have a single source of truth for crucial data.
When testing, remember that race-condition attacks often rely on a narrow time window between operations to squeeze the requests in, ideally around 1ms, and are sensitive to any time delays, whether caused by network jitter or current application load. These types of vulnerabilities do not usually succeed on the first attempt, and neither may your test suite.
#Cybersecurity #RaceCondition #WebSecurity #Pentesting #RealWorldPentests