This blog was written by Sarvesh Pandey.
When determining black-box or gray-box application security (penetration testing), an assessor mostly concentrates on the top 10 Open Web Application Security Project vulnerabilities and rarely worries about testing race-condition issues. The general consensus is that race-condition attacks are unreliable and cannot be identified using the black-box/gray-box approach. Consultants have typically relied upon source code review techniques to identify this issue. Although source code review is the right approach for identifying race conditions, with modern tools and techniques the potential is also good for identifying race-condition attacks using the black-box/gray-box approach.
In this post we will discuss race conditions and potential scenarios, the approach for identifying such flaws, and offer a race-condition demo using the Burp testing tool.
What is a race condition?
A race condition occurs when multiple threads simultaneously access the same shared code, variables, files, etc. without locking or synchronization, resulting in inconsistency of the output. While writing code, developers often tend to think that the code executes in a linear manner and they neglect the parallel nature of web server execution in which multiple threads execute concurrently, which may result in unintended outcomes.
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.
Three processes simultaneously accessing a critical section.
Java web application internals
In a traditional client server model, a browser forms an HTTP request and sends it to the web server. The browser then renders the response received from the server. Multiple simultaneous requests do not go from the browser to the web server when a user accesses the web application.
Multithreading in servlets.
Consider a Java-based web application running on Apache Tomcat. The app includes a container component that interacts with Java servlets. The container is responsible for managing the lifecycle of servlets, mapping a URL to a particular servlet. When the web server receives a request, it sends that request to container. The container creates a thread to handle that request and creates an HTTP request and response object and passes these objects to a thread.
The container in this scenario does not take care of thread safety. (A piece of code is thread safe if the implementation is guaranteed to be free of race conditions when simultaneously accessed by multiple threads. Thread safety should be handled by the developer.)
To take advantage of this scenario, an attacker can simultaneously send multiple requests using automated scripts, resulting in the generation of multiple threads by the container. These threads are executed in parallel. This execution results in complexities that are difficult to consider while writing code. In this case, thread safety is a security requisite.
(In a multithreaded scenario the container does not create multiple instances of a servlet because the servlet is a singleton, and the servlet member field gets shared with all the concurrent running threads. If the developer uses the servlet member field to perform operations they could create a race condition flaw.)
Consider a scenario in a banking application: An amount needs to be transferred from ACC_From to ACC_TO. The following pseudocode implements the money transfer.
Read account balance from ACC_From
Read account balance from ACC_TO
If (amount <= ACC_From)
In this pseudocode, money is transferred from account ACC_From to account ACC_TO and the application code verifies whether the source account has sufficient funds. But by sending multiple simultaneous requests (using automated scripts) an attacker could withdraw amounts that exceed the current balance.
This behavior is possible because multiple threads are executed simultaneously on the server and the condition inside the “if” statement (which validates the available balance) is evaluated to be true more than once. This results in a race condition because the money transferred may exceed the available balance. Note that this behavior is inconsistent and dependent on environmental variables such as network latency and application load.
While performing penetration testing, security analysts should analyze the complete application and figure out what kind of restrictions the application has and whether those restrictions could be bypassed by sending multiple simultaneous requests.
Using Burp to identify race-condition issues
Using Burp Suite Professional’s intruder tool, a pen tester can send multiple concurrent requests. The preceding pseudocode is implemented in the following demo application.
Consider a client transferring money from Account 888 to Account 999.
- Source Account 888. Balance: $1.
- Destination Account 999. Balance: $29,999.
Now initiate a transaction of $2, which is greater than the available balance ($1) in source account.
The application response is “Transaction Failed” because the transaction amount is greater than available balance in source account.
To exploit a race condition we initiate transaction of $1, intercept the request, and pass it to the intruder tool. At the end of the transaction, the source account balance should be $0 and the destination account balance should be $30,000.
- Capture the money transfer request and send it to the intruder tool.
- Navigate to the Options section and choose the number of threads. We chose 25 (the default value is five) because we want to send many simultaneous requests.
- In the Payloads section, select “Null payloads” because we are going to replay the request as it is.
- Start the intruder attack and observe the results. We see the source account balance now has a negative value.
- Source account balance: $-2.
- Destination account balance: $30,002.
A race condition is sometimes difficult to identify using a black-box/gray-box approach due to inconsistencies in environmental factors such as network latency and web server capability.