Internes Asset unsicherem Debug-Zugriffslevel oder -Zustand ausgesetzt
Beschreibung
Internes Asset unsicherem Debug-Zugriffslevel oder -Zustand ausgesetzt tritt auf, wenn ein Produkt physische Debug- oder Testschnittstellen mit mehreren Zugriffslevels verwendet, aber internen Assets falsche Debug-Zugriffsrechte zuweist, was unbeabsichtigten Zugriff von nicht vertrauenswürdigen Debug-Agenten ermöglicht. Die Debug-Autorisierung unterstützt mehrere Zugriffslevels, die steuern, welche System-Assets basierend auf authentifizierten Berechtigungen zugänglich sind. Die Autorisierung kann vom Systemzustand oder der Boot-Phase abhängen. Beispielsweise könnte ein vollständiger System-Debug-Zugriff nur früh im Boot nach einem System-Reset erlaubt sein, um sicherzustellen, dass Daten vorheriger Sitzungen nicht zugänglich sind.
Risiko
Falsche Debug-Zugriffslevels haben schwerwiegende Sicherheitsauswirkungen. Sensible Assets können auf falschen Berechtigungslevels zugänglich sein. Debug-Zugriff während falscher Boot-Phasen kann Geheimnisse offenlegen. Angreifer können den Boot-Ablauf über Debug ändern. Verschlüsselungsschlüssel können vor der Sperrung zugänglich sein. Speicherschutz kann über Debug umgangen werden. Daten vorheriger Sitzungen können zugänglich sein. Privilege Escalation kann über Debug möglich sein.
Lösung
Stellen Sie sicher, dass Debug-Zugriffslevels alle internen Assets korrekt schützen. Beschränken Sie den vollständigen Debug-Zugriff auf geeignete Boot-Phasen. Setzen Sie Debug-Schutzregister standardmäßig auf den gesicherten Zustand. Verwenden Sie UND-Logik statt ODER für die Kombination von Zugriffsüberprüfungen. Überprüfen Sie den Debug-Schutz über alle Systemzustände hinweg. Testen Sie den Debug-Zugriff in jeder Boot-Phase. Dokumentieren Sie die Debug-Zugriffsanforderungen für jedes Asset. Implementieren Sie eine ordnungsgemäße Debug-Authentifizierung.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Speicher lesen - Angreifer könnten sensible Informationen aus internen Assets über einen Debugger erhalten, wenn Schutzmechanismen die korrekten Debug-Zugriffslevels nicht durchsetzen. |
| Integrität | Umfang: Integrität Speicher ändern - Unbefugte Speicheränderung durch unzureichend geschützten Debug-Zugriff. |
| Zugriffskontrolle | Umfang: Zugriffskontrolle Schutzmechanismus umgehen, Berechtigungen erlangen - Autorisierungs- und Zugriffskontrollverletzungen ermöglichen unbefugte Privilegienannahme. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: JTAG-Zugriff vor Sicherheitsinitialisierung erlaubt
module vulnerable_jtag_protection (
input wire clk,
input wire reset_n,
input wire jtag_request,
input wire [31:0] jtag_addr,
input wire jtag_write,
input wire [31:0] jtag_wdata,
input wire boot_complete,
input wire security_init_done,
output reg [31:0] jtag_rdata,
output reg jtag_ack
);
// JTAG-Schutzregister
reg jtag_shield_enabled;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// VERWUNDBAR: JTAG-Schutz standardmäßig deaktiviert!
jtag_shield_enabled <= 1'b0; // Sollte 1'b1 sein
end
else if (boot_complete) begin
// Schutz erst nach Boot-Abschluss aktiviert
// Zu spät - Angreifer kann während des Boots zugreifen
jtag_shield_enabled <= 1'b1;
end
end
// VERWUNDBAR: Voller JTAG-Zugriff vor boot_complete
always @(posedge clk) begin
if (jtag_request) begin
if (!jtag_shield_enabled) begin
// JTAG hat vollen Zugriff während des frühen Boots!
if (jtag_write) begin
memory[jtag_addr] <= jtag_wdata; // Kann Boot-Code ändern!
end else begin
jtag_rdata <= memory[jtag_addr]; // Kann Schlüssel lesen!
end
jtag_ack <= 1'b1;
end else begin
jtag_ack <= 1'b0; // Nach Boot blockiert
end
end
end
// Angriffsfenster: Von Reset bis boot_complete, voller Debug-Zugriff
endmodule
// VERWUNDBAR: Debug-Berechtigungsprüfung verwendet ODER statt UND
module vulnerable_debug_auth (
input wire clk,
input wire reset_n,
input wire debug_request,
input wire debug_mode_active,
input wire user_mode,
input wire password_correct,
output reg debug_allowed
);
// VERWUNDBAR: ODER-Logik - eine der Bedingungen reicht für Zugriff
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
debug_allowed <= 1'b0;
end
else begin
// Fehler: debug_mode_active ODER user_mode gewährt Zugriff
// Sollte BEIDE Bedingungen erfordern
debug_allowed <= debug_request && (debug_mode_active || password_correct);
end
end
// Wenn debug_mode_active gesetzt ist (z.B. durch Ziehen eines Pins), kein Passwort nötig
endmodule
// VERWUNDBAR: Debug-Zugriffslevel nicht an Boot-Phase angepasst
module vulnerable_boot_debug (
input wire clk,
input wire reset_n,
input wire [2:0] boot_stage,
input wire debug_request,
input wire [2:0] debug_access_level,
input wire [31:0] debug_addr,
output reg [31:0] debug_data,
output reg debug_granted
);
// Boot-Phasen
parameter STAGE_ROM = 3'h0;
parameter STAGE_BOOTLOADER = 3'h1;
parameter STAGE_KERNEL = 3'h2;
parameter STAGE_USER = 3'h3;
// Debug-Zugriffslevels
parameter ACCESS_NONE = 3'h0;
parameter ACCESS_USER = 3'h1;
parameter ACCESS_PRIVILEGED = 3'h2;
parameter ACCESS_FULL = 3'h3;
always @(posedge clk) begin
if (debug_request) begin
// VERWUNDBAR: Zugriffslevel nicht korrekt nach Boot-Phase eingeschränkt
// Voller Zugriff selbst in späteren Boot-Phasen erlaubt
if (debug_access_level == ACCESS_FULL) begin
debug_data <= memory[debug_addr];
debug_granted <= 1'b1;
end
else begin
debug_granted <= 1'b0;
end
end
end
// Sollte vollen Zugriff nur auf frühes Boot beschränken
endmodule
// VERWUNDBAR: Debug-Zugriff während sensibler Boot-Operationen
void vulnerable_secure_boot(void) {
// Verschlüsselungsschlüssel laden
load_boot_keys(); // Schlüssel jetzt im Speicher
// VERWUNDBAR: Debug noch aktiviert, Schlüssel zugänglich!
// Firmware-Signatur überprüfen
if (!verify_signature()) {
// Boot fehlgeschlagen, aber Debug kann noch auf Schlüssel zugreifen
halt();
}
// Debug schließlich deaktivieren...
disable_debug(); // Zu spät - Schlüssel könnten bereits extrahiert worden sein
}
// VERWUNDBAR: Debug-Berechtigungsprüfung
bool vulnerable_debug_check(uint32_t addr) {
// VERWUNDBAR: Debug während Boot immer erlauben
if (!boot_complete) {
return true; // Voller Zugriff während des Boots
}
// Nach dem Boot Berechtigung prüfen
return is_privileged_debug();
}
Sichere Lösung
// SICHER: JTAG-Schutz standardmäßig aktiviert
module secure_jtag_protection (
input wire clk,
input wire reset_n,
input wire jtag_request,
input wire [31:0] jtag_addr,
input wire jtag_write,
input wire [31:0] jtag_wdata,
input wire jtag_authenticated, // Erfordert Authentifizierung
input wire boot_complete,
input wire security_init_done,
output reg [31:0] jtag_rdata,
output reg jtag_ack,
output reg jtag_denied
);
// JTAG-Schutzregister
reg jtag_shield_enabled;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// SICHER: JTAG-Schutz standardmäßig AKTIVIERT
jtag_shield_enabled <= 1'b1;
end
// Schutz kann nur mit Authentifizierung nach Sicherheitsinitialisierung deaktiviert werden
else if (security_init_done && jtag_authenticated) begin
// Authentifiziertes Debug nach Sicherheitskonfiguration erlauben
jtag_shield_enabled <= 1'b0;
end
end
// SICHER: JTAG blockiert bis authentifiziert
always @(posedge clk) begin
jtag_denied <= 1'b0;
if (jtag_request) begin
if (jtag_shield_enabled) begin
// Debug blockiert
jtag_rdata <= 32'h0;
jtag_ack <= 1'b0;
jtag_denied <= 1'b1;
end
else if (jtag_authenticated) begin
// Authentifiziertes Debug erlaubt
if (jtag_write) begin
memory[jtag_addr] <= jtag_wdata;
end else begin
jtag_rdata <= memory[jtag_addr];
end
jtag_ack <= 1'b1;
end
else begin
jtag_ack <= 1'b0;
jtag_denied <= 1'b1;
end
end
end
endmodule
// SICHER: Debug-Berechtigungsprüfung verwendet UND-Logik
module secure_debug_auth (
input wire clk,
input wire reset_n,
input wire debug_request,
input wire debug_mode_active,
input wire user_authorized,
input wire password_correct,
output reg debug_allowed
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
debug_allowed <= 1'b0;
end
else begin
// SICHER: UND-Logik - ALLE Bedingungen erforderlich
debug_allowed <= debug_request &&
debug_mode_active &&
user_authorized &&
password_correct;
end
end
endmodule
// SICHER: Debug-Zugriffslevel an Boot-Phase angepasst
module secure_boot_debug (
input wire clk,
input wire reset_n,
input wire [2:0] boot_stage,
input wire debug_request,
input wire [2:0] debug_access_level,
input wire debug_authenticated,
input wire [31:0] debug_addr,
output reg [31:0] debug_data,
output reg debug_granted,
output reg access_violation
);
// Boot-Phasen
parameter STAGE_ROM = 3'h0;
parameter STAGE_BOOTLOADER = 3'h1;
parameter STAGE_KERNEL = 3'h2;
parameter STAGE_USER = 3'h3;
// Debug-Zugriffslevels
parameter ACCESS_NONE = 3'h0;
parameter ACCESS_USER = 3'h1;
parameter ACCESS_PRIVILEGED = 3'h2;
parameter ACCESS_FULL = 3'h3;
// Maximales erlaubtes Zugriffslevel pro Boot-Phase
function [2:0] max_access_for_stage;
input [2:0] stage;
begin
case (stage)
STAGE_ROM: max_access_for_stage = ACCESS_NONE; // Kein Debug während ROM
STAGE_BOOTLOADER: max_access_for_stage = ACCESS_PRIVILEGED; // Eingeschränkt
STAGE_KERNEL: max_access_for_stage = ACCESS_PRIVILEGED;
STAGE_USER: max_access_for_stage = ACCESS_USER; // Nur Benutzerebene
default: max_access_for_stage = ACCESS_NONE;
endcase
end
endfunction
always @(posedge clk) begin
access_violation <= 1'b0;
if (debug_request && debug_authenticated) begin
// SICHER: Zugriffslevel für aktuelle Boot-Phase prüfen
if (debug_access_level <= max_access_for_stage(boot_stage)) begin
debug_data <= memory[debug_addr];
debug_granted <= 1'b1;
end
else begin
// Zugriffslevel zu hoch für aktuelle Boot-Phase
debug_data <= 32'h0;
debug_granted <= 1'b0;
access_violation <= 1'b1;
end
end
else begin
debug_granted <= 1'b0;
end
end
endmodule
// SICHER: Debug während Secure Boot ordnungsgemäß eingeschränkt
void secure_boot_sequence(void) {
// SICHER: Debug DEAKTIVIEREN, BEVOR Schlüssel geladen werden
disable_debug_access();
// Überprüfen, ob Debug deaktiviert ist
if (is_debug_enabled()) {
panic("Debug nicht während Secure Boot deaktiviert!");
}
// Jetzt sicher, Schlüssel zu laden
load_boot_keys();
// Firmware-Signatur überprüfen
if (!verify_signature()) {
// Schlüssel vor dem Anhalten löschen
clear_boot_keys();
halt();
}
// Schlüssel aus dem Speicher nach Verwendung löschen
clear_boot_keys();
// Debug kann nach dem Boot bei Bedarf wieder aktiviert werden
// (mit ordnungsgemäßer Authentifizierung)
}
// SICHER: Debug-Berechtigung ordnungsgemäß geprüft
bool secure_debug_check(uint32_t addr, uint32_t access_level) {
uint32_t current_stage = get_boot_stage();
uint32_t max_level = get_max_debug_level(current_stage);
// Authentifizierung prüfen
if (!is_debug_authenticated()) {
return false;
}
// Zugriffslevel für Boot-Phase prüfen
if (access_level > max_level) {
log_security_event("Debug-Zugriffslevel-Verletzung: %d > %d",
access_level, max_level);
return false;
}
// Prüfen, ob Adresse auf diesem Level zugänglich ist
if (!is_address_accessible(addr, access_level)) {
return false;
}
return true;
}
uint32_t get_max_debug_level(uint32_t boot_stage) {
switch (boot_stage) {
case STAGE_ROM:
return ACCESS_NONE; // Kein Debug während ROM
case STAGE_BOOTLOADER:
return ACCESS_PRIVILEGED; // Eingeschränkter Zugriff
case STAGE_KERNEL:
return ACCESS_PRIVILEGED;
case STAGE_USER:
return ACCESS_USER; // Nur Benutzerebene
default:
return ACCESS_NONE;
}
}
CVE-Beispiele
- CVE-2019-18827: JTAG-Zugriff vor ROM-Code-Ausführung auf Barco ClickShare möglich
- Schwachstellen im Debug-Modus des CVA6-Prozessors
Verwandte CWEs
- CWE-863: Fehlerhafte Autorisierung (übergeordnet)
- CWE-1191: On-Chip Debug- und Testschnittstelle mit unsachgemäßer Zugriffskontrolle (verwandt)
- CWE-1243: Sensible nichtflüchtige Informationen nicht während Debug geschützt (verwandt)
Referenzen
- MITRE Corporation. "CWE-1244: Internal Asset Exposed to Unsafe Debug Access Level or State." https://cwe.mitre.org/data/definitions/1244.html
- REF-1377, REF-1378: CVA6 Processor Vulnerability Examples
- REF-1056: Barco ClickShare JTAG Vulnerabilities