Authentifizierungsumgehung durch Capture-Replay
Beschreibung
Authentifizierungsumgehung durch Capture-Replay ist eine Schwachstelle, bei der Angreifer Netzwerkverkehr mit Authentifizierungsanmeldedaten oder Befehlen abfangen und wiederholen können, um unbefugten Zugang zu erlangen. Capture-Replay-Angriffe sind verbreitet und können ohne Kryptografie schwer zu bekämpfen sein. Sie sind eine Untergruppe von Netzwerk-Injection-Angriffen, die darauf beruhen, zuvor gesendete gültige Befehle zu beobachten und dann dieselben Befehle (möglicherweise mit leichten Modifikationen) an den Server zurückzusenden. Wenn der Server nicht zwischen frischen Anfragen und wiederholten unterscheiden kann, erreicht der Angreifer denselben authentifizierten Zustand wie der ursprüngliche legitime Benutzer.
Risiko
Replay-Angriffe stellen eine erhebliche Bedrohung für Authentifizierungssysteme dar, insbesondere für solche, die Anmeldedaten im Klartext übertragen oder einfache Hash-basierte Authentifizierung ohne Frische-Garantien verwenden. Angreifer, die in der Position sind, Netzwerkverkehr zu beobachten (durch Netzwerk-Sniffing, Man-in-the-Middle-Angriffe oder kompromittierte Infrastruktur), können Authentifizierungssequenzen erfassen und unbegrenzt wiederholen. Systeme, die MD5 oder andere Hashes für Passwortübertragung verwenden, sind besonders anfällig, da der Hash selbst zum Anmeldedatum wird. Das Risiko wird verstärkt in drahtlosen Netzwerken, gemeinsam genutzten Netzwerksegmenten und jeder Umgebung, in der Verkehrsabfangen möglich ist. Einmal erfasst, können Authentifizierungsanmeldedaten von jedem Standort aus wiederholt werden, was diese Angriffe wertvoll für persistenten Zugang macht.
Lösung
Implementieren Sie Replay-Präventionsmechanismen mit kryptografischen Techniken. Fügen Sie Sequenznummern oder Zeitstempel kombiniert mit kryptografischen Signaturen hinzu, um sicherzustellen, dass jede Nachricht nur einmal verwendet werden kann. Verwenden Sie Challenge-Response-Authentifizierung, bei der der Server für jeden Authentifizierungsversuch eine eindeutige Challenge bereitstellt. Implementieren Sie Nonces (einmal verwendete Zahlen), die in Authentifizierungsnachrichten enthalten sind und verfolgt werden, um Wiederverwendung zu verhindern. Verwenden Sie TLS für allen Authentifizierungsverkehr, um Erfassung auf Netzwerkebene zu verhindern. Für hochsensible Systeme implementieren Sie gegenseitige Authentifizierung mit Client-Zertifikaten. Erwägen Sie die Verwendung von zeitsynchronisierten Einmalpasswörtern (TOTP), die sich periodisch ändern. Wenn Sie Hashes für Authentifizierung verwenden, schließen Sie Zeitstempel und Zufallswerte in die Hash-Berechnung ein, um jede Authentifizierungsanfrage einzigartig zu machen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Zugriffskontrolle Wiederholte Authentifizierungsnachrichten gewähren Angreifern denselben Zugang wie dem ursprünglichen authentifizierten Benutzer. Dies ermöglicht unbefugten Zugang zu geschützten Ressourcen, Annahme der Benutzeridentität und die Fähigkeit, Aktionen als der Opferbenutzer durchzuführen. |
Beispielcode
Anfälliger Code (Python)
Die folgenden Beispiele demonstrieren Authentifizierung, die anfällig für Capture-Replay ist:
# Anfällig: Einfache Hash-basierte Authentifizierung anfällig für Replay
import hashlib
import socket
class VulnerableAuthClient:
def authenticate(self, username, password):
# Anfällig: Hash kann erfasst und wiederholt werden
password_hash = hashlib.md5(password.encode()).hexdigest()
# Anmeldedaten über Netzwerk senden
auth_message = f"{username}:{password_hash}"
self.socket.send(auth_message.encode())
# Angreifer erfasst auth_message, wiederholt sie später
response = self.socket.recv(1024)
return response == b"AUTH_SUCCESS"
class VulnerableAuthServer:
def handle_auth(self, client_socket):
data = client_socket.recv(1024).decode()
username, password_hash = data.split(':')
# Anfällig: Derselbe Hash funktioniert immer
stored_hash = self.get_stored_hash(username)
if password_hash == stored_hash:
# Wiederholter Hash wird akzeptiert!
client_socket.send(b"AUTH_SUCCESS")
return True
client_socket.send(b"AUTH_FAILED")
return False
// Anfällig: Token-basierte Authentifizierung ohne Replay-Schutz
#include <string.h>
#include <time.h>
typedef struct {
char username[64];
char token[128];
} AuthRequest;
int vulnerable_verify_token(AuthRequest *req) {
// Anfällig: Token enthält keinen Zeitstempel oder Nonce
char *stored_token = get_user_token(req->username);
if (stored_token && strcmp(req->token, stored_token) == 0) {
return 1; // Erfasstes Token kann für immer wiederholt werden
}
return 0;
}
// Anfällig: Sitzungstoken-Generierung ohne Eindeutigkeit
char* vulnerable_generate_session(const char *username) {
// Anfällig: Vorhersagbare, wiederholbare Sitzung
static char session[256];
// Kein Zeitstempel, keine Zufallskomponente
snprintf(session, sizeof(session), "%s_session", username);
return session;
}
// Anfällig: API-Authentifizierung ohne Replay-Schutz
public class VulnerableApiAuth {
public boolean authenticate(HttpServletRequest request) {
String apiKey = request.getHeader("X-API-Key");
String signature = request.getHeader("X-Signature");
// Anfällig: Kein Zeitstempel in Signatur
String expectedSig = computeSignature(apiKey, request.getRequestURI());
if (signature.equals(expectedSig)) {
return true; // Dieselbe Anfrage kann wiederholt werden
}
return false;
}
private String computeSignature(String apiKey, String uri) {
// Anfällig: Deterministische Signatur ohne Zeitkomponente
return hmacSha256(getSecret(apiKey), uri);
}
}
Korrigierter Code (Python)
# Korrigiert: Authentifizierung mit Replay-Schutz
import hashlib
import hmac
import secrets
import time
import socket
class SecureAuthClient:
def authenticate(self, username, password):
# Challenge vom Server anfordern
self.socket.send(b"REQUEST_CHALLENGE")
challenge = self.socket.recv(1024).decode()
# Zeitstempel einschließen
timestamp = str(int(time.time()))
# Antwort berechnen einschließlich Challenge und Zeitstempel
message = f"{username}:{timestamp}:{challenge}"
response_hash = hmac.new(
password.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
auth_message = f"{username}:{timestamp}:{response_hash}"
self.socket.send(auth_message.encode())
return self.socket.recv(1024) == b"AUTH_SUCCESS"
class SecureAuthServer:
def __init__(self):
self.used_challenges = {} # Verwendete Challenges verfolgen
self.challenge_timeout = 300 # 5 Minuten
def generate_challenge(self):
challenge = secrets.token_hex(32)
self.used_challenges[challenge] = time.time()
return challenge
def handle_auth(self, client_socket):
data = client_socket.recv(1024).decode()
if data == "REQUEST_CHALLENGE":
challenge = self.generate_challenge()
client_socket.send(challenge.encode())
data = client_socket.recv(1024).decode()
username, timestamp, client_hash = data.split(':')
# Korrigiert: Zeitstempel-Frische verifizieren
request_time = int(timestamp)
if abs(time.time() - request_time) > self.challenge_timeout:
client_socket.send(b"AUTH_FAILED_EXPIRED")
return False
# Korrigiert: Challenge wurde von uns ausgegeben und nicht wiederverwendet
# (In der Praxis würde Challenge in der Nachricht enthalten sein)
# Erwarteten Hash neu berechnen
password = self.get_user_password(username) # Sicher gespeichert
# In echter Implementierung würde gegen gespeicherten Hash verifiziert
# Korrigiert: Jede Authentifizierung ist einzigartig durch Zeitstempel und Challenge
expected_message = f"{username}:{timestamp}:{self.last_challenge}"
expected_hash = hmac.new(
password.encode(),
expected_message.encode(),
hashlib.sha256
).hexdigest()
if hmac.compare_digest(client_hash, expected_hash):
client_socket.send(b"AUTH_SUCCESS")
return True
client_socket.send(b"AUTH_FAILED")
return False
// Korrigiert: API-Authentifizierung mit Replay-Schutz
import javax.crypto.Mac;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;
public class SecureApiAuth {
private static final long MAX_TIMESTAMP_SKEW = 300; // 5 Minuten
private final ConcurrentHashMap<String, Long> usedNonces = new ConcurrentHashMap<>();
public boolean authenticate(HttpServletRequest request) {
String apiKey = request.getHeader("X-API-Key");
String signature = request.getHeader("X-Signature");
String timestamp = request.getHeader("X-Timestamp");
String nonce = request.getHeader("X-Nonce");
// Korrigiert: Zeitstempel-Frische verifizieren
long requestTime = Long.parseLong(timestamp);
long currentTime = Instant.now().getEpochSecond();
if (Math.abs(currentTime - requestTime) > MAX_TIMESTAMP_SKEW) {
return false; // Anfrage abgelaufen
}
// Korrigiert: Prüfen, dass Nonce nicht verwendet wurde
String nonceKey = apiKey + ":" + nonce;
Long previousUse = usedNonces.putIfAbsent(nonceKey, currentTime);
if (previousUse != null) {
return false; // Nonce bereits verwendet - Replay-Versuch!
}
// Alte Nonces periodisch bereinigen
cleanOldNonces();
// Korrigiert: Signatur enthält Zeitstempel und Nonce
String message = String.format("%s:%s:%s:%s",
timestamp, nonce, request.getMethod(), request.getRequestURI());
String expectedSig = computeHmac(getSecret(apiKey), message);
if (MessageDigest.isEqual(signature.getBytes(), expectedSig.getBytes())) {
return true;
}
return false;
}
private void cleanOldNonces() {
long cutoff = Instant.now().getEpochSecond() - MAX_TIMESTAMP_SKEW * 2;
usedNonces.entrySet().removeIf(entry -> entry.getValue() < cutoff);
}
}
Die Korrektur implementiert Challenge-Response-Authentifizierung mit Zeitstempeln und Nonces, um Replay von erfassten Authentifizierungsnachrichten zu verhindern.
Ausgenutzt in der Praxis
MD5-Hash-Replay-Angriffe (Verschiedene Systeme, Historisch)
CVE-2005-3435 dokumentierte MD5-Hash-Authentifizierung, die anfällig für Replay-Angriffe war. Angreifer erfassten gehashte Anmeldedaten und wiederholten sie, um unbefugten Zugang zu erlangen, ohne das ursprüngliche Passwort zu kennen.
Klartext-Protokoll-Replay (Netzwerkanwendungen, Fortlaufend)
CVE-2007-4961 dokumentierte Klartext-MD5-Übertragung kombiniert mit Replay-Schwachstelle, was Angreifern ermöglichte, Authentifizierungssequenzen zu erfassen und zu wiederholen.
Sitzungstoken-Replay (Webanwendungen, Fortlaufend)
Webanwendungen, die Sitzungstoken nicht invalidieren oder Frische-Garantien einschließen, wurden durch Sitzungserfassung und Replay von verschiedenen Standorten ausgenutzt.
Tools zum Testen/Ausnutzen
-
Wireshark — Netzwerkprotokollanalysator zum Erfassen von Authentifizierungsverkehr.
-
tcpreplay — Tool zum Wiederholen von erfasstem Netzwerkverkehr.
-
Burp Suite — Web-Sicherheitstool zum Erfassen und Wiederholen von HTTP-Anfragen.
CVE-Beispiele
-
CVE-2005-3435 — MD5-Hash-Authentifizierung anfällig für Replay-Angriffe.
-
CVE-2007-4961 — Klartext-MD5-Übertragung kombiniert mit Replay-Schwachstelle.
Referenzen
-
MITRE Corporation. "CWE-294: Authentication Bypass by Capture-replay." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/294.html
-
OWASP Foundation. "Session Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
-
NIST. "Digital Identity Guidelines: Authentication and Lifecycle Management." SP 800-63B. https://pages.nist.gov/800-63-3/sp800-63b.html