Offenlegung sensibler Systeminformationen durch nicht gelöschte Debug-Informationen

Beschreibung

Offenlegung sensibler Systeminformationen durch nicht gelöschte Debug-Informationen tritt auf, wenn Hardware sicherheitsrelevante Werte -- wie kryptografische Schlüssel und Zwischenwerte -- beim Aktivieren des Debug-Modus nicht vollständig löscht. Sensible Daten, die in temporären Hardware-Registern gespeichert sind, werden für Debugger zugänglich, wenn sie beim Eintritt in den Debug-Modus nicht gelöscht werden, wodurch potenziell kryptografische Geheimnisse an nicht vertrauenswürdige Parteien offengelegt werden, die Debug-Zugriff erlangen.

Risiko

Nicht gelöschte Debug-Informationen haben schwerwiegende Sicherheitsauswirkungen. Kryptografische Schlüssel können für Debugger offengelegt werden. Zwischenwerte von Berechnungen können Geheimnisse offenbaren. Authentifizierungstoken können lesbar sein. Secure-Boot-Schlüssel können kompromittiert werden. Sitzungsschlüssel können extrahiert werden. Private Schlüssel können geleakt werden. Hardware-Sicherheitsmodule können umgangen werden. Vertrauensanker können durch Debug-Zugriff kompromittiert werden.

Lösung

Wann immer der Debug-Modus aktiviert wird, müssen alle Register, die sensible Daten enthalten, gelöscht werden. Implementieren Sie hardware-erzwungenes Löschen sensibler Register beim Debug-Eintritt. Löschen Sie alle Schlüsselspeicher, Zwischenwerte und Sicherheitszustande. Füllen Sie sensible Speicherbereiche mit Nullen, bevor Debug-Zugriff gewährt wird. Überprüfen Sie die Vollständigkeit des Löschens, bevor Debug-Operationen erlaubt werden. Erwägen Sie, Debug-Zugriff vollständig zu verhindern, wenn sensible Daten vorhanden sind.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitUmfang: Vertraulichkeit

Speicher lesen - Sensible Daten einschließlich kryptografischer Schlüssel können über Debug-Schnittstelle gelesen werden.
ZugriffskontrolleUmfang: Zugriffskontrolle

Schutzmechanismus umgehen - Debug-Zugriff auf Schlüssel ermöglicht die Umgehung von Verschlüsselung und Authentifizierung.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Unvollständige Schlüssellöschung bei Debug-Modus

module vulnerable_aes_wrapper (
    input wire clk,
    input wire reset_n,
    input wire debug_mode,
    input wire [127:0] key0_in,
    input wire [127:0] key1_in,
    input wire key_load,
    input wire [127:0] plaintext,
    input wire encrypt_start,
    output wire [127:0] ciphertext,
    output wire done
);

    // Interner Schlüsselspeicher
    reg [127:0] core_key0;
    reg [127:0] core_key1;

    // Zwischenwerte
    reg [127:0] round_key;
    reg [127:0] state;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            core_key0 <= 128'h0;
            core_key1 <= 128'h0;
            round_key <= 128'h0;
            state <= 128'h0;
        end
        else if (debug_mode) begin
            // VERWUNDBAR: Löscht nur einen Schlüssel, vergisst den anderen!
            core_key0 <= 128'h0;
            // core_key1 NICHT gelöscht - für Debugger offengelegt!
            // round_key NICHT gelöscht - Zwischenwerte offengelegt!
            // state NICHT gelöscht - Verschlüsselungszustand offengelegt!
        end
        else if (key_load) begin
            core_key0 <= key0_in;
            core_key1 <= key1_in;
        end
    end

    // AES-Kern-Instanziierung
    aes_core aes_inst (
        .clk(clk),
        .key0(core_key0),
        .key1(core_key1),  // VERWUNDBAR: Im Debug-Modus zugänglich
        .plaintext(plaintext),
        .ciphertext(ciphertext),
        .done(done)
    );

endmodule

