====== BBC Ch 12: Race Conditions ======
//Source: Bug Bounty Bootcamp by Vickie Li//
===== How Race Conditions Work =====
A race condition occurs when the security of a system depends on the sequence or timing of events, and that sequence can be disrupted by an attacker. Web applications are particularly vulnerable when they perform a check-then-act sequence without atomic locking: the state can change between the check and the act.
The classic pattern is **time-of-check/time-of-use (TOCTOU)**:
- Application reads current state (check)
- Application performs action based on that state (use)
- If two requests execute concurrently, both may pass the check before either completes the use, leading to double-execution
===== Example: Bank Transfer Double-Spend =====
Account has $500. Transfer $500 to account A, and simultaneously (before the first transfer completes) transfer $500 to account B:
- Thread 1: checks balance -> $500, OK to proceed
- Thread 2: checks balance -> $500 (first transfer not yet committed), OK to proceed
- Thread 1: deducts $500, sends to account A
- Thread 2: deducts $500, sends to account B
- Balance is now -$500; $1000 was sent from a $500 account
===== Example: Coupon/Vote Manipulation =====
An application allows a coupon code to be applied once. If the "check used" and "mark used" steps are not atomic:
- Thread 1: checks -- not used -> OK
- Thread 2: checks -- not used -> OK (mark not yet written)
- Thread 1: applies discount, marks used
- Thread 2: applies discount, marks used
Both threads succeed and the coupon is applied twice. The same logic applies to vote-once checks, daily limit checks, and inventory reservation.
===== Prevention =====
* **Atomic database operations** -- use transactions with proper isolation levels so that check and update happen as a single atomic unit
* **Resource locks** -- acquire a lock on the resource before checking; release after the update; only one thread can hold the lock at a time
* **Synchronization** -- language/framework primitives (mutexes, semaphores) to serialize access to the critical section
* **Principle of least privilege** -- limit per-account transfer rates, vote limits enforced at the DB constraint level
===== Hunting for Race Conditions =====
==== Step 1: Find Features with Limits ====
Target any functionality that:
* Enforces a numeric limit (one vote, one coupon use, $X transfer limit)
* Reads a value then writes a new value in separate operations
* Has a critical action gated on a prior state check
Examples:
* Gift card redemption (single use)
* Promotional discount codes
* Transfer/withdrawal with a balance check
* Daily API rate limits
* Poll voting (one vote per user)
* Email/SMS confirmation codes (can be used exactly once)
==== Step 2: Send Simultaneous Requests ====
Use curl with the ''&'' operator to fire multiple requests in parallel from the shell:
curl -s "https://example.com/api/transfer?to=attacker&amount=500" &
curl -s "https://example.com/api/transfer?to=attacker&amount=500" &
curl -s "https://example.com/api/transfer?to=attacker&amount=500" &
wait
For POST requests with a session cookie:
for i in $(seq 1 10); do
curl -s -X POST https://example.com/api/use_coupon -d "code=SAVE50" -H "Cookie: session=YOUR_SESSION" &
done
wait
The ''&'' sends each request to the background without waiting for the previous to finish.
==== Step 3: Check for Impact ====
After the parallel requests complete, check whether the limit was exceeded:
* Was the coupon applied multiple times? Check order history.
* Was the vote counted multiple times? Check vote totals.
* Did the balance go negative? Check account balance.
* Were multiple confirmation codes consumed? Check server-side state.
==== Step 4: Vary Timing and Thread Count ====
Race conditions are timing-sensitive. If the first attempt fails, try:
* More simultaneous requests (10, 50, 100)
* Requests spread across a slightly longer window
* Burp Suite's Turbo Intruder extension (designed for high-concurrency HTTP races)
* Python with threading or asyncio for more precise control
===== Escalating the Attack =====
* **Financial double-spend** -- transfer same balance to attacker account twice; redeem gift cards multiple times; use discount codes repeatedly
* **Privilege escalation** -- if admin creation or role assignment is gated on a check, race to create two admin accounts simultaneously
* **Bypass rate limits** -- if an OTP or password-reset code can be verified multiple times before expiry, race to try more guesses than allowed
* **Inventory/resource exhaustion** -- over-claim limited seats, beta invites, or limited-quantity items
===== 5-Step Checklist =====
- Find features that enforce a one-time or limited-count action (coupons, votes, transfers, OTPs).
- Understand the check-then-act sequence; identify what window exists between check and commit.
- Send simultaneous curl requests (or Turbo Intruder) targeting the limited action.
- Check state after requests complete to confirm the limit was exceeded.
- Quantify impact: financial loss, unauthorized access, or data corruption and document with a minimal PoC.