Firmware nicht aktualisierbar

Beschreibung

Firmware nicht aktualisierbar tritt auf, wenn einem Produkt die Fahigkeit fehlt, Firmware zu aktualisieren oder zu patchen, um Schwachstellen oder Schwachen zu beheben. Dies erzeugt permanentes Risiko über die gesamte Lebensdauer des Gerats, die potenziell Jahre oder Jahrzehnte umfassen kann, da Verbraucher verwundbar gegenüber der Ausnutzung bekannter Schwachstellen oder zukunftig entdeckter Schwachstellen bleiben. Ohne die Möglichkeit, Firmware zu patchen oder zu aktualisieren, kann eine ausnutzbare Schwachstelle in einem ungepatchten Gerat gegen eine gesamte Geräteklasse eingesetzt werden.

Risiko

Nicht aktualisierbare Firmware hat schwerwiegende Sicherheitsauswirkungen. Bekannte Schwachstellen können nicht behoben werden. Zukunftige Schwachstellen können nicht adressiert werden. Gerate werden dauerhaft kompromittiert. Angriffswerkzeuge können für gesamte Produktlinien entwickelt werden. Botnets können verwundbare Gerate rekrutieren. Compliance-Anforderungen können verletzt werden. Produkthaftung kann zunehmen. Verbrauchervertrauen wird untergraben.

Lösung

Spezifizieren Sie Firmware-Aktualisierungsfahigkeit mit Integritatsprüfungen und Authentifizierung, um nicht vertrauenswurdige Installationen während der Anforderungsphase zu verhindern. Entwerfen Sie Gerate, die Firmware-Updates erlauben, und spezifizieren Sie Verteilungs-, Integritits- und Authentifizierungsmethoden während Architektur und Design. Implementieren Sie die erforderliche Funktionalitat für Firmware-Updates einschließlich sicherer Boot-Chain-Verifizierung. Testen Sie die Aktualisierungsfahigkeit grundlich einschließlich der Ablehnung ungültiger Images.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitUmfang: Vertraulichkeit

Speicher lesen - Ungepatchte Schwachstellen ermöglichen Datendiebstahl.
IntegritatUmfang: Integritat

Unbefugten Code ausführen - Malware kann permanent installiert werden.
VerfügbarkeitUmfang: Verfügbarkeit

DoS - Gerate können unbrauchbar gemacht werden.
ZugriffskontrolleUmfang: Zugriffskontrolle

Berechtigungen erlangen - Angreifer können volle Geratekontrolle erlangen.
AuthentifizierungUmfang: Authentifizierung

Schutzmechanismus umgehen - Sicherheitsfunktionen können nicht verbessert werden.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Gerat mit nur-ROM-Firmware

module vulnerable_rom_device (
    input wire clk,
    input wire reset_n,
    input wire [15:0] addr,
    output reg [31:0] data,
    // Keine Firmware-Update-Schnittstelle
    output reg device_ready
);

    // VERWUNDBAR: Firmware im ROM - kann nicht aktualisiert werden
    reg [31:0] firmware_rom [0:16383];

    // ROM wird bei der Fertigung initialisiert - ändert sich nie
    initial begin
        $readmemh("firmware.hex", firmware_rom);
    end

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            device_ready <= 1'b0;
        end
        else begin
            // VERWUNDBAR: Kann nur aus ROM lesen
            data <= firmware_rom[addr];
            device_ready <= 1'b1;

            // Kein Mechanismus zum Aktualisieren der Firmware
            // Wenn Schwachstelle gefunden wird, ist Gerat permanent gefährdet
        end
    end

    // Keine Update-Schnittstelle vorhanden
    // Keine Flash-Programmierfahigkeit
    // Kein Secure Boot zur Verifizierung neuer Firmware

endmodule

// VERWUNDBAR: Mikrocontroller mit gesperrtem Flash
module vulnerable_locked_mcu (
    input wire clk,
    input wire reset_n,
    // Flash ist permanent gesperrt
    input wire [15:0] flash_addr,
    output reg [31:0] flash_data
);

    // Flash-Speicher
    reg [31:0] flash_mem [0:32767];

    // VERWUNDBAR: Sperr-Fuse gebrannt - Flash kann nicht umprogrammiert werden
    wire flash_locked = 1'b1;  // Permanent gesperrt

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            // Von Flash initialisieren
        end
        else begin
            // VERWUNDBAR: Schreiboperationen blockiert
            // flash_mem[flash_addr] <= write_data;  // Nicht möglich

            // Nur Lesen
            flash_data <= flash_mem[flash_addr];
        end
    end

    // Gerat kann keine Sicherheitsupdates empfangen
    // Bekannte Schwachstellen können nicht gepatcht werden

