Als unveränderlich angenommene Daten werden in beschreibbarem Speicher gespeichert

Beschreibung

Als unveränderlich angenommene Daten werden in beschreibbarem Speicher gespeichert tritt auf, wenn sicherheitskritische Assets wie Bootloader, Gerätekennungen und Konfigurationseinstellungen, die unveränderlich bleiben sollten, stattdessen in Speicher gespeichert werden, der umprogrammiert oder aktualisiert werden kann. Vertrauenswürdige Systemkomponenten einschließlich initialer Bootloader, kryptographischer Schlüssel und Hash-Digests erfordern Unveränderlichkeit, um ein sicheres Fundament zu etablieren. Die Speicherung in Read-Only Memory (ROM), Fuses oder One-Time Programmable (OTP) Memory bietet Integritätsgarantien. Wenn solche Assets in beschreibbarem Speicher landen, wird die Root of Trust kompromittiert.

Risiko

Veränderbare unveränderliche Daten haben schwerwiegende Sicherheitsauswirkungen. Root of Trust wird kompromittiert. Bootloader können ersetzt werden. Kryptographische Schlüssel können modifiziert werden. Hash-Digests können gefälscht werden. Geräteidentität kann gefälscht werden. Sicherheitsrichtlinien können geändert werden. Firmware-Verifizierung kann umgangen werden. Das gesamte Sicherheitsmodell kann zusammenbrechen.

Lösung

Aller unveränderlicher Code und Daten sollten in ROM oder Write-Once Memory programmiert werden, nicht in beschreibbaren Speicher. Verwenden Sie Hardware-Fuses für kritische Sicherheitseinstellungen. Implementieren Sie One-Time Programmable (OTP) Memory für Schlüssel und Zertifikate. Schützen Sie kritische Daten mit Memory Protection Units. Verifizieren Sie Datenintegrität gegen sichere Referenzwerte.

Häufige Auswirkungen

AuswirkungDetails
IntegritätScope: Integrität

Modify Memory - Als unveränderlich angenommene Daten können geändert werden.
ZugriffskontrolleScope: Zugriffskontrolle

Bypass Protection Mechanism - Sicherheitsverifizierung kann umgangen werden.
AuthentifizierungScope: Authentifizierung

Gain Privileges - Geräteidentität kann gefälscht werden.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Sicherheitskritische Daten in beschreibbarem Speicher

module vulnerable_boot_storage (
    input wire clk,
    input wire reset_n,
    input wire [15:0] addr,
    input wire [31:0] write_data,
    input wire write_enable,
    input wire read_enable,
    output reg [31:0] read_data
);

    // VERWUNDBAR: Sicherheitskritische Daten in beschreibbarem RAM gespeichert
    reg [31:0] memory [0:65535];

    // Sicherheitskritische Adressen (sollten unveränderlich sein)
    parameter BOOTLOADER_START = 16'h0000;
    parameter BOOTLOADER_END = 16'h0FFF;
    parameter GOLDEN_HASH_ADDR = 16'h1000;
    parameter ROOT_KEY_ADDR = 16'h1010;
    parameter DEVICE_ID_ADDR = 16'h1020;

    // Mit sicherheitskritischen Daten initialisieren
    initial begin
        // VERWUNDBAR: Diese sollten in ROM/OTP sein, nicht RAM
        memory[GOLDEN_HASH_ADDR] = 32'hA5B6C7D8;     // Hash zur Verifizierung
        memory[ROOT_KEY_ADDR] = 32'h12345678;        // Root Public Key
        memory[DEVICE_ID_ADDR] = 32'hDEVICE01;       // Gerätekennung
    end

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            read_data <= 32'h0;
        end
        else begin
            if (read_enable) begin
                read_data <= memory[addr];
            end

            // VERWUNDBAR: Schreiben auf JEDE Adresse einschließlich sicherheitskritischer
            if (write_enable) begin
                memory[addr] <= write_data;

                // Angreifer kann:
                // 1. GOLDEN_HASH_ADDR mit Hash von bösartigem Code überschreiben
                // 2. ROOT_KEY_ADDR durch Angreifer-Schlüssel ersetzen
                // 3. DEVICE_ID_ADDR fälschen, um ein anderes Gerät zu imitieren
            end
        end
    end

