Race Condition (TOCTOU) - Timing-basierte Sicherheitsschwachstelle
Race Conditions entstehen wenn Sicherheit von der Reihenfolge zweier Operationen abhängt. TOCTOU-Angriffe und Schutzmaßnahmen für CWE-362 erklärt.
Inhaltsverzeichnis (4 Abschnitte)
Kurzerklärung: 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 → OKt=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:
- Prüfe: ist Gutschein gültig? (Status = unused)
- Wende Rabatt an
- 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:
- Prüfe: Wallet-Guthaben ≥ 100
- Sende Transaktion: -100
- 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":
- Prüfe: hat User schon Account? (COUNT(*) = 0)
- Erstelle Account
- 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":
- Prüfe: ist Account aktiv? (active = true)
- Invalide Sessions
- 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:
- HTTP-Request identifizieren (z.B. POST /apply-coupon)
- In Burp: Send to Turbo Intruder
- Payload: 50 Requests mit race=true
- Send simultaneously (nicht sequentiell!)
- 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! Fragen zu diesem Thema?
Unsere Experten beraten Sie kostenlos und unverbindlich.
Über den Autor
Geschäftsführender Gesellschafter der AWARE7 GmbH mit langjähriger Expertise in Informationssicherheit, Penetrationstesting und IT-Risikomanagement. Absolvent des Masterstudiengangs Internet-Sicherheit an der Westfälischen Hochschule (if(is), Prof. Norbert Pohlmann). Bestseller-Autor im Wiley-VCH Verlag und Lehrbeauftragter der ASW-Akademie. Einschätzungen zu Cybersecurity und digitaler Souveränität erschienen u.a. in Welt am Sonntag, WDR, Deutschlandfunk und Handelsblatt.
10 Publikationen
- Einsatz von elektronischer Verschlüsselung - Hemmnisse für die Wirtschaft (2018)
- Kompass IT-Verschlüsselung - Orientierungshilfen für KMU (2018)
- IT Security Day 2025 - Live Hacking: KI in der Cybersicherheit (2025)
- Live Hacking - Credential Stuffing: Finanzrisiken jenseits Ransomware (2025)
- Keynote: Live Hacking Show - Ein Blick in die Welt der Cyberkriminalität (2025)
- Analyse von Angriffsflächen bei Shared-Hosting-Anbietern (2024)
- Gänsehaut garantiert: Die schaurigsten Funde aus dem Leben eines Pentesters (2022)
- IT Security Zertifizierungen - CISSP, T.I.S.P. & Co (Live-Webinar) (2023)
- Sicherheitsforum Online-Banking - Live Hacking (2021)
- Nipster im Netz und das Ende der Kreidezeit (2017)