endmodule
// VERWUNDBAR: IoT-Gerat ohne Aktualisierungsfahigkeit

#include <stdint.h>

// VERWUNDBAR: Kein Firmware-Aktualisierungsmechanismus

void vulnerable_device_main(void) {
    // Gerateinitialisierung
    init_hardware();
    init_network();

    // Hauptschleife - führt dieselbe Firmware für immer aus
    while (1) {
        process_sensor_data();
        send_to_cloud();  // Kann Schwachstellen haben
        receive_commands();  // Kann Schwachstellen haben

        // Kein Weg diesen Code zu aktualisieren
        // Später entdeckte Schwachstellen können nicht behoben werden
    }
}

// VERWUNDBAR: Selbst wenn Schwachstelle gefunden wird, kein Fix möglich
void vulnerable_network_handler(uint8_t* data, size_t len) {
    // Buffer-Overflow-Schwachstelle (CWE-120)
    char buffer[64];
    memcpy(buffer, data, len);  // Keine Grenzprüfung

    // Diese Schwachstelle kann nicht gepatcht werden
    // Alle eingesetzten Gerate bleiben für immer verwundbar

    process_data(buffer);
}

// VERWUNDBAR: Keine Integritatsprüfung selbst wenn Update möglich ware
void no_update_mechanism(void) {
    // Kein Code fur:
    // - Firmware-Updates empfangen
    // - Update-Signaturen verifizieren
    // - In Flash schreiben
    // - In neue Firmware neustarten
}

Sichere Lösung

// SICHER: Gerat mit sicherer Firmware-Aktualisierungsfahigkeit

module secure_updateable_device (
    input wire clk,
    input wire reset_n,
    input wire [15:0] addr,
    output reg [31:0] data,
    output reg device_ready,
    // SICHER: Firmware-Update-Schnittstelle
    input wire [31:0] update_data,
    input wire [15:0] update_addr,
    input wire update_write,
    input wire update_start,
    input wire update_complete,
    // Signaturverifizierung
    input wire [255:0] update_signature,
    input wire verify_signature,
    output reg signature_valid,
    output reg update_success,
    output reg update_error
);

    // Firmware in Flash - kann aktualisiert werden
    reg [31:0] firmware_flash [0:16383];

    // SICHER: Update-Staging-Bereich
    reg [31:0] update_buffer [0:16383];
    reg [15:0] update_counter;

    // SICHER: Offentlicher Schlüssel für Signaturverifizierung (im ROM)
    reg [255:0] signing_public_key;
    initial begin
        signing_public_key = 256'h...; // Offentlicher Schlüssel des Herstellers
    end

    // Zustandsmaschine für Update-Prozess
    reg [2:0] update_state;
    parameter IDLE = 3'd0;
    parameter RECEIVING = 3'd1;
    parameter VERIFYING = 3'd2;
    parameter WRITING = 3'd3;
    parameter COMPLETE = 3'd4;
    parameter ERROR = 3'd5;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            update_state <= IDLE;
            update_success <= 1'b0;
            update_error <= 1'b0;
            signature_valid <= 1'b0;
            device_ready <= 1'b0;
        end
        else begin
            case (update_state)
                IDLE: begin
                    update_error <= 1'b0;
                    device_ready <= 1'b1;

                    // Normaler Betrieb - aus Flash lesen
                    data <= firmware_flash[addr];

                    if (update_start) begin
                        update_state <= RECEIVING;
                        update_counter <= 16'h0;
                        device_ready <= 1'b0;
                    end
                end

                RECEIVING: begin
                    // SICHER: Update in Staging-Buffer empfangen
                    if (update_write) begin
                        update_buffer[update_addr] <= update_data;
                        update_counter <= update_counter + 1;
                    end

                    if (update_complete) begin
                        update_state <= VERIFYING;
                    end
                end

                VERIFYING: begin
                    // SICHER: Signatur vor Anwendung des Updates verifizieren
                    if (verify_signature) begin
                        if (verify_ecdsa(update_buffer, update_counter,
                                        update_signature, signing_public_key)) begin
                            signature_valid <= 1'b1;
                            update_state <= WRITING;
                        end
                        else begin
                            signature_valid <= 1'b0;
                            update_state <= ERROR;
                        end
                    end
                end

                WRITING: begin
                    // SICHER: Verifiziertes Update in Haupt-Flash kopieren
                    if (update_counter > 0) begin
                        firmware_flash[16383 - update_counter] <=
                            update_buffer[16383 - update_counter];
                        update_counter <= update_counter - 1;
                    end
                    else begin
                        update_state <= COMPLETE;
                    end
                end

                COMPLETE: begin
                    update_success <= 1'b1;
                    update_state <= IDLE;
                    // Gerat wird mit neuer Firmware neustarten
                end

                ERROR: begin
                    update_error <= 1'b1;
                    // Staging-Buffer loschen
                    update_state <= IDLE;
                end
            endcase
        end
    end

