Zum Inhalt springen

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Schwachstellenklassen Glossar

Race Condition (TOCTOU) - Timing-basierte Sicherheitsschwachstelle

Race Conditions (CWE-362) entstehen wenn die Sicherheit eines Systems davon abhängt dass zwei oder mehr Operationen in einer bestimmten Reihenfolge ausgeführt werden, aber parallele Ausführung diese Reihenfolge verletzt. TOCTOU (Time-Of-Check Time-Of-Use) ist die häufigste Form: Prüfung und Nutzung einer Ressource sind zeitlich getrennt. Sicherheitsrelevante Auswirkungen: Doppel-Ausgaben in Finanzanwendungen (Double-Spending), Privilege-Escalation über temporäre Dateien, Discount-Missbrauch, Account-Übernahme. Schutz: atomare Datenbankoperationen, Mutexe, optimistic locking.

Race Conditions gehören zu den schwieriger zu findenden aber oft hochimpactigen Schwachstellen. Ein klassisches Beispiel: Online-Banking-Anwendung prüft Kontostand (€50) und überweist dann. Was wenn ein Angreifer 100 Überweisungsanfragen gleichzeitig sendet? Jede Prüfung sieht €50, jede Überweisung wird ausgeführt, bevor das Konto aktualisiert wird. Ergebnis: €5.000 abgebucht statt €50.

TOCTOU - Time Of Check / Time Of Use

Grundprinzip

Normaler (unsicherer) Ablauf:

  • t=0: PRÜFUNG: Kontostand = €50, Überweisung €50 → OK
  • t=1: AKTION: Buche €50 ab, Kontostand = €0

Race Condition (parallele Anfragen):

  • Anfrage A, t=0: PRÜFUNG: Kontostand = €50 → OK
  • Anfrage B, t=1: PRÜFUNG: Kontostand = €50 → OK (noch nicht aktualisiert!)
  • Anfrage A, t=2: AKTION: Buche €50 ab, Kontostand = €0
  • Anfrage B, t=3: AKTION: Buche €50 ab, Kontostand = -€50 (!)

Das Zeitfenster zwischen CHECK und USE = “Race Window”. Je größer das Race Window, desto leichter ausnutzbar. Datenbank-Calls, Netzwerk-Requests und I/O vergrößern das Fenster.

TOCTOU-Kategorien

1. Datei-System-TOCTOU:

// Prüfen ob Datei existiert:
if (!file_exists($filename)) {
    file_put_contents($filename, $data);  // ← Zwischen check + use: Symlink!
}
// Angreifer erstellt Symlink zwischen file_exists() und file_put_contents()
// Schreibt Daten in /etc/passwd o.ä. (wenn Prozess Root-Rechte hat)

2. Web-Anwendungs-TOCTOU (Business Logic):

  • Prüfen ob Benutzer genug Guthaben hat
  • Guthaben abbuchen
  • Race Window: parallele HTTP-Requests senden

3. Betriebssystem-Level:

  • Prozesse mit SUID-Bit: Datei-Existenz prüfen, dann öffnen
  • Zwischen Prüfung und Öffnen: Datei austauschen
  • Privilegierter Prozess öffnet nun andere Datei als erwartet

Auswirkungen in Web-Anwendungen

1. Gift-Card / Coupon-Codes mehrfach einlösen

Normaler Ablauf:

  1. Prüfe: ist Gutschein gültig? (Status = unused)
  2. Wende Rabatt an
  3. Markiere Gutschein als used

Race Condition:

  • Angreifer sendet 50 parallele Requests mit demselben Code
  • Alle prüfen: Status = unused → alle OK
  • Alle wenden Rabatt an (bevor einer “used” setzt)
  • Gutschein 50x eingelöst!
Nachweis: Burp Suite Turbo Intruder
POST /apply-coupon { "code": "SAVE50" }
→ 50 parallele Requests → prüfen ob mehrfach gutgeschrieben

2. Doppel-Ausgaben / Double-Spending

Krypto-Wallet oder E-Commerce:

  1. Prüfe: Wallet-Guthaben ≥ 100
  2. Sende Transaktion: -100
  3. Aktualisiere Wallet: -100

Race: parallele Transaktionen senden, beide prüfen 100 ≥ 100 → true. Beide Transaktionen werden ausgeführt → effektiv wird 200 aus einem 100-Guthaben verbraucht.

3. Limit-Umgehung (Rate Limiting via DB)

“User darf max. 1 Konto erstellen”:

  1. Prüfe: hat User schon Account? (COUNT(*) = 0)
  2. Erstelle Account
  3. Ergebnis: Account existiert

Race: 100 parallele Registrierungsanfragen → alle prüfen: 0 Accounts → true → alle erstellen Account → User hat 100 Accounts!

4. TOCTOU bei Privilegien-Änderung

Admin-Panel: “Deaktiviere User-Account”:

  1. Prüfe: ist Account aktiv? (active = true)
  2. Invalide Sessions
  3. Setze active = false

