Unsachgemäßer Schutz gegen Spannungs- und Taktglitches

Beschreibung

Unsachgemäßer Schutz gegen Spannungs- und Taktglitches tritt auf, wenn einem Gerät geeignete Schaltungen oder Sensoren fehlen, um Spannungs- und Taktglitches zu erkennen und abzuwehren, die sensible Informationen oder Software kompromittieren könnten. Geräte, die Sicherheitsfunktionen wie Secure Boot implementieren, etablieren eine Vertrauenskette durch Signaturüberprüfung vor der Ausführung nachfolgender Stufen. Hardware und Firmware arbeiten zusammen, um sichere Zustände über Zugriffskontrolleinstellungen zu konfigurieren. Ohne geeignete Abwehrmaßnahmen können Angreifer jedoch Fault-Injection-Techniken -- insbesondere Spannungs- und Taktglitches -- ausnutzen, um diese Sicherheitsmaßnahmen zu umgehen.

Risiko

Anfälligkeit für Glitch-Angriffe hat schwerwiegende Sicherheitsauswirkungen. Secure Boot kann umgangen werden. Signaturüberprüfung kann ausgehebelt werden. Zugriffskontrollentscheidungen können korrumpiert werden. Kryptografische Operationen können falsche Ergebnisse liefern. Sicherheitszustandsautomaten können Zustände überspringen. Debug-Sperren können umgangen werden. Privilege Escalation kann möglich sein. Beliebige Codeausführung kann erreicht werden.

Lösung

Implementieren Sie Tunable Replica Circuits (TRCs) oder Razor-Flip-Flops zur Erkennung von Timing-Verletzungen. Setzen Sie plattformweite Glitch-Erkennungssensoren ein. Fügen Sie Redundanz zu sicherheitskritischen Codeabschnitten hinzu. Implementieren Sie doppelte Überprüfung von Sicherheitsentscheidungen. Verwenden Sie fehlererkennende Codes für kritische Daten. Fügen Sie Spannungs- und Taktüberwachung hinzu. Gestalten Sie Sicherheitsüberprüfungen glitch-resistent. Erwägen Sie Hardware-Sicherheitsmodule für kritische Operationen.

Häufige Auswirkungen

AuswirkungDetails
Vertraulichkeit, Integrität, Verfügbarkeit, ZugriffskontrolleUmfang: Alle

Mehrere Auswirkungen einschließlich Privilege Escalation, Umgehung von Schutzmechanismen, unbefugtem Speicherzugriff und beliebiger Codeausführung.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Einzelne Sicherheitsüberprüfung leicht durch Glitch umgehbar

bool verify_firmware_signature(const uint8_t* firmware, size_t size,
                                const uint8_t* signature) {
    // VERWUNDBAR: Einzelner Ausfallpunkt für Glitch-Angriff
    bool valid = crypto_verify_signature(firmware, size, signature, public_key);

    if (valid) {  // <-- GLITCH-ZIEL: Diese Prüfung überspringen
        return true;
    } else {
        return false;
    }
}

void vulnerable_secure_boot(void) {
    load_firmware_to_memory();

    // VERWUNDBAR: Einzelne Signaturprüfung
    if (verify_firmware_signature(firmware, fw_size, fw_signature)) {
        // Angreifer glitcht hier, um Überprüfung zu überspringen
        execute_firmware();
    } else {
        halt_boot();
    }
}

// VERWUNDBAR: Sicherheitsentscheidung basierend auf einzelnem Vergleich
void vulnerable_password_check(const char* input) {
    // VERWUNDBAR: Einzelner Vergleich, Glitch kann umgehen
    if (strcmp(input, stored_password) == 0) {  // <-- GLITCH-ZIEL
        grant_access();
    } else {
        deny_access();
    }
}

// VERWUNDBAR: Sicherheitsflag leicht korrumpierbar
volatile bool security_enabled = true;

void vulnerable_security_gate(void) {
    // VERWUNDBAR: Einzelne Flag-Prüfung
    if (security_enabled) {  // <-- GLITCH kann dieses Lesen korrumpieren
        enforce_security_policy();
    }
    // Wenn Glitch security_enabled als false liest, Sicherheit umgangen
}
// VERWUNDBAR: Sicherheitszustandsautomat ohne Glitch-Schutz

