Unsachgemäße Loschung sensibler Daten von ausgemusterten Geraten
Beschreibung
Unsachgemäße Loschung sensibler Daten von ausgemusterten Geraten tritt auf, wenn ein Produkt keine ausreichende Fahigkeit bietet, damit Administratoren sensible Daten entfernen können, wenn Gerate außer Betrieb genommen werden. Dieses Fehlen, die Unzulanglichkeit oder die Fehlerhaftigkeit der Löschfunktionalität erzeugt Schwachstellen. Best Practices für die Außerbetriebnahme und regulatorische Anforderungen schreiben oft die Datenentfernung vor der Gerateausmusterung vor. Wenn sensible Informationen nicht ordnungsgemäß geloscht werden, können böswillige Akteure diese von entsorgten oder recycelten Geraten wiederherstellen.
Risiko
Unzureichende Datenlöschung hat schwerwiegende Sicherheitsauswirkungen. Authentifizierungsdaten können wiederhergestellt werden. Netzwerkkonfigurationen können offengelegt werden. Kryptografische Schlüssel können extrahiert werden. Proprietare Informationen können durchsickern. Kundendaten können kompromittiert werden. Geistiges Eigentum kann gestohlen werden. Compliance-Verstöße können auftreten. Reputationsschäden kann durch Datenverletzungen entstehen.
Lösung
Integrieren Sie umfassende Datenloschfunktionalitat während des initialen Designs, anstatt sie später nachzurusten. Dokumentieren Sie Speicherorte, Entfernungsrichtlinien und -verfahren in Administrationshandbuchern oder Volatilitätsaussagen. Stellen Sie Hilfsprogramme zum Loschen sensibler Daten aus nicht zuganglichen Speicherbereichen wie EEPROMs bereit. Implementieren Sie kryptografische Loschung, wo angemessen. Uberprüfen Sie die Wirksamkeit der Loschung durch Tests.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Speicher lesen - Angreifer erhalten unbefugten Zugriff auf gespeicherte sensible Informationen von ausgemusterten Geraten. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Gerat ohne Datenlöschfähigkeit
#include <stdint.h>
#define EEPROM_BASE 0x50000000
#define EEPROM_SIZE 4096
// Speicher für sensible Daten
typedef struct {
uint8_t wifi_ssid[32];
uint8_t wifi_password[64];
uint8_t admin_password[32];
uint8_t api_key[64];
uint8_t encryption_key[32];
uint8_t certificate[1024];
} device_credentials_t;
// VERWUNDBAR: Keine Loschfunktion vorgesehen
// Gerat speichert Anmeldedaten dauerhaft
void vulnerable_store_credentials(device_credentials_t* creds) {
// Anmeldedaten ins EEPROM schreiben
volatile uint8_t* eeprom = (volatile uint8_t*)EEPROM_BASE;
memcpy((void*)eeprom, creds, sizeof(device_credentials_t));
}
void vulnerable_factory_reset(void) {
// VERWUNDBAR: Setzt nur Konfigurations-Flags zurück
// Loscht KEINE Anmeldedaten aus dem EEPROM
config_flags = DEFAULT_FLAGS;
reboot_device();
// Anmeldedaten bleiben im EEPROM!
// Wenn Gerat ausgemustert wird, kann Angreifer:
// 1. EEPROM-Chip entfernen
// 2. Mit Programmer auslesen
// 3. Alle Anmeldedaten extrahieren
}
// VERWUNDBAR: Keine Datenzerstörung bei Außerbetriebnahme
void vulnerable_shutdown(void) {
// Normales Herunterfahren - Daten bleiben erhalten
save_state_to_flash();
power_down();
}
// VERWUNDBAR: Hardware ohne sichere Loschfunktion
module vulnerable_secure_storage (
input wire clk,
input wire reset_n,
input wire [7:0] addr,
input wire [31:0] write_data,
input wire write_enable,
input wire read_enable,
output reg [31:0] read_data
);
// Nichtfluchtiger Speicher (NVM)
reg [31:0] nvm_storage [0:255];
// VERWUNDBAR: Kein Befehl zum sicheren Loschen
// Daten bleiben auf unbestimmte Zeit erhalten
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// VERWUNDBAR: Reset loscht NVM nicht
// Loscht nur fluchtigen Zustand
read_data <= 32'h0;
end
else if (write_enable) begin
nvm_storage[addr] <= write_data;
end
else if (read_enable) begin
read_data <= nvm_storage[addr];
end
end
// Kein Befehl zum sicheren Loschen des gesamten Speichers
// Keine Verifizierung, dass Daten tatsachlich geloscht wurden
// Keine Nullung bei Manipulation oder Außerbetriebnahme
endmodule
// VERWUNDBAR: Gerat mit unvollständiger Loschung
module vulnerable_partial_scrub (
input wire clk,
input wire reset_n,
input wire scrub_command,
input wire [7:0] scrub_addr,
output reg scrub_complete
);
reg [31:0] config_storage [0:63]; // Wird geloscht
reg [31:0] key_storage [0:31]; // VERWUNDBAR: NICHT geloscht
reg [31:0] log_storage [0:127]; // VERWUNDBAR: NICHT geloscht
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
scrub_complete <= 1'b0;
end
else if (scrub_command) begin
// VERWUNDBAR: Loscht nur Konfiguration, ubersieht Schlüssel und Logs
config_storage[scrub_addr] <= 32'h0;
// key_storage und log_storage werden NICHT geloscht!
// Angreifer kann noch wiederherstellen:
// - Verschlüsselungsschlüssel
// - Zugriffsprotokolle mit Benutzerinformationen
// - Netzwerkanmeldedaten in Protokollen gespeichert
scrub_complete <= 1'b1;
end
end
endmodule
Sichere Lösung
// SICHER: Gerat mit umfassender Datenlöschung
#include <stdint.h>
#include <string.h>
#define EEPROM_BASE 0x50000000
#define EEPROM_SIZE 4096
#define SCRUB_PATTERN_COUNT 3
typedef struct {
uint8_t wifi_ssid[32];
uint8_t wifi_password[64];
uint8_t admin_password[32];
uint8_t api_key[64];
uint8_t encryption_key[32];
uint8_t certificate[1024];
} device_credentials_t;
// Dokumentierte Speicherorte für Außerbetriebnahme
typedef struct {
const char* name;
uint32_t address;
uint32_t size;
bool contains_sensitive_data;
} storage_location_t;
static const storage_location_t storage_map[] = {
{"Anmeldedaten", 0x0000, sizeof(device_credentials_t), true},
{"Verschlüsselungsschlüssel", 0x1000, 256, true},
{"Protokolle", 0x2000, 1024, true},
{"Konfiguration", 0x3000, 512, false},
{NULL, 0, 0, false}
};
// SICHER: Sicheres Loschen mit Verifizierung
static void secure_memset(volatile void* ptr, uint8_t value, size_t size) {
volatile uint8_t* p = (volatile uint8_t*)ptr;
while (size--) {
*p++ = value;
}
// Speicherbarriere
__asm__ volatile("" ::: "memory");
}
// SICHER: Mehrfach-Überschreibung für sichere Loschung
static bool secure_erase_region(uint32_t address, uint32_t size) {
volatile uint8_t* ptr = (volatile uint8_t*)(EEPROM_BASE + address);
// Muster 1: Alles Nullen
secure_memset(ptr, 0x00, size);
if (!verify_pattern(ptr, 0x00, size)) return false;
// Muster 2: Alles Einsen
secure_memset(ptr, 0xFF, size);
if (!verify_pattern(ptr, 0xFF, size)) return false;
// Muster 3: Zufallsdaten
uint8_t* random_data = get_random_bytes(size);
memcpy((void*)ptr, random_data, size);
free(random_data);
// Muster 4: Abschließende Nullen
secure_memset(ptr, 0x00, size);
if (!verify_pattern(ptr, 0x00, size)) return false;
return true;
}
// SICHER: Loschung verifizieren
static bool verify_pattern(volatile uint8_t* ptr, uint8_t expected, size_t size) {
for (size_t i = 0; i < size; i++) {
if (ptr[i] != expected) {
return false;
}
}
return true;
}
// SICHER: Umfassende Loschfunktion
int secure_decommission(void) {
int errors = 0;
log_event("Starte sichere Außerbetriebnahme");
// SICHER: Alle dokumentierten Speicherorte loschen
for (int i = 0; storage_map[i].name != NULL; i++) {
log_event("Losche: %s", storage_map[i].name);
if (!secure_erase_region(storage_map[i].address, storage_map[i].size)) {
log_error("Loschung fehlgeschlagen: %s", storage_map[i].name);
errors++;
}
}
// SICHER: RAM mit sensiblen Daten loschen
clear_sensitive_ram();
// SICHER: Verschlüsselungsschlüssel in Hardware ungültig machen
invalidate_hw_keys();
// SICHER: Alle zwischengespeicherten Anmeldedaten loschen
clear_credential_cache();
// SICHER: Bericht erstellen
generate_decommission_report();
if (errors == 0) {
log_event("Sichere Außerbetriebnahme abgeschlossen");
return 0;
} else {
log_error("Außerbetriebnahme unvollständig: %d Fehler", errors);
return -1;
}
}
// SICHER: Werksreset mit Anmeldedaten-Loschung
void secure_factory_reset(void) {
// Zuerst alle sensiblen Daten loschen
secure_decommission();
// Dann Konfiguration zurücksetzen
config_flags = DEFAULT_FLAGS;
// Loschung vor Neustart verifizieren
if (!verify_all_scrubbed()) {
// Sicher fehlschlagen - Gerat nicht weiterlaufen lassen
enter_lockout_mode();
}
reboot_device();
}
// SICHER: Hardware mit umfassender sicherer Loschung
module secure_storage_with_scrub (
input wire clk,
input wire reset_n,
input wire [7:0] addr,
input wire [31:0] write_data,
input wire write_enable,
input wire read_enable,
// SICHER: Sichere Losch-Schnittstelle
input wire scrub_all_command,
input wire scrub_verify_command,
output reg [31:0] read_data,
output reg scrub_complete,
output reg scrub_verified,
output reg scrub_error
);
// Speicher-Arrays
reg [31:0] config_storage [0:63];
reg [31:0] key_storage [0:31];
reg [31:0] log_storage [0:127];
// SICHER: Losch-Zustandsmaschine
reg [2:0] scrub_state;
reg [7:0] scrub_index;
reg [1:0] scrub_pass;
parameter IDLE = 3'd0;
parameter SCRUB_CONFIG = 3'd1;
parameter SCRUB_KEYS = 3'd2;
parameter SCRUB_LOGS = 3'd3;
parameter VERIFY = 3'd4;
parameter DONE = 3'd5;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
scrub_state <= IDLE;
scrub_complete <= 1'b0;
scrub_verified <= 1'b0;
scrub_error <= 1'b0;
scrub_index <= 8'h0;
scrub_pass <= 2'd0;
end
else begin
case (scrub_state)
IDLE: begin
scrub_complete <= 1'b0;
scrub_verified <= 1'b0;
scrub_error <= 1'b0;
if (scrub_all_command) begin
scrub_state <= SCRUB_CONFIG;
scrub_index <= 8'h0;
scrub_pass <= 2'd0;
end
end
SCRUB_CONFIG: begin
// SICHER: GESAMTEN Konfigurationsspeicher loschen
if (scrub_index < 64) begin
// Mehrfach-Überschreibung
case (scrub_pass)
2'd0: config_storage[scrub_index] <= 32'h00000000;
2'd1: config_storage[scrub_index] <= 32'hFFFFFFFF;
2'd2: config_storage[scrub_index] <= 32'h00000000;
endcase
if (scrub_pass == 2'd2) begin
scrub_index <= scrub_index + 1;
scrub_pass <= 2'd0;
end
else begin
scrub_pass <= scrub_pass + 1;
end
end
else begin
scrub_index <= 8'h0;
scrub_pass <= 2'd0;
scrub_state <= SCRUB_KEYS;
end
end
SCRUB_KEYS: begin
// SICHER: GESAMTEN Schlüsselspeicher loschen
if (scrub_index < 32) begin
case (scrub_pass)
2'd0: key_storage[scrub_index] <= 32'h00000000;
2'd1: key_storage[scrub_index] <= 32'hFFFFFFFF;
2'd2: key_storage[scrub_index] <= 32'h00000000;
endcase
if (scrub_pass == 2'd2) begin
scrub_index <= scrub_index + 1;
scrub_pass <= 2'd0;
end
else begin
scrub_pass <= scrub_pass + 1;
end
end
else begin
scrub_index <= 8'h0;
scrub_pass <= 2'd0;
scrub_state <= SCRUB_LOGS;
end
end
SCRUB_LOGS: begin
// SICHER: GESAMTEN Protokollspeicher loschen
if (scrub_index < 128) begin
case (scrub_pass)
2'd0: log_storage[scrub_index] <= 32'h00000000;
2'd1: log_storage[scrub_index] <= 32'hFFFFFFFF;
2'd2: log_storage[scrub_index] <= 32'h00000000;
endcase
if (scrub_pass == 2'd2) begin
scrub_index <= scrub_index + 1;
scrub_pass <= 2'd0;
end
else begin
scrub_pass <= scrub_pass + 1;
end
end
else begin
scrub_index <= 8'h0;
scrub_state <= VERIFY;
end
end
VERIFY: begin
// SICHER: Verifizieren dass gesamter Speicher genullt ist
if (scrub_index < 64 && config_storage[scrub_index] != 32'h0) begin
scrub_error <= 1'b1;
end
else if (scrub_index < 32 && key_storage[scrub_index] != 32'h0) begin
scrub_error <= 1'b1;
end
else if (scrub_index < 128 && log_storage[scrub_index] != 32'h0) begin
scrub_error <= 1'b1;
end
scrub_index <= scrub_index + 1;
if (scrub_index >= 128) begin
scrub_state <= DONE;
end
end
DONE: begin
scrub_complete <= 1'b1;
scrub_verified <= !scrub_error;
scrub_state <= IDLE;
end
endcase
end
end
endmodule
CVE-Beispiele
Datenwiederherstellung von ausgemusterten Geraten wurde in zahlreichen Fallen nachgewiesen, darunter:
- Medizinische Gerate mit Patientendaten
- Netzwerkausrustung mit Anmeldedaten
- Unternehmensspeicher mit vertraulichen Daten
- Kassenterminals mit Zahlungsinformationen
Verwandte CWEs
- CWE-404: Unsachgemäßes Herunterfahren oder Freigeben von Ressourcen (ubergeordnet)
- CWE-226: Sensible Informationen in Ressource nicht vor Wiederverwendung entfernt (verwandt)
- CWE-459: Unvollständige Bereinigung (verwandt)
- CAPEC-150: Daten von allgemeinen Ressourcenstandorten sammeln (Angriffsmuster)
- CAPEC-675: Daten von ausgemusterten Geraten abrufen (Angriffsmuster)
Referenzen
- MITRE Corporation. "CWE-1266: Improper Scrubbing of Sensitive Data from Decommissioned Device." https://cwe.mitre.org/data/definitions/1266.html
- NIST SP 800-88. "Guidelines for Media Sanitization"
- FIPS 140-3. "Zeroization Requirements"