// VERWUNDBAR: Debug-Register mit Schlüsseloffenlegung
module vulnerable_debug_interface (
    input wire clk,
    input wire reset_n,
    input wire debug_enable,
    input wire [7:0] debug_addr,
    input wire debug_read,
    output reg [31:0] debug_data
);

    // Sensible Register, die nicht lesbar sein sollten
    reg [127:0] secret_key;
    reg [127:0] session_key;
    reg [31:0] auth_token;

    // VERWUNDBAR: Debug kann alle Register lesen
    always @(posedge clk) begin
        if (debug_enable && debug_read) begin
            case (debug_addr)
                8'h00: debug_data <= secret_key[31:0];    // VERWUNDBAR!
                8'h04: debug_data <= secret_key[63:32];   // VERWUNDBAR!
                8'h08: debug_data <= secret_key[95:64];   // VERWUNDBAR!
                8'h0C: debug_data <= secret_key[127:96];  // VERWUNDBAR!
                8'h10: debug_data <= session_key[31:0];   // VERWUNDBAR!
                8'h20: debug_data <= auth_token;          // VERWUNDBAR!
                default: debug_data <= 32'h0;
            endcase
        end
    end

endmodule
// VERWUNDBAR: Software-Debug-Handler ohne Löschung

#include <stdint.h>

typedef struct {
    uint8_t aes_key[32];
    uint8_t hmac_key[32];
    uint8_t session_key[32];
    uint8_t intermediate_state[64];
} crypto_context_t;

volatile crypto_context_t* crypto_ctx = (volatile crypto_context_t*)0x40000000;

void vulnerable_enter_debug_mode(void) {
    // VERWUNDBAR: Tritt in Debug-Modus ein, ohne sensible Daten zu löschen

    // Debug-Zugriff aktivieren
    DEBUG_CTRL |= DEBUG_ENABLE;

    // VERWUNDBAR: Schlüssel und Zustand verbleiben im Speicher
    // Debugger kann jetzt crypto_ctx->aes_key lesen, etc.

    // Debug-Bereitschaft signalisieren
    DEBUG_STATUS = DEBUG_READY;
}

void vulnerable_debug_read(uint32_t addr, uint32_t* value) {
    // VERWUNDBAR: Keine Filterung sensibler Adressen
    *value = *(volatile uint32_t*)addr;
    // Debugger kann jeden Speicher einschließlich Schlüssel lesen
}

Sichere Lösung

// SICHER: Vollständige Schlüssellöschung bei Debug-Modus

