Sensible Informationen vor Debug-/Energiezustandsübergang nicht geloscht
Beschreibung
Sensible Informationen vor Debug-/Energiezustandsübergang nicht geloscht tritt auf, wenn ein Produkt sensible Informationen während Energie- oder Debug-Zustandsübergangen nicht loscht, wodurch Daten zuganglich bleiben, wenn sie aufgrund geänderter Zugriffseinschränkungen nicht mehr verfügbar sein sollten. Gerate arbeiten über mehrere Energiezustände (Normal, Niedrigenergie, Ruhezustand, Tiefschlaf) und Debug-Bedingungen. Beim Übergang zwischen Zuständen können Informationen, die im vorherigen Zustand zuganglich waren, im Speicher verbleiben. Wenn diese sensiblen Daten nicht vor dem Übergang entfernt werden, können sie an unbefugte Akteure im neuen Zustand gelangen.
Risiko
Nicht geloschte sensible Informationen haben schwerwiegende Sicherheitsauswirkungen. Kryptografische Schlüssel können über Zustände hinweg durchsickern. Authentifizierungsdaten können freigelegt werden. Debug-Zugriff kann Geheimnisse offenlegen. Versteckte Geratefunktionen können entsperrt werden. Vertrauliche Daten können kompromittiert werden. Sicherheitsgrenzen können verletzt werden. Angreifer können Zustandsübergange ausnutzen. Informationsoffenlegung ermöglicht weitere Angriffe.
Lösung
Entfernen Sie während Zustandsübergangen Informationen, die im nächsten Zustand nicht benötigt werden, bevor der Übergang abgeschlossen wird. Implementieren Sie automatisches Loschen sensibler Register und Speicher während Energieübergängen. Loschen Sie kryptografische Schlüssel vor dem Eintritt in den Debug-Modus. Entwerfen Sie Zustandsmaschinen, die das Loschen von Daten erzwingen. Verifizieren Sie das Loschen durch Tests. Wenden Sie diese Minderung sowohl während der Architektur-/Design- als auch der Implementierungsphase an.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Speicher lesen - Sensible Daten bleiben nach Zustandsübergang zuganglich. |
| Zugriffskontrolle | Umfang: Zugriffskontrolle Schutzmechanismus umgehen - Angreifer können über Zustandsübergange auf Daten zugreifen. |
| Authentifizierung | Umfang: Authentifizierung Berechtigungen erlangen - Anmeldedaten können aus dem vorherigen Zustand wiederhergestellt werden. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Zustandsübergang ohne Loschen sensibler Daten
module vulnerable_power_controller (
input wire clk,
input wire reset_n,
input wire [1:0] power_request,
output reg [1:0] current_state,
// Sensible Daten
input wire [127:0] encryption_key,
output reg [127:0] key_register
);
// Energiezustände
parameter ACTIVE = 2'b00;
parameter IDLE = 2'b01;
parameter SLEEP = 2'b10;
parameter DEBUG = 2'b11;
// VERWUNDBAR: Schlüssel bleibt im Register über Zustandsübergange hinweg
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= ACTIVE;
key_register <= 128'h0;
end
else begin
case (current_state)
ACTIVE: begin
// Schlüssel im aktiven Zustand laden
key_register <= encryption_key;
if (power_request == SLEEP) begin
// VERWUNDBAR: Übergang in Schlafmodus ohne Schlüssel zu loschen
current_state <= SLEEP;
end
else if (power_request == DEBUG) begin
// VERWUNDBAR: Übergang in Debug-Modus ohne Schlüssel zu loschen
current_state <= DEBUG;
// Schlüssel ist im Debug-Zustand noch zuganglich!
end
end
SLEEP: begin
// VERWUNDBAR: Schlüssel noch im Schlafzustand vorhanden
// Angreifer kann Speicher untersuchen während Gerat schlaft
if (power_request == ACTIVE) begin
current_state <= ACTIVE;
end
end
DEBUG: begin
// VERWUNDBAR: Vollständiger Schlüssel im Debug-Zustand sichtbar
// Debug-Schnittstelle kann key_register lesen
if (power_request == ACTIVE) begin
current_state <= ACTIVE;
end
end
endcase
end
end
endmodule
// VERWUNDBAR: Debug-Modus legt sensible Informationen offen
module vulnerable_debug_access (
input wire clk,
input wire reset_n,
input wire debug_enable,
input wire [7:0] debug_addr,
output reg [31:0] debug_data,
// Interner sensibler Zustand
input wire [255:0] private_key,
input wire [127:0] session_key,
input wire [63:0] user_credentials
);
// VERWUNDBAR: Gesamter interner Zustand im Debug-Modus zuganglich
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
debug_data <= 32'h0;
end
else if (debug_enable) begin
// VERWUNDBAR: Kein Loschen sensibler Daten vor Debug
case (debug_addr)
8'h00: debug_data <= private_key[31:0];
8'h01: debug_data <= private_key[63:32];
8'h02: debug_data <= private_key[95:64];
// ... vollständiger privater Schlüssel zuganglich
8'h10: debug_data <= session_key[31:0];
8'h14: debug_data <= user_credentials[31:0];
endcase
end
end
endmodule
// VERWUNDBAR: Software-Zustandsübergang ohne Loschen
#include <stdint.h>
typedef struct {
uint8_t aes_key[32];
uint8_t private_key[256];
uint8_t user_password[64];
uint8_t session_token[32];
} sensitive_data_t;
static sensitive_data_t secrets;
// VERWUNDBAR: Schlafmodus ohne Loschen von Geheimnissen
void vulnerable_enter_sleep(void) {
// Zustand für Wiederaufnahme speichern
save_cpu_context();
// VERWUNDBAR: Geheimnisse bleiben im Speicher während Schlafmodus
// RAM kann für Angreifer zuganglich sein
// Schlafmodus betreten
enter_low_power_mode();
// Beim Aufwachen sind Geheimnisse noch vorhanden
}
// VERWUNDBAR: Debug-Modus ohne Loschen von Geheimnissen
void vulnerable_enter_debug(void) {
// VERWUNDBAR: Kein Loschen vor Debug
// Debug-Schnittstelle aktivieren
enable_jtag();
enable_debug_uart();
// Debugger kann jetzt auf gesamten Speicher einschließlich Geheimnissen zugreifen!
}
// VERWUNDBAR: TPM-Spezifikationsverletzung
void vulnerable_tpm_power_transition(void) {
// VERWUNDBAR: Erforderliche Flags gemäß TPM-Spezifikation nicht gesetzt
// Fehlgeschlagene Autorisierungsversuche werden nach Stromverlust nicht aufgezeichnet
// Niedrigenergiemodus betreten
tpm_enter_idle();
// Stromverlust tritt auf...
// Bei Wiederaufnahme wird der Autorisierungsfehlzahler zurückgesetzt
// Angreifer erhält unbegrenzte Passwortversuche!
}
Sichere Lösung
// SICHER: Zustandsübergang mit Loschen sensibler Daten
module secure_power_controller (
input wire clk,
input wire reset_n,
input wire [1:0] power_request,
output reg [1:0] current_state,
input wire [127:0] encryption_key,
output reg [127:0] key_register,
output reg key_valid,
output reg transition_complete
);
// Energiezustände
parameter ACTIVE = 2'b00;
parameter IDLE = 2'b01;
parameter SLEEP = 2'b10;
parameter DEBUG = 2'b11;
// Zustandsübergangsphasen
reg [1:0] transition_phase;
parameter PHASE_IDLE = 2'b00;
parameter PHASE_CLEARING = 2'b01;
parameter PHASE_TRANSITION = 2'b10;
parameter PHASE_COMPLETE = 2'b11;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= ACTIVE;
key_register <= 128'h0;
key_valid <= 1'b0;
transition_phase <= PHASE_IDLE;
transition_complete <= 1'b0;
end
else begin
case (current_state)
ACTIVE: begin
transition_complete <= 1'b0;
// Schlüssel im aktiven Zustand laden
key_register <= encryption_key;
key_valid <= 1'b1;
if (power_request == SLEEP || power_request == DEBUG) begin
// SICHER: Loschphase vor Übergang betreten
transition_phase <= PHASE_CLEARING;
end
end
endcase
// SICHER: Loschphase
if (transition_phase == PHASE_CLEARING) begin
// Alle sensiblen Daten loschen
key_register <= 128'h0;
key_valid <= 1'b0;
transition_phase <= PHASE_TRANSITION;
end
// Übergang nach abgeschlossenem Loschen
if (transition_phase == PHASE_TRANSITION) begin
current_state <= power_request;
transition_phase <= PHASE_COMPLETE;
transition_complete <= 1'b1;
end
if (transition_phase == PHASE_COMPLETE) begin
transition_phase <= PHASE_IDLE;
end
end
end
endmodule
// SICHER: Debug-Modus mit Schutz sensibler Daten
module secure_debug_access (
input wire clk,
input wire reset_n,
input wire debug_request,
input wire debug_authenticated,
input wire [7:0] debug_addr,
output reg [31:0] debug_data,
output reg debug_enabled,
// Interner sensibler Zustand
input wire [255:0] private_key,
input wire [127:0] session_key,
input wire [63:0] user_credentials
);
// SICHER: Geloschte Kopien für Debug-Zugriff
reg [255:0] cleared_private_key;
reg [127:0] cleared_session_key;
reg [63:0] cleared_credentials;
reg sensitive_cleared;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
debug_data <= 32'h0;
debug_enabled <= 1'b0;
sensitive_cleared <= 1'b0;
cleared_private_key <= 256'h0;
cleared_session_key <= 128'h0;
cleared_credentials <= 64'h0;
end
else begin
if (debug_request && debug_authenticated) begin
// SICHER: Sensible Daten VOR Aktivierung des Debug loschen
if (!sensitive_cleared) begin
cleared_private_key <= 256'h0;
cleared_session_key <= 128'h0;
cleared_credentials <= 64'h0;
sensitive_cleared <= 1'b1;
end
else begin
debug_enabled <= 1'b1;
end
end
if (debug_enabled) begin
case (debug_addr)
// SICHER: Nur geloschte/bereinigte Daten bereitstellen
8'h00: debug_data <= 32'hDEADBEEF; // Indikator
8'h10: debug_data <= 32'hDEADBEEF; // Keine echten Daten
default: debug_data <= 32'h0;
endcase
end
// Debug-Modus verlassen
if (!debug_request) begin
debug_enabled <= 1'b0;
sensitive_cleared <= 1'b0;
end
end
end
endmodule
// SICHER: Energiezustandsmaschine mit obligatorischem Loschen
module secure_power_fsm (
input wire clk,
input wire reset_n,
input wire [1:0] requested_state,
input wire transition_request,
output reg [1:0] current_state,
output reg clearing_in_progress,
output reg transition_complete,
// Schnittstelle für sensible Daten
output reg clear_keys,
output reg clear_session,
output reg clear_cache,
input wire keys_cleared,
input wire session_cleared,
input wire cache_cleared
);
parameter ACTIVE = 2'b00;
parameter SLEEP = 2'b01;
parameter HIBERNATE = 2'b10;
parameter DEBUG = 2'b11;
reg [2:0] fsm_state;
parameter FSM_IDLE = 3'd0;
parameter FSM_START_CLEAR = 3'd1;
parameter FSM_WAIT_CLEAR = 3'd2;
parameter FSM_VERIFY_CLEAR = 3'd3;
parameter FSM_TRANSITION = 3'd4;
parameter FSM_COMPLETE = 3'd5;
reg [1:0] pending_state;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= ACTIVE;
fsm_state <= FSM_IDLE;
clearing_in_progress <= 1'b0;
transition_complete <= 1'b0;
clear_keys <= 1'b0;
clear_session <= 1'b0;
clear_cache <= 1'b0;
end
else begin
case (fsm_state)
FSM_IDLE: begin
transition_complete <= 1'b0;
if (transition_request && requested_state != current_state) begin
pending_state <= requested_state;
fsm_state <= FSM_START_CLEAR;
end
end
FSM_START_CLEAR: begin
// SICHER: Loschen aller sensiblen Daten einleiten
clearing_in_progress <= 1'b1;
clear_keys <= 1'b1;
clear_session <= 1'b1;
clear_cache <= 1'b1;
fsm_state <= FSM_WAIT_CLEAR;
end
FSM_WAIT_CLEAR: begin
// SICHER: Auf Abschluss aller Loschvorgange warten
if (keys_cleared && session_cleared && cache_cleared) begin
clear_keys <= 1'b0;
clear_session <= 1'b0;
clear_cache <= 1'b0;
fsm_state <= FSM_VERIFY_CLEAR;
end
end
FSM_VERIFY_CLEAR: begin
// SICHER: Verifizieren dass Loschen erfolgreich war
// Zusätzliche Verifizierung könnte hier hinzugefugt werden
fsm_state <= FSM_TRANSITION;
end
FSM_TRANSITION: begin
// SICHER: Nur nach verifiziertem Loschen ubergehen
current_state <= pending_state;
clearing_in_progress <= 1'b0;
fsm_state <= FSM_COMPLETE;
end
FSM_COMPLETE: begin
transition_complete <= 1'b1;
fsm_state <= FSM_IDLE;
end
endcase
end
end
endmodule
// SICHER: Software-Zustandsübergang mit ordnungsgemäßem Loschen
#include <stdint.h>
#include <string.h>
typedef struct {
uint8_t aes_key[32];
uint8_t private_key[256];
uint8_t user_password[64];
uint8_t session_token[32];
} sensitive_data_t;
static sensitive_data_t secrets;
// SICHER: Sicheres Speicherloschen das nicht wegoptimiert wird
static void secure_clear(volatile void* ptr, size_t size) {
volatile uint8_t* p = (volatile uint8_t*)ptr;
while (size--) {
*p++ = 0;
}
__asm__ volatile("" ::: "memory");
}
// SICHER: Schlafmodus mit ordnungsgemäßem Loschen
void secure_enter_sleep(void) {
// SICHER: Sensible Daten vor Schlafmodus loschen
secure_clear(&secrets.aes_key, sizeof(secrets.aes_key));
secure_clear(&secrets.private_key, sizeof(secrets.private_key));
secure_clear(&secrets.session_token, sizeof(secrets.session_token));
// Hinweis: Benutzerpasswort behalten falls für Wiederaufnahme-Authentifizierung benötigt
// SICHER: Hardware-Schlüsselregister loschen
clear_hardware_key_registers();
// SICHER: Caches loschen
flush_and_invalidate_cache();
// Minimalen Zustand für Wiederaufnahme speichern
save_cpu_context();
// Jetzt sicher in Schlafmodus zu wechseln
enter_low_power_mode();
}
// SICHER: Debug-Modus mit Schutz sensibler Daten
void secure_enter_debug(void) {
// SICHER: ALLE sensiblen Daten vor Aktivierung des Debug loschen
secure_clear(&secrets, sizeof(secrets));
// SICHER: Hardware-Sicherheitszustand loschen
clear_hardware_key_registers();
clear_secure_memory_regions();
zeroize_crypto_state();
// SICHER: Loschen verifizieren
if (!verify_sensitive_data_cleared()) {
log_error("Loschen sensibler Daten fehlgeschlagen");
secure_halt();
return;
}
// Jetzt sicher Debug zu aktivieren
enable_jtag();
enable_debug_uart();
}
// SICHER: TPM-konformer Energieübergang
void secure_tpm_power_transition(void) {
// SICHER: Erforderliche Flags gemäß TPM-Spezifikation setzen
tpm_set_state_save_flag();
// SICHER: Autorisierungsfehlzahler speichern
save_auth_failure_counter();
// Niedrigenergiemodus betreten
tpm_enter_idle();
// Bei Wiederaufnahme wird Zahler wiederhergestellt
// Brute-Force-Angriffe bleiben begrenzt
}
// SICHER: Wiederaufnahme aus Schlafmodus mit Verifizierung
void secure_resume_from_sleep(void) {
// Verifizieren dass wir im erwarteten Zustand sind
if (!verify_sleep_state()) {
secure_halt();
return;
}
// SICHER: Verifizieren dass sensible Daten geloscht wurden
if (!verify_secrets_zero(&secrets.aes_key, sizeof(secrets.aes_key))) {
log_error("AES-Schlüssel nicht während Schlafmodus geloscht");
secure_halt();
return;
}
// CPU-Kontext wiederherstellen
restore_cpu_context();
// Erneut authentifizieren vor Wiederherstellung von Geheimnissen
if (!authenticate_user()) {
secure_halt();
return;
}
// Jetzt sicher Geheimnisse aus sicherem Speicher neu zu laden
reload_secrets_from_secure_storage();
}
CVE-Beispiele
- CVE-2020-12926: Produktsoftware setzte erforderliche Flags gemäß TPM-Spezifikationen nicht, was verhinderte, dass fehlgeschlagene Autorisierungsversuche nach Stromverlust aufgezeichnet wurden, wodurch Brute-Force-Angriffe ermöglicht wurden.
Verwandte CWEs
- CWE-226: Sensible Informationen in Ressource vor Wiederverwendung nicht entfernt (ubergeordnet)
- CWE-200: Offenlegung sensibler Informationen an unbefugten Akteur (verwandt)
- CWE-1207: Debug- und Testprobleme (Kategorie)
- CWE-1258: Offenlegung sensibler Systeminformationen durch nicht geloschte Debug-Informationen (verwandt)
Referenzen
- MITRE Corporation. "CWE-1272: Sensitive Information Uncleared Before Debug/Power State Transition." https://cwe.mitre.org/data/definitions/1272.html
- TCG. "TPM 2.0 Library Specification"
- ARM. "TrustZone Power Management"