Klartext-Speicherung in der Registry
Beschreibung
Klartext-Speicherung in der Registry ist eine Windows-spezifische Schwachstelle, bei der ein Produkt sensible Informationen im Klartext in der Windows-Registry speichert. Die Windows-Registry ist eine hierarchische Datenbank, die Konfigurationseinstellungen und Optionen für das Betriebssystem und Anwendungen speichert. Wenn sensible Daten wie Passwörter, API-Schlüssel oder Verschlüsselungsschlüssel ohne Verschlüsselung in Registry-Schlüsseln gespeichert werden, werden sie für jeden zugänglich, der die entsprechenden Registry-Zugriffsberechtigungen hat. Selbst kodierte Daten (wie Base64) bieten keine echte Sicherheit, da Angreifer leicht die Kodierungsmethode bestimmen und die Informationen dekodieren können.
Risiko
Klartext-Registry-Speicherung exponiert sensible Daten gegenüber mehreren Bedrohungsvektoren auf Windows-Systemen. Lokale Benutzer mit Registry-Lesezugriff können gespeicherte Anmeldedaten einsehen. Malware scannt häufig Registry-Speicherorte nach gespeicherten Passwörtern und Anmeldedaten. Administrative Tools und Backup-Utilities können Registry-Inhalte exponieren. Remote-Registry-Zugriff, falls aktiviert, erweitert die Angriffsfläche auf netzwerkbasierte Angreifer. Registry-Exportdateien (.reg), die sensible Daten enthalten, können unbeabsichtigt geteilt oder unsicher gespeichert werden. Die Persistenz und zentrale Natur der Registry macht sie zu einem attraktiven Ziel für Credential-Harvesting-Angriffe. Im Gegensatz zu Dateispeicherung kann Registry-Zugriff weniger überwacht werden, was Angreifern ermöglicht, Daten zu extrahieren, ohne Alarme auszulösen.
Lösung
Vermeiden Sie die Speicherung sensibler Informationen in der Registry, wann immer möglich. Wenn Registry-Speicherung notwendig ist, verschlüsseln Sie sensible Werte vor der Speicherung mit der Windows Data Protection API (DPAPI) oder anderen starken Verschlüsselungsmechanismen. Verwenden Sie DPAPI mit Benutzerbereich, um die Verschlüsselung an spezifische Benutzerkontexte zu binden, oder Maschinenbereich mit zusätzlichen Zugriffskontrollen. Implementieren Sie den Windows Credential Manager oder Credential Locker für sichere Anmeldedatenspeicherung. Setzen Sie angemessene Registry-Schlüsselberechtigungen (ACLs), um den Zugriff auf notwendige Konten zu beschränken. Speichern Sie niemals Klartext-Passwörter oder Verschlüsselungsschlüssel in der Registry. Erwägen Sie zertifikatsbasierte Authentifizierung oder Windows-Credential-Provider für Anwendungsauthentifizierung anstelle von in der Registry gespeicherten Anmeldedaten.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Angreifer mit Registry-Zugriff können sensible Informationen direkt lesen. Selbst kodierte Daten können leicht dekodiert werden, sobald die Kodierungsmethode identifiziert ist, was keinen bedeutungsvollen Schutz bietet. |
Beispielcode
Anfälliger Code (C#/C++)
Die folgenden Beispiele demonstrieren Klartext-Registry-Speicherungs-Schwachstellen:
// Anfällig: Anmeldedaten im Klartext in Registry speichern
using Microsoft.Win32;
public class VulnerableRegistryStorage
{
private const string RegKeyPath = @"SOFTWARE\MyApplication";
public void SaveCredentials(string username, string password)
{
// Anfällig: Klartext-Anmeldedaten in Registry
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegKeyPath))
{
key.SetValue("Username", username);
key.SetValue("Password", password); // Klartext!
}
}
public void SaveDatabaseConfig(string connectionString)
{
// Anfällig: Connection-String mit eingebettetem Passwort
// "Server=db.example.com;Database=App;User=admin;Password=SecretPass123;"
using (RegistryKey key = Registry.LocalMachine.CreateSubKey(RegKeyPath))
{
key.SetValue("ConnectionString", connectionString); // Enthält Passwort!
}
}
public void SaveApiKeys(Dictionary<string, string> keys)
{
// Anfällig: API-Schlüssel im Klartext
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegKeyPath + @"\ApiKeys"))
{
foreach (var apiKey in keys)
{
key.SetValue(apiKey.Key, apiKey.Value); // Klartext-API-Schlüssel!
}
}
}
}
// Anfällig: C++ Klartext-Registry-Speicherung
#include <windows.h>
#include <string>
class VulnerableConfig {
public:
bool SavePassword(const std::wstring& password) {
HKEY hKey;
// Anfällig: Registry-Schlüssel für Passwortspeicherung erstellen
LONG result = RegCreateKeyExW(
HKEY_CURRENT_USER,
L"SOFTWARE\\MyApp\\Credentials",
0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL
);
if (result != ERROR_SUCCESS) {
return false;
}
// Anfällig: Passwort als Klartext-String speichern
result = RegSetValueExW(
hKey,
L"Password",
0,
REG_SZ,
(LPBYTE)password.c_str(),
(DWORD)((password.length() + 1) * sizeof(wchar_t))
);
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
bool SaveEncryptionKey(const BYTE* key, DWORD keySize) {
HKEY hKey;
LONG result = RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\MyApp\\Crypto",
0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL
);
if (result != ERROR_SUCCESS) {
return false;
}
// Anfällig: Verschlüsselungsschlüssel im Klartext-Binärformat speichern
result = RegSetValueExW(
hKey,
L"MasterKey",
0,
REG_BINARY,
key, // Klartext-Verschlüsselungsschlüssel!
keySize
);
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
};
' Anfällig: VBScript/VBA Registry-Speicherung
Sub SaveCredentials(username, password)
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")
' Anfällig: Klartext-Anmeldedaten in Registry
WshShell.RegWrite "HKCU\SOFTWARE\MyApp\Username", username, "REG_SZ"
WshShell.RegWrite "HKCU\SOFTWARE\MyApp\Password", password, "REG_SZ" ' Klartext!
Set WshShell = Nothing
End Sub
Korrigierter Code (C#/C++)
// Korrigiert: Sichere Anmeldedatenspeicherung mit DPAPI und Credential Manager
using Microsoft.Win32;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using CredentialManagement; // Oder P/Invoke für CredWrite/CredRead verwenden
public class SecureRegistryStorage
{
private const string RegKeyPath = @"SOFTWARE\MyApplication";
// Korrigiert: Windows Credential Manager für Anmeldedaten verwenden
public void SaveCredentials(string target, string username, string password)
{
using (var cred = new Credential())
{
cred.Target = target;
cred.Username = username;
cred.Password = password;
cred.Type = CredentialType.Generic;
cred.PersistanceType = PersistanceType.LocalComputer;
cred.Save();
}
// Anmeldedaten sicher von Windows gespeichert
}
public NetworkCredential GetCredentials(string target)
{
using (var cred = new Credential())
{
cred.Target = target;
if (cred.Load())
{
return new NetworkCredential(cred.Username, cred.Password);
}
}
return null;
}
// Korrigiert: Vor Registry-Speicherung mit DPAPI verschlüsseln
public void SaveEncryptedConfig(string configData)
{
// Korrigiert: Mit DPAPI im Benutzerbereich verschlüsseln
byte[] plainBytes = Encoding.UTF8.GetBytes(configData);
byte[] encryptedBytes = ProtectedData.Protect(
plainBytes,
null, // Optionale Entropie
DataProtectionScope.CurrentUser
);
// Verschlüsselte Daten speichern
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegKeyPath))
{
key.SetValue("EncryptedConfig", encryptedBytes);
}
// Korrigiert: Klartext aus dem Speicher löschen
Array.Clear(plainBytes, 0, plainBytes.Length);
}
public string GetEncryptedConfig()
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegKeyPath))
{
if (key == null) return null;
byte[] encryptedBytes = (byte[])key.GetValue("EncryptedConfig");
if (encryptedBytes == null) return null;
// Korrigiert: Mit DPAPI entschlüsseln
byte[] plainBytes = ProtectedData.Unprotect(
encryptedBytes,
null,
DataProtectionScope.CurrentUser
);
string result = Encoding.UTF8.GetString(plainBytes);
// Korrigiert: Entschlüsselte Daten aus dem Speicher löschen
Array.Clear(plainBytes, 0, plainBytes.Length);
return result;
}
}
// Korrigiert: Connection-String-Builder ohne Passwortspeicherung verwenden
public void SaveDatabaseConfig(string server, string database)
{
// Korrigiert: Nur nicht-sensible Verbindungsinfos speichern
// Passwort zur Laufzeit aus Credential Manager geholt
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegKeyPath))
{
key.SetValue("DbServer", server);
key.SetValue("DbName", database);
// Passwort NICHT in Registry gespeichert
}
}
}
// Korrigiert: C++ sichere Registry-Speicherung mit DPAPI
#include <windows.h>
#include <wincred.h>
#include <dpapi.h>
#include <string>
#include <vector>
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "credui.lib")
class SecureConfig {
public:
// Korrigiert: Windows Credential Manager verwenden
bool SavePassword(const std::wstring& target, const std::wstring& username,
const std::wstring& password) {
CREDENTIALW cred = {0};
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = const_cast<LPWSTR>(target.c_str());
cred.UserName = const_cast<LPWSTR>(username.c_str());
cred.CredentialBlob = (LPBYTE)password.c_str();
cred.CredentialBlobSize = (DWORD)((password.length() + 1) * sizeof(wchar_t));
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
return CredWriteW(&cred, 0) != FALSE;
}
bool GetPassword(const std::wstring& target, std::wstring& password) {
PCREDENTIALW pCred = nullptr;
if (!CredReadW(target.c_str(), CRED_TYPE_GENERIC, 0, &pCred)) {
return false;
}
password = std::wstring(
(wchar_t*)pCred->CredentialBlob,
pCred->CredentialBlobSize / sizeof(wchar_t)
);
// Korrigiert: Credential sicher freigeben
CredFree(pCred);
return true;
}
// Korrigiert: Daten vor Registry-Speicherung verschlüsseln
bool SaveEncryptedKey(const BYTE* key, DWORD keySize) {
DATA_BLOB dataIn = {keySize, const_cast<BYTE*>(key)};
DATA_BLOB dataOut = {0};
// Korrigiert: Mit DPAPI verschlüsseln
if (!CryptProtectData(&dataIn, L"MyApp Key", NULL, NULL, NULL,
CRYPTPROTECT_UI_FORBIDDEN, &dataOut)) {
return false;
}
HKEY hKey;
LONG result = RegCreateKeyExW(
HKEY_CURRENT_USER,
L"SOFTWARE\\MyApp\\Crypto",
0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL
);
if (result == ERROR_SUCCESS) {
// Korrigiert: DPAPI-verschlüsselte Daten speichern
result = RegSetValueExW(
hKey,
L"ProtectedKey",
0,
REG_BINARY,
dataOut.pbData,
dataOut.cbData
);
RegCloseKey(hKey);
}
LocalFree(dataOut.pbData);
return result == ERROR_SUCCESS;
}
bool GetEncryptedKey(std::vector<BYTE>& key) {
HKEY hKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\MyApp\\Crypto",
0, KEY_READ, &hKey) != ERROR_SUCCESS) {
return false;
}
DWORD dataSize = 0;
RegQueryValueExW(hKey, L"ProtectedKey", NULL, NULL, NULL, &dataSize);
std::vector<BYTE> encryptedData(dataSize);
if (RegQueryValueExW(hKey, L"ProtectedKey", NULL, NULL,
encryptedData.data(), &dataSize) != ERROR_SUCCESS) {
RegCloseKey(hKey);
return false;
}
RegCloseKey(hKey);
// Korrigiert: Mit DPAPI entschlüsseln
DATA_BLOB dataIn = {dataSize, encryptedData.data()};
DATA_BLOB dataOut = {0};
if (!CryptUnprotectData(&dataIn, NULL, NULL, NULL, NULL,
CRYPTPROTECT_UI_FORBIDDEN, &dataOut)) {
return false;
}
key.assign(dataOut.pbData, dataOut.pbData + dataOut.cbData);
// Korrigiert: Entschlüsselte Daten sicher löschen
SecureZeroMemory(dataOut.pbData, dataOut.cbData);
LocalFree(dataOut.pbData);
return true;
}
};
Die Korrektur verwendet Windows Credential Manager für Anmeldedaten und DPAPI zum Verschlüsseln anderer sensibler Registry-Daten.
Ausgenutzt in der Praxis
Registry-Passwortexposition (Windows-Anwendungen, 2005)
CVE-2005-2227 dokumentierte eine Windows-Anwendung, die Klartext-Passwörter in Registry-Schlüsseln speicherte, die lokalen Benutzern zugänglich waren.
Malware-Credential-Harvesting (Fortlaufend)
Verschiedene Malware-Familien scannen speziell die Windows-Registry nach gespeicherten Anmeldedaten und zielen auf gängige Anwendungs-Registry-Speicherorte ab.
Tools zum Testen/Ausnutzen
-
Registry Editor (regedit) — Integriertes Windows-Tool zum Durchsuchen von Registry-Inhalten.
-
RegRipper — Registry-Analysetool für Forensik und Sicherheitstests.
-
Mimikatz — Sicherheitstool, das Anmeldedaten aus verschiedenen Windows-Speicherorten extrahieren kann.
CVE-Beispiele
-
CVE-2005-2227 — Klartext-Passwörter in Registry-Schlüssel gespeichert.
-
CVE-2007-5778 — Login-Anmeldedaten in unverschlüsseltem Registry-Schlüssel.
Referenzen
-
MITRE Corporation. "CWE-314: Cleartext Storage in the Registry." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/314.html
-
Microsoft. "Data Protection API (DPAPI)." https://docs.microsoft.com/en-us/windows/win32/api/dpapi/
-
Microsoft. "Credential Locker." https://docs.microsoft.com/en-us/windows/uwp/security/credential-locker