endmodule

// VERWUNDBAR: Bootloader in beschreibbarem Flash
module vulnerable_bootloader_storage (
    input wire clk,
    input wire reset_n,
    input wire [15:0] flash_addr,
    input wire [31:0] flash_write_data,
    input wire flash_write,
    input wire flash_read,
    output reg [31:0] flash_read_data,
    // Flash-Steuerung
    input wire flash_erase,
    input wire [7:0] sector_select
);

    // VERWUNDBAR: Bootloader in umprogrammierbarem Flash gespeichert
    reg [31:0] flash_memory [0:65535];

    // Bootloader in ersten 4KB (0x0000-0x0FFF)
    // VERWUNDBAR: Kann gelöscht und umprogrammiert werden

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            flash_read_data <= 32'h0;
        end
        else begin
            if (flash_read) begin
                flash_read_data <= flash_memory[flash_addr];
            end

            // VERWUNDBAR: Kein Schutz für Bootloader-Region
            if (flash_write) begin
                flash_memory[flash_addr] <= flash_write_data;
            end

            // VERWUNDBAR: Bootloader-Sektor kann gelöscht werden
            if (flash_erase && sector_select == 8'h00) begin
                // Bootloader-Sektor löschen - katastrophal!
                // Angreifer kann dann bösartigen Bootloader programmieren
            end
        end
    end

endmodule
// VERWUNDBAR: Software mit veränderbaren Sicherheitsdaten

#include <stdint.h>

// VERWUNDBAR: Sicherheitskritische Daten in beschreibbarem Speicher

// In .data-Sektion - beschreibbar
static uint8_t golden_hash[32] = {
    0xDE, 0xAD, 0xBE, 0xEF, /* ... */
};

// In .data-Sektion - beschreibbar
static uint8_t root_public_key[64] = {
    0x04, /* ... */
};

// In .bss-Sektion - beschreibbar
static uint32_t device_id;

// VERWUNDBAR: Hash-Verifizierung mit veränderbarer Referenz
bool vulnerable_verify_firmware(const uint8_t* firmware, size_t len) {
    uint8_t computed_hash[32];

    sha256(firmware, len, computed_hash);

    // VERWUNDBAR: Vergleich gegen veränderbaren golden_hash
    // Angreifer kann golden_hash ändern, um bösartige Firmware zu akzeptieren
    return memcmp(computed_hash, golden_hash, 32) == 0;
}

// VERWUNDBAR: Geräte-ID aus beschreibbarem Speicher initialisieren
void vulnerable_init_device_id(void) {
    // VERWUNDBAR: Geräte-ID in beschreibbarem Flash gespeichert
    // Kann modifiziert werden, um ein anderes Gerät zu imitieren

    uint32_t* flash_device_id = (uint32_t*)0x08000000;
    device_id = *flash_device_id;

    // Angreifer kann Flash mit anderer Geräte-ID umprogrammieren
}

// VERWUNDBAR: Zertifikatkette mit veränderbarem Root
bool vulnerable_verify_certificate(const uint8_t* cert, size_t len) {
    // VERWUNDBAR: Root-Schlüssel kann vom Angreifer ersetzt werden
    return verify_signature(cert, len, root_public_key);
}

Sichere Lösung

// SICHER: Sicherheitskritische Daten in unveränderlichem Speicher

module secure_boot_storage (
    input wire clk,
    input wire reset_n,
    input wire [15:0] addr,
    input wire [31:0] write_data,
    input wire write_enable,
    input wire read_enable,
    output reg [31:0] read_data,
    output reg write_denied
);

    // Reguläres RAM für nicht-kritische Daten
    reg [31:0] ram [0:32767];

    // SICHER: Sicherheitskritische Daten in ROM (als festverdrahtete Logik synthetisiert)
    wire [31:0] rom_data [0:255];

    // ROM-Inhalte - können nicht modifiziert werden
    assign rom_data[0] = 32'hA5B6C7D8;   // Golden Hash
    assign rom_data[1] = 32'h12345678;   // Root Key Wort 0
    assign rom_data[2] = 32'h9ABCDEF0;   // Root Key Wort 1
    // ... weitere ROM-Daten

    // SICHER: OTP-Fuse-Daten für gerätespezifische unveränderliche Daten
    wire [127:0] otp_device_id;
    wire [255:0] otp_device_key;

    otp_fuse_block otp (
        .clk(clk),
        .device_id(otp_device_id),
        .device_key(otp_device_key)
    );

    // Adressdekodierung
    wire is_rom_access = (addr >= 16'h0000) && (addr < 16'h0100);
    wire is_otp_access = (addr >= 16'h0100) && (addr < 16'h0110);
    wire is_ram_access = (addr >= 16'h8000);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            read_data <= 32'h0;
            write_denied <= 1'b0;
        end
        else begin
            write_denied <= 1'b0;

            if (read_enable) begin
                if (is_rom_access) begin
                    // SICHER: Aus ROM lesen
                    read_data <= rom_data[addr[7:0]];
                end
                else if (is_otp_access) begin
                    // SICHER: Aus OTP lesen
                    read_data <= otp_device_id[addr[3:0] * 32 +: 32];
                end
                else if (is_ram_access) begin
                    read_data <= ram[addr - 16'h8000];
                end
            end

            if (write_enable) begin
                if (is_rom_access) begin
                    // SICHER: ROM-Schreibvorgänge abgelehnt
                    write_denied <= 1'b1;
                end
                else if (is_otp_access) begin
                    // SICHER: OTP-Schreibvorgänge abgelehnt (kann nur einmal programmiert werden)
                    write_denied <= 1'b1;
                end
                else if (is_ram_access) begin
                    // RAM-Schreibvorgänge erlaubt
                    ram[addr - 16'h8000] <= write_data;
                end
            end
        end
    end

endmodule

// SICHER: Geschützter Bootloader mit Write-Once-Speicher
module secure_bootloader_storage (
    input wire clk,
    input wire reset_n,
    input wire [15:0] addr,
    input wire [31:0] write_data,
    input wire write_enable,
    input wire read_enable,
    input wire [3:0] requester_id,
    output reg [31:0] read_data,
    output reg access_denied,
    // Boot-Status
    input wire boot_complete,
    output reg protection_active
);

    // Bootloader in geschützter ROM-Region
    wire [31:0] bootloader_rom [0:4095];

    // Anwendungs-Flash (beschreibbar durch autorisierte Benutzer)
    reg [31:0] app_flash [0:61439];

    // SICHER: Schutz-Lock - kann nach Setzen nicht gelöscht werden
    reg bootloader_locked;

    // Bootloader-Region
    parameter BOOTLOADER_START = 16'h0000;
    parameter BOOTLOADER_END = 16'h0FFF;

    // SICHER: Nur vertrauenswürdiger Requester
    parameter SECURE_MASTER = 4'd0;

    wire is_bootloader_access = (addr >= BOOTLOADER_START) &&
                                (addr <= BOOTLOADER_END);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            read_data <= 32'h0;
            access_denied <= 1'b0;
            bootloader_locked <= 1'b0;
            protection_active <= 1'b0;
        end
        else begin
            access_denied <= 1'b0;

            // SICHER: Bootloader nach Boot-Abschluss sperren
            if (boot_complete && !bootloader_locked) begin
                bootloader_locked <= 1'b1;
                protection_active <= 1'b1;
            end

            if (read_enable) begin
                if (is_bootloader_access) begin
                    // Bootloader-Lesevorgänge immer erlaubt
                    read_data <= bootloader_rom[addr];
                end
                else begin
                    read_data <= app_flash[addr - 16'h1000];
                end
            end

            if (write_enable) begin
                if (is_bootloader_access) begin
                    // SICHER: Bootloader-Schreibvorgänge immer abgelehnt (ROM)
                    access_denied <= 1'b1;
                end
                else if (bootloader_locked && requester_id != SECURE_MASTER) begin
                    // App-Flash nach Boot eingeschränkt
                    access_denied <= 1'b1;
                end
                else begin
                    app_flash[addr - 16'h1000] <= write_data;
                end
            end
        end
    end

endmodule
// SICHER: Software mit unveränderlichen Sicherheitsdaten

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

// SICHER: Sicherheitskritische Daten in Read-Only-Sektion
// Compiler platziert dies in .rodata (typischerweise in Flash/ROM)
static const uint8_t golden_hash[32] __attribute__((section(".rodata.security"))) = {
    0xDE, 0xAD, 0xBE, 0xEF, /* ... */
};

// SICHER: Root Public Key in Read-Only Memory
static const uint8_t root_public_key[64] __attribute__((section(".rodata.security"))) = {
    0x04, /* ... */
};

// SICHER: Geräte-ID aus OTP/Fuse lesen
static uint32_t read_device_id_from_otp(void) {
    // OTP-Register ist Read-Only, kann nach Programmierung nicht modifiziert werden
    volatile uint32_t* otp_device_id = (volatile uint32_t*)OTP_DEVICE_ID_ADDR;
    return *otp_device_id;
}

// SICHER: Verifizieren, dass Golden Hash in ROM ist
static bool verify_golden_hash_integrity(void) {
    // Prüfen, dass golden_hash in erwarteter ROM-Region ist
    uintptr_t addr = (uintptr_t)golden_hash;
    if (addr < ROM_START || addr >= ROM_END) {
        // Golden Hash nicht in ROM - Sicherheitsverletzung!
        return false;
    }

    // Verifizieren, dass MPU diese Region schützt
    if (!mpu_region_is_read_only(addr)) {
        return false;
    }

    return true;
}

// SICHER: Hash-Verifizierung mit unveränderlicher Referenz
bool secure_verify_firmware(const uint8_t* firmware, size_t len) {
    // SICHER: Verifizieren, dass Golden Hash geschützt ist
    if (!verify_golden_hash_integrity()) {
        log_security_error("Golden hash integrity check failed");
        return false;
    }

    uint8_t computed_hash[32];
    sha256(firmware, len, computed_hash);

    // Gegen unveränderlichen golden_hash im ROM vergleichen
    return secure_compare(computed_hash, golden_hash, 32);
}

// SICHER: MPU verwenden, um sicherheitskritische Daten zu schützen
void protect_security_data(void) {
    // MPU-Region für Sicherheitsdaten als Read-Only konfigurieren

    mpu_region_config_t security_region = {
        .base_address = (uint32_t)&golden_hash,
        .size = 4096,  // Gesamte Sicherheitssektion schützen
        .attributes = MPU_REGION_RO | MPU_REGION_EXEC_NEVER,
        .enable = true
    };

    configure_mpu_region(MPU_SECURITY_REGION, &security_region);

    // SICHER: MPU-Konfiguration sperren
    lock_mpu_configuration();
}

// SICHER: Geräte-ID aus unveränderlicher Quelle holen
uint32_t get_device_id(void) {
    static uint32_t cached_device_id = 0;
    static bool device_id_cached = false;

    if (!device_id_cached) {
        // Aus OTP lesen (unveränderlich)
        cached_device_id = read_device_id_from_otp();
        device_id_cached = true;
    }

    return cached_device_id;
}

// SICHER: Linker-Script-Auszug zum Platzieren von Sicherheitsdaten im ROM
/*
SECTIONS {
    .rodata.security : {
        __security_data_start = .;
        KEEP(*(.rodata.security))
        __security_data_end = .;
    } > ROM

    ASSERT(__security_data_end <= ROM_END,
           "Security data must fit in ROM");
}
*/

CVE-Beispiele

Schwachstellen bei veränderbaren Sicherheitsdaten wurden in verschiedenen eingebetteten Systemen gefunden, bei denen Hash-Digests oder kryptographische Schlüssel in beschreibbarem Flash gespeichert waren, was Angreifern ermöglichte, Verifizierungsdaten zu modifizieren und Sicherheitsprüfungen zu umgehen.


Verwandte CWEs

  • CWE-668: Exposure of Resource to Wrong Sphere (übergeordnet)
  • CWE-471: Modification of Assumed-Immutable Data (kann vorausgehen)
  • CWE-1202: Memory and Storage Issues (Kategorie)
  • CAPEC-458: Flash Memory Attacks (Angriffsmuster)
  • CAPEC-679: Exploitation of Improperly Configured Memory Protections (Angriffsmuster)

Referenzen

  1. MITRE Corporation. "CWE-1282: Assumed-Immutable Data is Stored in Writable Memory." https://cwe.mitre.org/data/definitions/1282.html
  2. ARM. "TrustZone Memory Protection"
  3. NIST. "Root of Trust Guidelines"