endmodule

// SICHER: Secure Boot mit Update-Unterstützung
module secure_boot_with_update (
    input wire clk,
    input wire reset_n,
    input wire [31:0] flash_data,
    output reg [15:0] flash_addr,
    output reg boot_success,
    output reg boot_error,
    // Update-Bank-Auswahl
    input wire use_backup_bank,
    output reg active_bank
);

    // SICHER: Dual-Bank-Flash für sichere Updates
    parameter BANK_A_START = 16'h0000;
    parameter BANK_B_START = 16'h8000;

    reg [2:0] boot_state;
    parameter INIT = 3'd0;
    parameter VERIFY_MAIN = 3'd1;
    parameter VERIFY_BACKUP = 3'd2;
    parameter BOOT = 3'd3;
    parameter FALLBACK = 3'd4;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            boot_state <= INIT;
            boot_success <= 1'b0;
            boot_error <= 1'b0;
        end
        else begin
            case (boot_state)
                INIT: begin
                    // SICHER: Verifizierung der primaren Bank starten
                    flash_addr <= use_backup_bank ? BANK_B_START : BANK_A_START;
                    boot_state <= VERIFY_MAIN;
                end

                VERIFY_MAIN: begin
                    // SICHER: Primäre Firmware-Signatur verifizieren
                    if (verify_firmware_signature()) begin
                        active_bank <= use_backup_bank ? 1'b1 : 1'b0;
                        boot_state <= BOOT;
                    end
                    else begin
                        // Backup-Bank versuchen
                        boot_state <= VERIFY_BACKUP;
                    end
                end

                VERIFY_BACKUP: begin
                    // SICHER: Backup-Firmware verifizieren
                    flash_addr <= use_backup_bank ? BANK_A_START : BANK_B_START;

                    if (verify_firmware_signature()) begin
                        active_bank <= use_backup_bank ? 1'b0 : 1'b1;
                        boot_state <= FALLBACK;
                    end
                    else begin
                        // Beide Banken fehlgeschlagen
                        boot_error <= 1'b1;
                    end
                end

                BOOT: begin
                    boot_success <= 1'b1;
                    // Verifizierte Firmware ausführen
                end

                FALLBACK: begin
                    // SICHER: Von Backup nach Protokollierung des Fehlers booten
                    log_boot_failure();
                    boot_success <= 1'b1;
                end
            endcase
        end
    end

endmodule
// SICHER: IoT-Gerat mit sicherer Aktualisierungsfahigkeit

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

// SICHER: Firmware-Aktualisierungsfahigkeit

#define FLASH_BANK_A 0x08000000
#define FLASH_BANK_B 0x08040000
#define FLASH_BANK_SIZE 0x40000

// Offentlicher Schlüssel für Firmware-Verifizierung (im schreibgeschützten Speicher)
static const uint8_t manufacturer_public_key[64] = { /* ... */ };

typedef struct {
    uint32_t magic;
    uint32_t version;
    uint32_t size;
    uint8_t signature[64];
    uint8_t data[];
} firmware_image_t;

// SICHER: Firmware-Signatur verifizieren
static bool verify_firmware(const firmware_image_t* image) {
    // Magische Nummer prüfen
    if (image->magic != 0x46575550) {  // "FWUP"
        return false;
    }

    // Große ist gültig prüfen
    if (image->size > FLASH_BANK_SIZE - sizeof(firmware_image_t)) {
        return false;
    }

    // SICHER: ECDSA-Signatur verifizieren
    if (!ecdsa_verify(
            manufacturer_public_key,
            image->data,
            image->size,
            image->signature)) {
        log_error("Firmware-Signaturverifizierung fehlgeschlagen");
        return false;
    }

    return true;
}