Race: User sendet Request im selben Moment → Check: active = true → OK → Deaktivierung läuft → User-Request passiert zwischen Prüfung und Deaktivierung → noch autorisiert!

Erkennung und Testing

Burp Suite Turbo Intruder

Speziell für Race-Condition-Tests optimiert: HTTP-Pipelining + simultane TCP-Verbindungen, sehr präzises Timing (ms-Genauigkeit).

Basic Race Condition Test:

  1. HTTP-Request identifizieren (z.B. POST /apply-coupon)
  2. In Burp: Send to Turbo Intruder
  3. Payload: 50 Requests mit race=true
  4. Send simultaneously (nicht sequentiell!)
  5. Responses analysieren: mehr als 1 Erfolg?

Turbo Intruder Konfiguration:

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                          concurrentConnections=50,
                          pipeline=False)  # Separate Verbindungen!
    for i in range(50):
        engine.queue(target.req)  # Alle sofort einreihen

def handleResponse(req, interesting):
    if '200' in req.status:
        table.add(req)  # Erfolgreiche Responses markieren

HTTP/2 Single-Packet Attack:

  • Alle Requests in ein einziges TCP-Paket
  • Maximale Synchronisation → höchste Race-Window-Trefferquote
  • Unterstützt ab Burp Suite 2022.9

Testing-Schritte für Business Logic

  • Gift-Cards: denselben Code 20x gleichzeitig einlösen
  • Überweisungen: denselben Betrag 10x gleichzeitig transferieren
  • Registrierung: denselben Username 10x gleichzeitig anlegen
  • Passwort-Reset: denselben Token 5x gleichzeitig einlösen
  • Discount: denselben Code 20x gleichzeitig anwenden

Indikatoren für Race Conditions

  • Multiple “success” Responses auf identische parallele Anfragen
  • Unterschiedliche Response-Zeiten bei Parallel-Tests
  • Inkonsistente Datenbankzustände nach Tests

Schutzmaßnahmen

1. Datenbankebene - Atomare Operationen

-- Unsicher:
SELECT balance FROM accounts WHERE id = 123;  -- balance = 100
UPDATE accounts SET balance = balance - 50 WHERE id = 123;

-- Sicher (atomare Operation):
UPDATE accounts
SET balance = balance - 50
WHERE id = 123 AND balance >= 50;
-- Affected rows: 0 → Retry oder Fehler; Affected rows: 1 → Erfolg!
-- SELECT FOR UPDATE (Pessimistic Locking):
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 123 FOR UPDATE;
-- Zeile ist jetzt gelockt! Kein anderer Thread kann sie ändern
UPDATE accounts SET balance = balance - 50 WHERE id = 123;
COMMIT;

2. Datenbankebene - Unique Constraints

-- Verhindert Doppel-Ausgabe von Gutscheincodes:
CREATE TABLE coupon_redemptions (
    coupon_code VARCHAR(50) NOT NULL,
    user_id INT NOT NULL,
    UNIQUE (coupon_code, user_id)  -- DB verhindert Duplikat!
);
-- INSERT wird fehlschlagen wenn bereits vorhanden → Race verhindert!

3. Anwendungsebene - Mutex/Semaphore

import threading
lock = threading.Lock()

def transfer_money(from_account, to_account, amount):
    with lock:  # ← Exklusiver Zugriff
        balance = get_balance(from_account)
        if balance >= amount:
            set_balance(from_account, balance - amount)
            set_balance(to_account, get_balance(to_account) + amount)
# Redis-basiertes Distributed Locking (für skalierte Apps):
import redis
r = redis.Redis()
lock_key = f"transfer_lock_{account_id}"
if r.set(lock_key, "1", nx=True, ex=5):  # NX = nur wenn nicht existiert
    try:
        perform_transfer()
    finally:
        r.delete(lock_key)
else:
    raise Exception("Transfer already in progress, retry")

4. Idempotency Keys (für APIs)

Jede kritische Aktion bekommt einen einzigartigen Key:

POST /api/transfer
Idempotency-Key: uuid-generated-by-client

Server-side:

  • Prüfe: wurde dieser Key bereits verarbeitet?
  • Ja: gebe gecachte Antwort zurück (kein erneutes Ausführen!)
  • Nein: verarbeite und speichere Key mit Ergebnis

Verhindert Doppel-Ausführung selbst bei Netzwerk-Retries. Standard in Payment-APIs (Stripe, PayPal nutzen dieses Muster).

5. TOCTOU im Dateisystem

// Verwende O_EXCL + O_CREAT (atomares Erstellen):
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd == -1 && errno == EEXIST) {
    // Datei existiert bereits → Fehler
}
// O_EXCL: Fehler wenn Datei schon existiert
// Atomisch: kein Race zwischen Prüfung und Erstellung!

Cookielose Analyse via Matomo (selbst gehostet, kein Tracking-Cookie). Datenschutzerklärung