module vulnerable_secure_boot_fsm (
    input wire clk,
    input wire reset_n,
    input wire signature_valid,
    output reg boot_authorized,
    output reg [2:0] boot_state
);

    parameter IDLE = 3'h0;
    parameter VERIFY = 3'h1;
    parameter AUTHORIZED = 3'h2;
    parameter DENIED = 3'h3;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            boot_state <= IDLE;
            boot_authorized <= 1'b0;
        end
        else begin
            case (boot_state)
                IDLE: begin
                    boot_state <= VERIFY;
                end

                VERIFY: begin
                    // VERWUNDBAR: Einzelne Prüfung, keine Redundanz
                    if (signature_valid) begin  // <-- GLITCH-ZIEL
                        boot_state <= AUTHORIZED;
                        boot_authorized <= 1'b1;
                    end else begin
                        boot_state <= DENIED;
                    end
                end

                AUTHORIZED: begin
                    // Boot fortsetzen
                end

                DENIED: begin
                    // Boot angehalten
                end
            endcase
        end
    end

endmodule

// VERWUNDBAR: Keine Spannungs-/Taktglitch-Erkennung
module vulnerable_crypto_core (
    input wire clk,
    input wire reset_n,
    input wire [127:0] data_in,
    input wire [127:0] key,
    output reg [127:0] data_out
);

    // VERWUNDBAR: Keine Glitch-Erkennung
    // Glitch während Krypto-Operation kann falsche/schwache Ausgabe erzeugen

    always @(posedge clk) begin
        data_out <= aes_encrypt(data_in, key);
        // Wenn Takt geglitcht, könnte Verschlüsselung unvollständig/falsch sein
    end

endmodule

Sichere Lösung

// SICHER: Redundante Sicherheitsüberprüfungen widerstehen Glitch-Angriffen

bool verify_firmware_signature_secure(const uint8_t* firmware, size_t size,
                                       const uint8_t* signature) {
    // SICHER: Mehrere unabhängige Überprüfungsdurchläufe
    volatile bool valid1 = crypto_verify_signature(firmware, size, signature, public_key);

    // Zeitlichen Jitter hinzufügen, um Glitch-Timing zu erschweren
    random_delay();

    volatile bool valid2 = crypto_verify_signature(firmware, size, signature, public_key);

    // Andere Überprüfungsmethode
    volatile bool valid3 = crypto_verify_signature_alt(firmware, size, signature, public_key);

    // SICHER: Alle drei müssen übereinstimmen
    if (valid1 && valid2 && valid3) {
        // Dreifache Überprüfung der Entscheidung
        if (valid1 == true && valid2 == true && valid3 == true) {
            return true;
        }
    }

    return false;
}

void secure_boot_with_redundancy(void) {
    load_firmware_to_memory();

    // SICHER: Mehrfache Überprüfung mit unterschiedlichem Timing
    volatile int verify_count = 0;

    for (int i = 0; i < 3; i++) {
        random_delay();  // Variables Timing

        if (verify_firmware_signature(firmware, fw_size, fw_signature)) {
            verify_count++;
        }
    }

    // SICHER: Alle Überprüfungen müssen bestehen
    if (verify_count == 3) {
        // Abschließende Prüfung vor Ausführung
        if (verify_count == 3) {
            execute_firmware();
        }
    } else {
        halt_boot();
    }
}

// SICHER: Glitch-resistenter Vergleich
bool secure_compare(const char* a, const char* b, size_t len) {
    volatile uint8_t result = 0;
    volatile uint8_t result2 = 0;

    // Erster Durchlauf
    for (size_t i = 0; i < len; i++) {
        result |= a[i] ^ b[i];
    }

    random_delay();

    // Zweiter Durchlauf (ändere Richtung)
    for (size_t i = len; i > 0; i--) {
        result2 |= a[i-1] ^ b[i-1];
    }

    // Beide müssen Übereinstimmung anzeigen
    return (result == 0) && (result2 == 0) && (result == result2);
}

// SICHER: Sicherheitsflag mit Redundanz
volatile bool security_enabled_1 = true;
volatile bool security_enabled_2 = true;
volatile uint32_t security_checksum = SECURITY_ENABLED_CHECKSUM;

void secure_security_gate(void) {
    // SICHER: Mehrere Flags und Prüfsumme
    bool flag1 = security_enabled_1;
    bool flag2 = security_enabled_2;
    bool checksum_valid = (security_checksum == SECURITY_ENABLED_CHECKSUM);

    // Alle drei müssen übereinstimmen
    if (flag1 && flag2 && checksum_valid) {
        if (flag1 == flag2) {
            enforce_security_policy();
        }
    } else {
        // Inkonsistenz erkannt - möglicher Angriff
        security_violation_handler();
    }
}
// SICHER: Sicherheitszustandsautomat mit Glitch-Erkennung

