Veränderbare Attestierungs- oder Messdaten
Beschreibung
Veränderbare Attestierungs- oder Messdaten treten auf, wenn Attestierungs- oder Messregister, die in sicheren Boot-Prozessen verwendet werden, von Angreifern modifiziert werden können, wodurch sie die Integritätsmessungen des Boot-Ablaufs fälschen können. Während des sicheren/verifizierten Boots eines SoC berechnen Systeme kryptographische Hashes von Code-Binärdateien und erweitern diese sequenziell. Diese endgültigen Hash-Werte — gespeichert in Registern für spätere Attestierung — können gelesen werden, um Manipulationen zu erkennen. Die Schwachstelle tritt auf, wenn diese Register keinen angemessenen Schutz haben, was es Angreifern ermöglicht, beliebige Hash-Werte zu schreiben und Boot-Integritätsaussagen zu fälschen.
Risiko
Veränderbare Attestierungsdaten haben schwerwiegende Sicherheitsauswirkungen. Boot-Integrität kann vorgetäuscht werden. Messketten können gefälscht werden. Attestierungsberichte werden unzuverlässig. Bösartiger Boot bleibt unerkannt. Vertrauensverifizierung wird umgangen. Remote-Attestierung wird kompromittiert. TPM-ähnliche Garantien gehen verloren. Secure Boot kann überwunden werden.
Lösung
Speichern Sie Messdaten in Registern mit Nur-Lese-Zugriffsschutz. Stellen Sie Unveränderlichkeit gegen direkte oder indirekte Modifikation sicher. Implementieren Sie angemessene Zugriffskontrollen, die Modifikation durch nicht vertrauenswürdige Agenten verhindern. Verwenden Sie Nur-Erweiterungsoperationen für Messungen. Sperren Sie Messregister nach Abschluss des Boots. Überprüfen Sie den Schutz der Messregister in Sicherheitsaudits.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Falsche Attestierung ermöglicht unbefugten Zugriff. |
| Integrität | Bereich: Integrität Speicher modifizieren - Messdaten können gefälscht werden. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Attestierungsverifizierung wird umgangen. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Messregister ohne Schreibschutz
module vulnerable_measurement_engine (
input wire clk,
input wire reset_n,
input wire [255:0] hash_input,
input wire extend_command,
input wire [7:0] pcr_select,
input wire [255:0] direct_write_data,
input wire direct_write_enable,
input wire [3:0] requester_id,
output reg [255:0] pcr_read_data,
output reg measurement_done
);
// Platform Configuration Registers (PCRs)
reg [255:0] pcr [0:23];
// VERWUNDBAR: PCRs können direkt geschrieben werden
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// PCRs auf Null initialisieren
integer i;
for (i = 0; i < 24; i = i + 1) begin
pcr[i] <= 256'h0;
end
measurement_done <= 1'b0;
end
else begin
measurement_done <= 1'b0;
if (extend_command) begin
// Normale Erweiterungsoperation: PCR = Hash(PCR || neue_Daten)
pcr[pcr_select] <= sha256({pcr[pcr_select], hash_input});
measurement_done <= 1'b1;
end
// VERWUNDBAR: Direktes Schreiben in PCRs erlaubt
if (direct_write_enable) begin
// Jeder Anfragende kann beliebige Werte schreiben!
pcr[pcr_select] <= direct_write_data;
// Angreifer kann:
// 1. PCR auf erwarteten "guten" Wert setzen
// 2. Bösartige Boot-Komponenten verstecken
// 3. Attestierung mit kompromittiertem System bestehen
end
end
end
// PCR-Wert lesen
always @(*) begin
pcr_read_data = pcr[pcr_select];
end
endmodule
// VERWUNDBAR: Attestierungsbericht aus veränderbarer Quelle
module vulnerable_attestation (
input wire clk,
input wire reset_n,
input wire generate_report,
input wire [7:0] pcr_mask,
output reg [2047:0] attestation_report,
output reg report_valid
);
// VERWUNDBAR: Messregister können modifiziert werden
reg [255:0] measurements [0:7];
// VERWUNDBAR: Jeder kann Messungen aktualisieren
input wire [255:0] measurement_update;
input wire [2:0] measurement_select;
input wire update_measurement;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
report_valid <= 1'b0;
end
else begin
// VERWUNDBAR: Keine Zugriffskontrolle bei Messungsaktualisierungen
if (update_measurement) begin
measurements[measurement_select] <= measurement_update;
end
if (generate_report) begin
// Bericht aus veränderbaren Messungen erstellen
// Bericht ist nicht vertrauenswürdig!
attestation_report <= {measurements[0], measurements[1],
measurements[2], measurements[3],
measurements[4], measurements[5],
measurements[6], measurements[7]};
report_valid <= 1'b1;
end
end
end
endmodule
// VERWUNDBAR: Software mit veränderbarem Messungsspeicher
#include <stdint.h>
// VERWUNDBAR: Messungen in beschreibbarem Speicher gespeichert
static uint8_t pcr_values[24][32]; // In .bss - beschreibbar
// VERWUNDBAR: Direkte PCR-Schreibfunktion
void vulnerable_pcr_write(uint8_t pcr_index, const uint8_t* value) {
// VERWUNDBAR: Keine Zugriffskontrolle
// Jeder Code kann beliebige Werte in PCRs schreiben
if (pcr_index < 24) {
memcpy(pcr_values[pcr_index], value, 32);
}
}
// VERWUNDBAR: Erweiterungsfunktion, die umgangen werden kann
void vulnerable_pcr_extend(uint8_t pcr_index, const uint8_t* data, size_t len) {
if (pcr_index >= 24) return;
// Normale Erweiterung: neuer_Wert = SHA256(alter_Wert || Daten)
uint8_t buffer[64];
memcpy(buffer, pcr_values[pcr_index], 32);
memcpy(buffer + 32, data, len > 32 ? 32 : len);
sha256(buffer, 64, pcr_values[pcr_index]);
// Problem: Angreifer kann vulnerable_pcr_write() direkt aufrufen
// um PCR auf beliebigen Wert zu setzen und die Erweiterungskette zu umgehen
}
// VERWUNDBAR: Attestierung mit veränderbaren PCRs
bool vulnerable_generate_attestation(uint8_t* report, size_t* report_len) {
// PCR-Werte zitieren (die möglicherweise manipuliert wurden)
for (int i = 0; i < 24; i++) {
memcpy(report + i * 32, pcr_values[i], 32);
}
// Mit Attestierungsschlüssel signieren
sign_report(report, 24 * 32);
*report_len = 24 * 32 + 64; // PCRs + Signatur
return true;
// Bericht ist signiert, aber PCR-Werte sind nicht vertrauenswürdig
}
Sichere Lösung
// SICHER: Messregister mit Schreibschutz
module secure_measurement_engine (
input wire clk,
input wire reset_n,
input wire [255:0] hash_input,
input wire extend_command,
input wire [7:0] pcr_select,
input wire [3:0] requester_id,
input wire boot_complete,
output reg [255:0] pcr_read_data,
output reg measurement_done,
output reg access_denied,
output reg pcrs_locked
);
// Platform Configuration Registers (PCRs)
reg [255:0] pcr [0:23];
// SICHER: PCR-Sperrstatus - einmal gesperrt, nicht mehr änderbar
reg [23:0] pcr_lock;
// SICHER: Vertrauenswürdige Anfragende für verschiedene PCRs
parameter SECURE_BOOT_ROM = 4'd0;
parameter SECURE_BOOT_LOADER = 4'd1;
parameter OS_KERNEL = 4'd2;
// PCR-Zuweisungen
// PCR 0-3: Boot-ROM-Messungen (nur ROM)
// PCR 4-7: Bootloader-Messungen (nur Bootloader)
// PCR 8-15: OS-Messungen (nur Kernel)
// PCR 16-23: Anwendungsmessungen (verschiedene)
function automatic is_pcr_writable;
input [7:0] pcr_idx;
input [3:0] requester;
begin
is_pcr_writable = 1'b0;
// PCR-Bereich und Anfragenden prüfen
if (pcr_idx < 4 && requester == SECURE_BOOT_ROM) begin
is_pcr_writable = 1'b1;
end
else if (pcr_idx >= 4 && pcr_idx < 8 && requester == SECURE_BOOT_LOADER) begin
is_pcr_writable = 1'b1;
end
else if (pcr_idx >= 8 && pcr_idx < 16 && requester == OS_KERNEL) begin
is_pcr_writable = 1'b1;
end
// PCR 16-23 haben flexiblere Richtlinien
end
endfunction
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
integer i;
for (i = 0; i < 24; i = i + 1) begin
pcr[i] <= 256'h0;
end
pcr_lock <= 24'h0;
measurement_done <= 1'b0;
access_denied <= 1'b0;
pcrs_locked <= 1'b0;
end
else begin
measurement_done <= 1'b0;
access_denied <= 1'b0;
// SICHER: PCRs nach dem Boot sperren
if (boot_complete) begin
pcr_lock <= 24'hFFFFFF; // Alle PCRs sperren
pcrs_locked <= 1'b1;
end
if (extend_command) begin
// SICHER: Prüfen, ob PCR gesperrt ist
if (pcr_lock[pcr_select]) begin
access_denied <= 1'b1;
end
// SICHER: Autorisierung des Anfragenden prüfen
else if (!is_pcr_writable(pcr_select, requester_id)) begin
access_denied <= 1'b1;
end
else begin
// SICHER: Nur Erweiterungsoperation - kein direktes Schreiben
pcr[pcr_select] <= sha256({pcr[pcr_select], hash_input});
measurement_done <= 1'b1;
end
end
// SICHER: Keine direkte Schreibschnittstelle
// PCRs können nur durch Erweiterungsoperation modifiziert werden
end
end
// PCR-Wert lesen (immer erlaubt)
always @(*) begin
pcr_read_data = pcr[pcr_select];
end
endmodule
// SICHER: Sichere Attestierung mit geschützten Messungen
module secure_attestation (
input wire clk,
input wire reset_n,
input wire generate_report,
input wire [23:0] pcr_mask,
input wire [255:0] nonce,
input wire [3:0] requester_id,
output reg [2047:0] attestation_report,
output reg report_valid,
output reg report_signed
);
// SICHER: Messungen von geschützter PCR-Engine
wire [255:0] pcr_values [0:23];
wire pcrs_locked;
secure_measurement_engine pcr_engine (
// ... Verbindungen ...
.pcrs_locked(pcrs_locked)
);
// SICHER: Attestierungsschlüssel in Hardware
wire [255:0] attestation_private_key; // Aus sicherem Schlüsselspeicher
// Zustandsautomat für Attestierung
reg [2:0] attest_state;
parameter IDLE = 3'd0;
parameter COLLECT = 3'd1;
parameter HASH = 3'd2;
parameter SIGN = 3'd3;
parameter DONE = 3'd4;
reg [7:0] pcr_index;
reg [2047:0] report_buffer;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
report_valid <= 1'b0;
report_signed <= 1'b0;
attest_state <= IDLE;
end
else begin
case (attest_state)
IDLE: begin
report_valid <= 1'b0;
report_signed <= 1'b0;
if (generate_report) begin
// SICHER: Bericht nur erstellen, wenn PCRs gesperrt sind
if (pcrs_locked) begin
attest_state <= COLLECT;
pcr_index <= 8'h0;
report_buffer <= {nonce, 1792'h0}; // Nonce einschließen
end
end
end
COLLECT: begin
// SICHER: PCR-Werte von geschützter Engine sammeln
if (pcr_mask[pcr_index]) begin
// Diesen PCR in Bericht aufnehmen
report_buffer <= {report_buffer, pcr_values[pcr_index]};
end
pcr_index <= pcr_index + 1;
if (pcr_index >= 23) begin
attest_state <= HASH;
end
end
HASH: begin
// Bericht zum Signieren hashen
attest_state <= SIGN;
end
SIGN: begin
// SICHER: Mit geschütztem Attestierungsschlüssel signieren
// Signatur beweist, dass der Bericht von diesem Gerät stammt
attestation_report <= sign_ecdsa(report_buffer,
attestation_private_key);
report_signed <= 1'b1;
attest_state <= DONE;
end
DONE: begin
report_valid <= 1'b1;
attest_state <= IDLE;
end
endcase
end
end
endmodule
// SICHER: Software mit geschütztem Messungsspeicher
#include <stdint.h>
#include <stdbool.h>
// SICHER: PCR-Operationen gehen über ein hardware-basiertes TPM-ähnliches Modul
#define TPM_PCR_EXTEND_REG 0x50001000
#define TPM_PCR_READ_REG 0x50001004
#define TPM_PCR_SELECT_REG 0x50001008
#define TPM_STATUS_REG 0x5000100C
#define TPM_PCR_LOCKED_BIT 0x01
// SICHER: PCRs sind in Hardware, Software hat nur Erweiterungsschnittstelle
static bool pcr_extend(uint8_t pcr_index, const uint8_t* data, size_t len) {
volatile uint32_t* pcr_select = (volatile uint32_t*)TPM_PCR_SELECT_REG;
volatile uint32_t* status = (volatile uint32_t*)TPM_STATUS_REG;
volatile uint32_t* extend_reg = (volatile uint32_t*)TPM_PCR_EXTEND_REG;
if (pcr_index >= 24) {
return false;
}
// Prüfen, ob PCRs gesperrt sind
if (*status & TPM_PCR_LOCKED_BIT) {
log_error("PCRs sind gesperrt");
return false;
}
// PCR auswählen
*pcr_select = pcr_index;
// SICHER: Nur Erweiterungsoperation verfügbar - kein direktes Schreiben
// Hardware führt aus: PCR = SHA256(PCR || Daten)
for (size_t i = 0; i < len; i += 4) {
uint32_t word;
memcpy(&word, data + i, 4);
*extend_reg = word;
}
// Auf Abschluss der Operation warten
while (!(*status & TPM_EXTEND_COMPLETE_BIT)) {
// Warten
}
return true;
}
// SICHER: PCR aus Hardware lesen
static bool pcr_read(uint8_t pcr_index, uint8_t* value) {
volatile uint32_t* pcr_select = (volatile uint32_t*)TPM_PCR_SELECT_REG;
volatile uint32_t* read_reg = (volatile uint32_t*)TPM_PCR_READ_REG;
if (pcr_index >= 24) {
return false;
}
*pcr_select = pcr_index;
// 32 Bytes (256 Bits) lesen
for (int i = 0; i < 8; i++) {
uint32_t word = read_reg[i];
memcpy(value + i * 4, &word, 4);
}
return true;
}
// SICHER: Keine direkte PCR-Schreibfunktion
// void pcr_write(...) - EXISTIERT NICHT
// SICHER: Attestierung mit hardware-geschützten PCRs
bool secure_generate_attestation(const uint8_t* nonce, size_t nonce_len,
uint8_t* report, size_t* report_len) {
attestation_request_t req;
attestation_response_t resp;
// Anfrage mit Nonce erstellen (für Aktualität)
memcpy(req.nonce, nonce, nonce_len);
req.pcr_mask = 0x00FFFFFF; // Alle 24 PCRs
// SICHER: Attestierung von Hardware-TPM anfordern
// Hardware liest PCRs und signiert mit geschütztem Schlüssel
if (!tpm_generate_quote(&req, &resp)) {
return false;
}
// SICHER: Überprüfen, dass Signatur von diesem TPM stammt
if (!verify_quote_signature(&resp)) {
log_error("Quote-Signaturverifizierung fehlgeschlagen");
return false;
}
memcpy(report, resp.quote, resp.quote_len);
*report_len = resp.quote_len;
return true;
}
// SICHER: PCRs nach dem Boot sperren
void finalize_measurements(void) {
volatile uint32_t* tpm_ctrl = (volatile uint32_t*)TPM_CONTROL_REG;
// Alle PCRs sperren - kann ohne Reset nicht entsperrt werden
*tpm_ctrl |= TPM_LOCK_PCRS;
// Sperre verifizieren
volatile uint32_t* status = (volatile uint32_t*)TPM_STATUS_REG;
if (!(*status & TPM_PCR_LOCKED_BIT)) {
log_error("PCR-Sperrung fehlgeschlagen");
secure_halt();
}
}
CVE-Beispiele
Schwachstellen bei veränderbaren Attestierungen wurden in TPM-ähnlichen Implementierungen gefunden, bei denen PCR-Register direkt geschrieben statt nur erweitert werden könnten, was es Angreifern ermöglichte, Attestierungsberichte zu fälschen.
Verwandte CWEs
- CWE-284: Unsachgemäße Zugriffskontrolle (übergeordnet)
- CWE-1196: Sicherheitsfluss-Probleme (Kategorie)
- CWE-1282: Als unveränderlich angenommene Daten werden in beschreibbarem Speicher gespeichert (verwandt)
- CAPEC-680: Ausnutzung unsachgemäß kontrollierter Register (Angriffsmuster)
Referenzen
- MITRE Corporation. "CWE-1283: Mutable Attestation or Measurement Reporting Data." https://cwe.mitre.org/data/definitions/1283.html
- TCG. "TPM 2.0 Library Specification"
- Intel. "PCIe Device Measurement Requirements"