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
| Auswirkung | Details |
|---|---|
| Integrität | Scope: Integrität Modify Memory - Als unveränderlich angenommene Daten können geändert werden. |
| Zugriffskontrolle | Scope: Zugriffskontrolle Bypass Protection Mechanism - Sicherheitsverifizierung kann umgangen werden. |
| Authentifizierung | Scope: 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
- MITRE Corporation. "CWE-1282: Assumed-Immutable Data is Stored in Writable Memory." https://cwe.mitre.org/data/definitions/1282.html
- ARM. "TrustZone Memory Protection"
- NIST. "Root of Trust Guidelines"