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

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Sensible Speicherinhalte und kryptographische Schlüssel können offengelegt werden.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismen können mit enthüllten Informationen umgangen werden.
AuthentifizierungBereich: 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

  1. MITRE Corporation. "CWE-1295: Debug Messages Revealing Unnecessary Information." https://cwe.mitre.org/data/definitions/1295.html
  2. OWASP. "Information Exposure Through Debug Information"
  3. NIST. "SP 800-123 Guide to General Server Security"