// SICHER: Sicherer Firmware-Aktualisierungsprozess
typedef enum {
    UPDATE_SUCCESS,
    UPDATE_INVALID_IMAGE,
    UPDATE_VERIFICATION_FAILED,
    UPDATE_FLASH_ERROR,
    UPDATE_ROLLBACK_ATTEMPTED
} update_result_t;

update_result_t secure_firmware_update(const uint8_t* update_data, size_t len) {
    const firmware_image_t* image = (const firmware_image_t*)update_data;

    // SICHER: Vor Schreiben verifizieren
    if (!verify_firmware(image)) {
        return UPDATE_VERIFICATION_FAILED;
    }

    // SICHER: Version prüfen um Rollback zu verhindern
    uint32_t current_version = get_current_firmware_version();
    if (image->version < current_version) {
        log_security_event("Firmware-Rollback-Versuch blockiert");
        return UPDATE_ROLLBACK_ATTEMPTED;
    }

    // SICHER: Inaktive Bank für Update bestimmen
    uint32_t target_bank = get_inactive_bank();
    uint32_t target_addr = (target_bank == 0) ? FLASH_BANK_A : FLASH_BANK_B;

    // SICHER: Zielbank loschen
    if (!flash_erase_bank(target_addr, FLASH_BANK_SIZE)) {
        return UPDATE_FLASH_ERROR;
    }

    // SICHER: Neue Firmware schreiben
    if (!flash_write(target_addr, update_data, len)) {
        return UPDATE_FLASH_ERROR;
    }

    // SICHER: Geschriebene Daten verifizieren
    if (memcmp((void*)target_addr, update_data, len) != 0) {
        return UPDATE_FLASH_ERROR;
    }

    // SICHER: Bank-Auswahl für nächsten Boot aktualisieren
    set_active_bank(target_bank);

    log_info("Firmware-Update erfolgreich, Version %u -> %u",
             current_version, image->version);

    return UPDATE_SUCCESS;
}

// SICHER: Hauptschleife mit Aktualisierungsfahigkeit
void secure_device_main(void) {
    // Firmware-Integritat beim Boot verifizieren
    if (!verify_current_firmware()) {
        // Von Backup-Bank booten
        boot_backup_firmware();
        return;
    }

    init_hardware();
    init_network();

    while (1) {
        process_sensor_data();
        send_to_cloud();
        receive_commands();

        // SICHER: Firmware-Updates prüfen und anwenden
        if (firmware_update_available()) {
            uint8_t* update_data;
            size_t update_size;

            if (download_firmware_update(&update_data, &update_size)) {
                update_result_t result = secure_firmware_update(
                    update_data, update_size);

                if (result == UPDATE_SUCCESS) {
                    // Neustarten um Update anzuwenden
                    system_reboot();
                }
                else {
                    log_error("Firmware-Update fehlgeschlagen: %d", result);
                }

                free(update_data);
            }
        }
    }
}

// SICHER: Automatische Update-Prüfung
void check_for_updates_periodically(void) {
    static uint32_t last_check = 0;
    uint32_t now = get_current_time();

    // Alle 24 Stunden prüfen
    if (now - last_check > 86400) {
        last_check = now;

        if (check_update_server()) {
            schedule_firmware_update();
        }
    }
}

CVE-Beispiele

  • CVE-2020-9054: Network-Attached-Storage-Gerate mit OS-Command-Injection-Schwachstellen wurden aktiv für Botnet-Rekrutierung ausgenutzt, aber End-of-Support-Produkte können nicht gepatcht werden.
  • Smart Lock mit schwacher Schlüsselerzeugungsschwachstelle über Bluetooth-Sniffing erkennbar - Firmware kann nicht aktualisiert werden.

Verwandte CWEs

  • CWE-1329: Abhängigkeit von nicht aktualisierbarer Komponente (ubergeordnet)
  • CWE-1208: Querschnittsprobleme (Kategorie)
  • CWE-912: Versteckte Funktionalitat (verwandt)
  • CAPEC-682: Ausnutzung von Firmware oder ROM-Code mit nicht patchbaren Schwachstellen (Angriffsmuster)

Referenzen

  1. MITRE Corporation. "CWE-1277: Firmware Not Updateable." https://cwe.mitre.org/data/definitions/1277.html
  2. NIST. "Guidelines for Firmware Update"
  3. IEC 62443. "Industrial Cybersecurity Standards"