module secure_boot_fsm (
    input wire clk,
    input wire reset_n,
    input wire signature_valid,
    input wire voltage_glitch_detected,
    input wire clock_glitch_detected,
    output reg boot_authorized,
    output reg [2:0] boot_state,
    output reg security_violation
);

    parameter IDLE = 3'h0;
    parameter VERIFY_1 = 3'h1;
    parameter VERIFY_2 = 3'h2;
    parameter VERIFY_3 = 3'h3;
    parameter AUTHORIZED = 3'h4;
    parameter DENIED = 3'h5;

    reg [2:0] verify_count;
    reg [2:0] verify_pass_count;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            boot_state <= IDLE;
            boot_authorized <= 1'b0;
            security_violation <= 1'b0;
            verify_count <= 3'h0;
            verify_pass_count <= 3'h0;
        end
        // SICHER: Auf Glitch-Angriffe prüfen
        else if (voltage_glitch_detected || clock_glitch_detected) begin
            boot_state <= DENIED;
            security_violation <= 1'b1;
            boot_authorized <= 1'b0;
        end
        else begin
            case (boot_state)
                IDLE: begin
                    boot_state <= VERIFY_1;
                    verify_count <= 3'h0;
                    verify_pass_count <= 3'h0;
                end

                VERIFY_1: begin
                    // SICHER: Erste Überprüfung
                    if (signature_valid) verify_pass_count <= verify_pass_count + 1;
                    boot_state <= VERIFY_2;
                end

                VERIFY_2: begin
                    // SICHER: Zweite Überprüfung (anderes Timing)
                    if (signature_valid) verify_pass_count <= verify_pass_count + 1;
                    boot_state <= VERIFY_3;
                end

                VERIFY_3: begin
                    // SICHER: Dritte Überprüfung
                    if (signature_valid) verify_pass_count <= verify_pass_count + 1;

                    // SICHER: Alle drei Überprüfungen müssen bestehen
                    if (verify_pass_count == 3'd2 && signature_valid) begin
                        boot_state <= AUTHORIZED;
                        boot_authorized <= 1'b1;
                    end else begin
                        boot_state <= DENIED;
                    end
                end

                AUTHORIZED: begin
                    // Weiterhin auf Glitches überwachen
                    if (voltage_glitch_detected || clock_glitch_detected) begin
                        boot_authorized <= 1'b0;
                        security_violation <= 1'b1;
                    end
                end

                DENIED: begin
                    boot_authorized <= 1'b0;
                end
            endcase
        end
    end

endmodule

// SICHER: Glitch-Erkennungsschaltung
module glitch_detector (
    input wire clk,
    input wire reset_n,
    input wire voltage_sense,
    input wire clock_in,
    output reg voltage_glitch,
    output reg clock_glitch
);

    // Spannungsglitch-Erkennung mittels Fensterkomparator
    reg [7:0] voltage_history;
    parameter VOLTAGE_MIN = 8'd100;
    parameter VOLTAGE_MAX = 8'd200;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            voltage_glitch <= 1'b0;
        end
        else begin
            // Spannung außerhalb des Normalbereichs erkennen
            if (voltage_sense < VOLTAGE_MIN || voltage_sense > VOLTAGE_MAX) begin
                voltage_glitch <= 1'b1;
            end
        end
    end

    // Taktglitch-Erkennung nach Razor-Flip-Flop-Konzept
    reg clock_sample_1, clock_sample_2;
    reg clock_edge_count;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            clock_glitch <= 1'b0;
            clock_sample_1 <= 1'b0;
            clock_sample_2 <= 1'b0;
        end
        else begin
            clock_sample_1 <= clock_in;
            clock_sample_2 <= clock_sample_1;

            // Unerwartete Taktflanken erkennen
            if (clock_sample_1 != clock_sample_2) begin
                clock_edge_count <= clock_edge_count + 1;
                if (clock_edge_count > expected_edges) begin
                    clock_glitch <= 1'b1;
                end
            end
        end
    end

endmodule

CVE-Beispiele

  • CVE-2019-17391: Secure-Boot-Umgehung durch fehlenden Anti-Glitch-Schutz
  • CVE-2021-33478: Boot-Shell-Zugriff durch Impulsangriffe
  • Plundervolt- und CLKSCREW-Angriffe, die DVFS-Schnittstellen ausnutzen

Verwandte CWEs

  • CWE-1384: Unsachgemäße Behandlung physischer oder umgebungsbedingter Zustände (übergeordnet)
  • CWE-1332: Unsachgemäße Behandlung von Fehlern, die zu Instruktionsübersprüngen führen (gleichrangig)
  • CWE-1256: Privilegierter Zugriff auf Energieverwaltungsfunktionen (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1247: Improper Protection Against Voltage and Clock Glitches." https://cwe.mitre.org/data/definitions/1247.html
  2. Plundervolt Attack Research
  3. CLKSCREW: Exploiting DVFS for Security Bypass