Debug-Nachrichten enthüllen unnötige Informationen
Beschreibung
Debug-Nachrichten, die unnötige Informationen enthüllen, treten auf, wenn ein Produkt die Offenlegung unnötiger und potenziell sensibler Systeminformationen in Debug-Nachrichten nicht angemessen verhindert. Debug-Nachrichten helfen bei der Fehlerbehebung, indem sie den internen Systemzustand offenlegen, z.B. durch Speicherabzüge oder Boot-Logs über Schnittstellen wie UART oder Scan-Ketten. Während detaillierte Debug-Informationen die Fehlerbehebung unterstützen, riskieren sie die Offenlegung von Details, die Angreifern helfen könnten, Schwachstellen oder die Systemarchitektur zu verstehen. Obwohl "Security by Obscurity" allein unzureichend ist, unterstützt die Begrenzung von Debug-Informationen eine "Defense-in-Depth"-Strategie.
Risiko
Ausführliche Debug-Nachrichten haben erhebliche Sicherheitsauswirkungen. Speicherinhalte offengelegt. Systemarchitektur enthüllt. Sicherheitsumgehungstechniken offengelegt. Pointer-Informationen enthüllt ermöglichen ASLR-Umgehung. Kryptographische Schlüssel offengelegt. Interne Pfade enthüllt. Authentifizierungsdetails offengelegt. Privilegienstufen offengelegt. Angriffsfläche durch detaillierte technische Informationen exponiert. Mittlere Ausnutzungswahrscheinlichkeit.
Lösung
Stellen Sie sicher, dass Debug-Nachrichten während des Debug-Prozesses keine unnötigen Informationen für die beabsichtigte Reaktion offenlegen. Implementieren Sie verschiedene Detailstufen für Debug und Produktion. Entfernen Sie sensible Informationen aus Fehlerantworten. Sanitisieren Sie Speicheradressen vor der Ausgabe. Fügen Sie niemals kryptographisches Material in die Debug-Ausgabe ein. Überprüfen Sie alle Debug-Ausgaben bei Sicherheitsaudits. Deaktivieren oder beschränken Sie Debug-Schnittstellen in der Produktion. Verwenden Sie sichere Debug-Authentifizierung.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Sensible Speicherinhalte und kryptographische Schlüssel können offengelegt werden. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismen können mit enthüllten Informationen umgangen werden. |
| Authentifizierung | Bereich: Authentifizierung, Autorisierung Anmelde- und Sitzungsinformationen können offengelegt werden. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Debug-Nachrichten enthüllen sensible Informationen
#include <stdio.h>
#include <stdint.h>
#include <string.h>
// VERWUNDBAR: Debug-Funktion legt Speicheradressen offen
void vulnerable_debug_memory_error(void* address, size_t size, int error_code) {
// VERWUNDBAR: Legt tatsächliche Speicheradressen offen (besiegt ASLR)
printf("[DEBUG] Speicherfehler bei Adresse %p, Größe %zu, Code %d\n",
address, size, error_code);
// VERWUNDBAR: Speicherabzug enthält sensible Daten
printf("[DEBUG] Speicherinhalte:\n");
hexdump(address, size); // Könnte Schlüssel, Passwörter usw. enthalten
}
// VERWUNDBAR: Boot-Log enthüllt Systemkonfiguration
void vulnerable_boot_log(void) {
// VERWUNDBAR: Enthüllt genaues Speicherlayout
printf("[BOOT] Code-Region: 0x%08lx - 0x%08lx\n",
(unsigned long)code_start, (unsigned long)code_end);
printf("[BOOT] Daten-Region: 0x%08lx - 0x%08lx\n",
(unsigned long)data_start, (unsigned long)data_end);
printf("[BOOT] Stack-Basis: 0x%08lx\n", (unsigned long)stack_base);
// VERWUNDBAR: Enthüllt Sicherheitskonfiguration
printf("[BOOT] Secure Boot: %s\n", secure_boot_enabled ? "aktiviert" : "deaktiviert");
printf("[BOOT] Debug-Fuse: %s\n", debug_fuse_blown ? "gebrannt" : "intakt");
// VERWUNDBAR: Enthüllt Speicherort kryptographischer Schlüssel
printf("[BOOT] Schlüsselspeicher bei: 0x%08lx\n", (unsigned long)key_storage);
}
// VERWUNDBAR: Authentifizierungs-Debug enthüllt zu viel
int vulnerable_auth_debug(const char* username, const char* password) {
const char* stored_password = get_stored_password(username);
if (stored_password == NULL) {
printf("[AUTH DEBUG] Benutzer nicht in Datenbank bei %s gefunden\n",
user_database_path); // VERWUNDBAR: Enthüllt Pfad
return -1;
}
if (strcmp(password, stored_password) != 0) {
// VERWUNDBAR: Enthüllt erwartete Passwortlänge und Speicherort
printf("[AUTH DEBUG] Passwort stimmt nicht für Benutzer '%s'\n", username);
printf("[AUTH DEBUG] Erwartetes Passwort gespeichert bei %p (Länge=%zu)\n",
stored_password, strlen(stored_password));
printf("[AUTH DEBUG] Erwartetes erstes Zeichen: '%c'\n",
stored_password[0]); // VERWUNDBAR: Teilweises Passwort!
return -1;
}
printf("[AUTH DEBUG] Erfolgreiche Auth, Sitzungsschlüssel: 0x%016llx\n",
session_key); // VERWUNDBAR: Legt Sitzungsschlüssel offen!
return 0;
}
// VERWUNDBAR: TAP-Antwort enthüllt interne Struktur
void vulnerable_tap_response(int command, int status) {
// VERWUNDBAR: Enthüllt TAP-Hierarchie wenn nur Erfolg/Fehler benötigt
printf("TAP-Antwort:\n");
printf(" Kette: CPU_TAP -> DEBUG_TAP -> TRACE_TAP\n");
printf(" IR-Länge: %d Bits\n", ir_length);
printf(" DR-Länge: %d Bits\n", dr_length);
printf(" Befehl: 0x%04x\n", command);
printf(" Interner Zustand: 0x%08x\n", internal_state);
printf(" Status: %s\n", status ? "ERFOLG" : "FEHLER");
}
# VERWUNDBAR: Python-Debug-Logging mit sensiblen Daten
import logging
import traceback
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
class VulnerablePaymentProcessor:
def __init__(self):
self.api_key = "sk_live_abc123def456" # Produktions-API-Schlüssel
def process_payment(self, card_number, cvv, amount):
# VERWUNDBAR: Protokolliert Kreditkartendetails
logger.debug(f"Zahlung verarbeiten: Karte={card_number}, CVV={cvv}, Betrag={amount}")
try:
result = self._call_payment_api(card_number, cvv, amount)
# VERWUNDBAR: Protokolliert API-Antwort mit sensiblen Daten
logger.debug(f"API-Antwort: {result}")
return result
except Exception as e:
# VERWUNDBAR: Voller Stack-Trace kann interne Pfade enthüllen
logger.debug(f"Zahlung fehlgeschlagen: {traceback.format_exc()}")
# VERWUNDBAR: Enthüllt API-Schlüssel im Fehler
logger.debug(f"Verwendeter API-Schlüssel: {self.api_key}")
raise
class VulnerableCryptoHandler:
def decrypt(self, ciphertext, key):
# VERWUNDBAR: Protokolliert kryptographischen Schlüssel
logger.debug(f"Entschlüsselung mit Schlüssel: {key.hex()}")
try:
plaintext = self._perform_decryption(ciphertext, key)
# VERWUNDBAR: Protokolliert entschlüsselte sensible Daten
logger.debug(f"Entschlüsselter Klartext: {plaintext}")
return plaintext
except Exception as e:
# VERWUNDBAR: Enthüllt internen Speicherzustand
logger.debug(f"Entschlüsselung fehlgeschlagen, Schlüsselpuffer bei: {id(key):#x}")
logger.debug(f"Chiffretextlänge: {len(ciphertext)}")
raise
Sichere Lösung
// SICHER: Debug-Nachrichten ohne sensible Informationen
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef enum {
DEBUG_LEVEL_NONE = 0,
DEBUG_LEVEL_ERROR = 1,
DEBUG_LEVEL_INFO = 2,
DEBUG_LEVEL_VERBOSE = 3
} debug_level_t;
#ifdef PRODUCTION_BUILD
static const debug_level_t current_level = DEBUG_LEVEL_ERROR;
#else
static debug_level_t current_level = DEBUG_LEVEL_VERBOSE;
#endif
// SICHER: Debug-Funktion ohne sensible Adressen
void secure_debug_memory_error(int region_id, int error_code) {
if (current_level < DEBUG_LEVEL_ERROR) return;
// SICHER: Region-ID statt tatsächlicher Adresse verwenden
printf("[FEHLER] Speicherfehler in Region %d, Code %d\n",
region_id, error_code);
// SICHER: Kein Speicherabzug in Produktion
#ifndef PRODUCTION_BUILD
if (current_level >= DEBUG_LEVEL_VERBOSE && is_debug_authenticated()) {
printf("[DEBUG] Zusätzliche Informationen über sicheres Debug verfügbar\n");
}
#endif
}
// SICHER: Boot-Log ohne sensible Details
void secure_boot_log(void) {
printf("[BOOT] System wird initialisiert...\n");
// SICHER: Generischer Status ohne Adressen
printf("[BOOT] Speicher: OK\n");
printf("[BOOT] Peripheriegeräte: OK\n");
// SICHER: Sicherheitskonfiguration nicht enthüllen
if (is_debug_authenticated()) {
printf("[BOOT] Sicherheitssubsystem: initialisiert\n");
}
}
// SICHER: Authentifizierungs-Debug ohne Geheimnisse enthüllen
int secure_auth_debug(const char* username, const char* password) {
(void)password; // Passwort überhaupt nicht protokollieren
// SICHER: Generische Fehlermeldungen
if (!user_exists(username)) {
log_auth_event("AUTH_USER_NOT_FOUND", username);
return -1;
}
if (!verify_password(username, password)) {
log_auth_event("AUTH_PASSWORD_MISMATCH", username);
// SICHER: Erwartetes Passwort oder dessen Eigenschaften nicht enthüllen
return -1;
}
// SICHER: Sitzungsschlüssel nicht protokollieren
log_auth_event("AUTH_SUCCESS", username);
return 0;
}
// SICHER: TAP-Antwort mit minimaler Information
void secure_tap_response(int status) {
// SICHER: Nur Erfolg/Fehler, keine internen Details
if (status) {
printf("TAP: OK\n");
} else {
printf("TAP: FEHL\n");
}
// SICHER: Detaillierte Info nur über authentifiziertes sicheres Debug
#ifndef PRODUCTION_BUILD
if (is_tap_debug_authenticated()) {
// Eingeschränkte zusätzliche Info für authentifiziertes Debug
printf("TAP: Zusätzliche Diagnose verfügbar\n");
}
#endif
}
// SICHER: Sicheres Debug mit Authentifizierung
typedef struct {
uint8_t challenge[32];
uint8_t response[32];
bool authenticated;
} debug_session_t;
static debug_session_t debug_session = {0};
bool is_debug_authenticated(void) {
return debug_session.authenticated;
}
bool authenticate_debug_session(const uint8_t* response) {
// Challenge-Response vor Aktivierung des ausführlichen Debug verifizieren
if (verify_debug_challenge(debug_session.challenge, response)) {
debug_session.authenticated = true;
return true;
}
return false;
}
# SICHER: Python sicheres Debug-Logging
import logging
import os
class SanitizedFormatter(logging.Formatter):
"""Benutzerdefinierter Formatter, der sensible Daten bereinigt."""
SENSITIVE_PATTERNS = [
'password', 'key', 'secret', 'token', 'card', 'cvv', 'ssn'
]
def format(self, record):
msg = super().format(record)
# Potenziell sensible Daten bereinigen
for pattern in self.SENSITIVE_PATTERNS:
import re
msg = re.sub(
rf'{pattern}["\']?\s*[:=]\s*["\']?[^"\'\s,}}]+',
f'{pattern}=[GESCHWÄRZT]',
msg,
flags=re.IGNORECASE
)
return msg
# SICHER: Produktions-Logger-Konfiguration
def get_secure_logger(name):
logger = logging.getLogger(name)
if os.environ.get('PRODUCTION'):
logger.setLevel(logging.INFO)
else:
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setFormatter(SanitizedFormatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
))
logger.addHandler(handler)
return logger
logger = get_secure_logger(__name__)
class SecurePaymentProcessor:
def __init__(self):
self.api_key = os.environ.get('PAYMENT_API_KEY')
def process_payment(self, card_number, cvv, amount):
# SICHER: Nur nicht-sensible Bezeichner protokollieren
masked_card = f"****{card_number[-4:]}" if len(card_number) >= 4 else "****"
logger.info(f"Zahlung verarbeiten: Karte={masked_card}, Betrag={amount}")
try:
result = self._call_payment_api(card_number, cvv, amount)
# SICHER: Nur Transaktionsstatus protokollieren
logger.info(f"Zahlung abgeschlossen: Transaktions-ID={result.get('id')}")
return result
except Exception as e:
# SICHER: Generischer Fehler ohne interne Details
logger.error(f"Zahlung fehlgeschlagen: {type(e).__name__}")
# SICHER: Bei Bedarf in separates sicheres Audit-Log schreiben
self._audit_log_payment_failure(masked_card, amount)
raise
class SecureCryptoHandler:
def decrypt(self, ciphertext, key):
# SICHER: Niemals kryptographische Schlüssel protokollieren
logger.debug(f"Daten entschlüsseln, Chiffretextlänge={len(ciphertext)}")
try:
plaintext = self._perform_decryption(ciphertext, key)
# SICHER: Niemals entschlüsselte sensible Daten protokollieren
logger.debug("Entschlüsselung erfolgreich")
return plaintext
except Exception as e:
# SICHER: Generischer Fehler ohne Speicherdetails
logger.error(f"Entschlüsselung fehlgeschlagen: {type(e).__name__}")
raise
def _audit_log(self, operation, success):
"""Sicheres Audit-Log ohne sensible Details."""
# Nur Operationstyp und Ergebnis protokollieren
audit_entry = {
'operation': operation,
'success': success,
'timestamp': time.time()
}
secure_audit_write(audit_entry)
CVE-Beispiele
- CVE-2021-25476: DRM gibt Pointer-Informationen preis, was ASLR-Umgehung ermöglicht.
- CVE-2020-24491: Prozessor-Debug-Nachricht enthält Speichertransaktionsadressen.
- CVE-2017-18326: Modem-Debug-Nachrichten enthalten kryptographische Schlüssel.
Verwandte CWEs
- CWE-200: Offenlegung sensibler Informationen an unbefugten Akteur (übergeordnet)
- CWE-209: Generierung von Fehlermeldungen mit sensiblen Informationen (gleichrangig)
- CWE-1207: Debug- und Testprobleme (Kategorie)
- CWE-532: Einfügung sensibler Informationen in Logdatei (verwandt)
Referenzen
- MITRE Corporation. "CWE-1295: Debug Messages Revealing Unnecessary Information." https://cwe.mitre.org/data/definitions/1295.html
- OWASP. "Information Exposure Through Debug Information"
- NIST. "SP 800-123 Guide to General Server Security"