module secure_aes_wrapper (
    input wire clk,
    input wire reset_n,
    input wire debug_mode,
    input wire [127:0] key0_in,
    input wire [127:0] key1_in,
    input wire key_load,
    input wire [127:0] plaintext,
    input wire encrypt_start,
    output wire [127:0] ciphertext,
    output wire done,
    output reg debug_ready  // Zeigt an, dass Debug sicher ist
);

    // Interner Schlüsselspeicher
    reg [127:0] core_key0;
    reg [127:0] core_key1;

    // Zwischenwerte
    reg [127:0] round_key;
    reg [127:0] state;

    // Zusätzlicher sensibler Zustand
    reg [127:0] key_schedule [0:10];
    reg [127:0] temp_buffer;

    // SICHER: Löschungsabschluss verfolgen
    reg clearing_in_progress;
    reg [3:0] clear_counter;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            core_key0 <= 128'h0;
            core_key1 <= 128'h0;
            round_key <= 128'h0;
            state <= 128'h0;
            temp_buffer <= 128'h0;
            clearing_in_progress <= 1'b0;
            clear_counter <= 4'h0;
            debug_ready <= 1'b0;
        end
        else if (debug_mode) begin
            // SICHER: ALLE sensiblen Register löschen
            core_key0 <= 128'h0;
            core_key1 <= 128'h0;
            round_key <= 128'h0;
            state <= 128'h0;
            temp_buffer <= 128'h0;

            // SICHER: Schlüsselplan-Array löschen
            if (clear_counter < 4'd11) begin
                key_schedule[clear_counter] <= 128'h0;
                clear_counter <= clear_counter + 1;
                clearing_in_progress <= 1'b1;
                debug_ready <= 1'b0;
            end
            else begin
                // SICHER: Alles gelöscht, sicher für Debug
                clearing_in_progress <= 1'b0;
                debug_ready <= 1'b1;
            end
        end
        else begin
            clear_counter <= 4'h0;
            debug_ready <= 1'b0;

            if (key_load) begin
                core_key0 <= key0_in;
                core_key1 <= key1_in;
            end
        end
    end

    // SICHER: Debug-Zugriff sperren bis Löschung abgeschlossen
    wire debug_access_allowed = debug_mode && debug_ready && !clearing_in_progress;

    // AES-Kern mit geschützten Schlüsseln
    aes_core aes_inst (
        .clk(clk),
        .key0(debug_mode ? 128'h0 : core_key0),  // SICHER: Null während Debug
        .key1(debug_mode ? 128'h0 : core_key1),  // SICHER: Null während Debug
        .plaintext(plaintext),
        .ciphertext(ciphertext),
        .done(done)
    );

endmodule

// SICHER: Debug-Schnittstelle mit geschützten Registern
module secure_debug_interface (
    input wire clk,
    input wire reset_n,
    input wire debug_enable,
    input wire [7:0] debug_addr,
    input wire debug_read,
    output reg [31:0] debug_data,
    output reg access_denied
);

    // Sensible Register
    reg [127:0] secret_key;
    reg [127:0] session_key;
    reg [31:0] auth_token;

    // SICHER: Nicht-sensible Debug-Register
    reg [31:0] debug_status;
    reg [31:0] debug_version;
    reg [31:0] debug_counter;

    // SICHER: Sensibler Adressbereich
    wire is_sensitive_addr = (debug_addr >= 8'h00) && (debug_addr < 8'h30);

    // SICHER: Löschungszustand
    reg sensitive_data_present;
    reg clearing_complete;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            secret_key <= 128'h0;
            session_key <= 128'h0;
            auth_token <= 32'h0;
            sensitive_data_present <= 1'b0;
            clearing_complete <= 1'b1;
            debug_data <= 32'h0;
            access_denied <= 1'b0;
        end
        else if (debug_enable) begin
            // SICHER: Alle sensiblen Daten löschen wenn Debug aktiviert
            if (!clearing_complete) begin
                secret_key <= 128'h0;
                session_key <= 128'h0;
                auth_token <= 32'h0;
                clearing_complete <= 1'b1;
                sensitive_data_present <= 1'b0;
            end

            if (debug_read) begin
                // SICHER: Zugriff auf sensible Adressen blockieren
                if (is_sensitive_addr) begin
                    debug_data <= 32'hDEADBEEF;  // Dummy-Wert zurückgeben
                    access_denied <= 1'b1;
                end
                else begin
                    // Zugriff auf nicht-sensible Debug-Register erlauben
                    case (debug_addr)
                        8'h80: debug_data <= debug_status;
                        8'h84: debug_data <= debug_version;
                        8'h88: debug_data <= debug_counter;
                        default: debug_data <= 32'h0;
                    endcase
                    access_denied <= 1'b0;
                end
            end
        end
        else begin
            clearing_complete <= 1'b0;  // Für nächste Debug-Sitzung zurücksetzen
            access_denied <= 1'b0;
        end
    end

endmodule
// SICHER: Software-Debug-Handler mit ordnungsgemäßer Löschung

#include <stdint.h>
#include <string.h>

typedef struct {
    uint8_t aes_key[32];
    uint8_t hmac_key[32];
    uint8_t session_key[32];
    uint8_t intermediate_state[64];
} crypto_context_t;

volatile crypto_context_t* crypto_ctx = (volatile crypto_context_t*)0x40000000;

// SICHER: Sichere Speicherlöschung, die nicht wegoptimiert werden kann
static void secure_zero(volatile void* ptr, size_t size) {
    volatile uint8_t* p = (volatile uint8_t*)ptr;
    while (size--) {
        *p++ = 0;
    }
    // Speicherbarriere, um sicherzustellen, dass Löschung abgeschlossen wird
    __asm__ volatile("" ::: "memory");
}

void secure_enter_debug_mode(void) {
    // SICHER: Alle sensiblen Daten vor Debug-Aktivierung löschen

    // Kryptografische Schlüssel löschen
    secure_zero(crypto_ctx->aes_key, sizeof(crypto_ctx->aes_key));
    secure_zero(crypto_ctx->hmac_key, sizeof(crypto_ctx->hmac_key));
    secure_zero(crypto_ctx->session_key, sizeof(crypto_ctx->session_key));

    // Zwischenzustand löschen
    secure_zero(crypto_ctx->intermediate_state, sizeof(crypto_ctx->intermediate_state));

    // SICHER: Alle anderen sensiblen Speicherbereiche löschen
    clear_key_cache();
    clear_pending_operations();
    clear_temporary_buffers();

    // Speicherbarriere vor Debug-Aktivierung
    __sync_synchronize();

    // Löschungsabschluss überprüfen
    if (!verify_sensitive_memory_cleared()) {
        // Löschung fehlgeschlagen - Debug nicht aktivieren
        DEBUG_STATUS = DEBUG_ERROR;
        return;
    }

    // SICHER: Jetzt sicher Debug-Zugriff zu aktivieren
    DEBUG_CTRL |= DEBUG_ENABLE;
    DEBUG_STATUS = DEBUG_READY;
}

// SICHER: Gefilterter Debug-Lesevorgang mit Adressvalidierung
int secure_debug_read(uint32_t addr, uint32_t* value) {
    // Geschützte Adressbereiche definieren
    static const struct {
        uint32_t start;
        uint32_t end;
    } protected_ranges[] = {
        {0x40000000, 0x40000100},  // Krypto-Kontext
        {0x40001000, 0x40001100},  // Schlüsselspeicher
        {0x40002000, 0x40002100},  // Sitzungsdaten
    };

    // SICHER: Prüfen, ob Adresse im geschützten Bereich liegt
    for (int i = 0; i < sizeof(protected_ranges)/sizeof(protected_ranges[0]); i++) {
        if (addr >= protected_ranges[i].start && addr < protected_ranges[i].end) {
            // Null statt tatsächlichem Wert zurückgeben
            *value = 0;
            log_debug_blocked_access(addr);
            return -EACCES;
        }
    }

    // Adresse ist nicht geschützt, Lesen erlauben
    *value = *(volatile uint32_t*)addr;
    return 0;
}

// SICHER: Überprüfung, dass sensibler Speicher gelöscht ist
static bool verify_sensitive_memory_cleared(void) {
    volatile uint8_t* p = (volatile uint8_t*)crypto_ctx;
    size_t size = sizeof(crypto_context_t);

    for (size_t i = 0; i < size; i++) {
        if (p[i] != 0) {
            return false;
        }
    }
    return true;
}

CVE-Beispiele

  • CVE-2021-33080: Nicht gelöschte Debug-Informationen im SSD-Speicherbeschleuniger legten sensible Daten offen
  • CVE-2022-31162: Rust-Bibliothek leakt OAuth-Details in Debug-Logs

Verwandte CWEs

  • CWE-212: Unsachgemäße Entfernung sensibler Informationen vor Speicherung oder Übertragung (übergeordnet)
  • CWE-1272: Sensible Informationen nicht gelöscht vor Debug-/Energiezustandsübergang (verwandt)
  • CWE-1244: Internes Asset unsicherem Debug-Zugriffslevel oder -zustand ausgesetzt (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1258: Exposure of Sensitive System Information Due to Uncleared Debug Information." https://cwe.mitre.org/data/definitions/1258.html
  2. NIST. "Guidelines for Hardware Security"
  3. Common Criteria. "Protection Profile for Hardware Security Modules"