browserforensics
Zurück zu allen Artikeln

Firefox-Passwörter entschlüsseln: NSS, key4.db und logins.json

2026-06-17 · 3 min

Chrome stützt sich auf den Schlüsselspeicher des Betriebssystems — DPAPI unter Windows, den Keychain unter macOS. Firefox geht seinen eigenen Weg: gespeicherte Passwörter werden durch NSS (Network Security Services) geschützt, dieselbe Krypto-Bibliothek, die Firefox auch für TLS verwendet. Nichts ist an Ihr Windows-Konto gebunden, was Firefox-Passwörter offline besser wiederherstellbar macht als die von Chrome — Sie brauchen nur zwei Dateien und (manchmal) das Master-Passwort.

Die zwei Dateien

DateiInhaltFormat
logins.jsondie verschlüsselten Benutzernamen & PasswörterJSON
key4.dbder Schlüssel, der sie entschlüsseltSQLite

Beide liegen im Profilstamm (siehe Speicherorte der Firefox-Dateien). Cookies sind eine eigene Geschichte — cookies.sqlite liegt im Klartext und braucht überhaupt keinen Schlüssel (anders als Chrome-Cookies).

logins.json ist ein Array von Einträgen:

{
  "logins": [
    {
      "hostname": "https://example.com",
      "encryptedUsername": "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECC4...",
      "encryptedPassword": "MEIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECF...",
      "timeCreated": 1700000000000,
      "timeLastUsed": 1701234567890
    }
  ]
}

Jeder encrypted*-Wert ist Base64 einer ASN.1-Struktur: eine Schlüssel-ID, eine Chiffre + IV und der Chiffretext. Die Chiffre für die Einträge selbst ist immer 3DES-CBC — der Schlüssel dazu stammt aber aus key4.db.

Im Inneren von key4.db

key4.db (SQLite; es löste etwa 2018 die alte Berkeley-DB-key3.db ab) hat zwei relevante Tabellen:

  • metadata — die Zeile id = 'password' trägt item1 (das globale Salt) und item2 (ein password-check-Blob).
  • nssPrivate — die Zeile, deren a102 der bekannten ID f8000000000000000000000000000001 entspricht, trägt a11, den verschlüsselten Schlüssel.

item2 und a11 sind beide auf dieselbe Weise gekapselt, durch einen Schlüssel, der aus dem globalen Salt und Ihrem Master-Passwort (standardmäßig leer) abgeleitet wird. Welche Kapselung verwendet wird, gibt der Algorithmus-OID in der ASN.1-Struktur an:

OIDSchema
1.2.840.113549.1.12.5.1.3pbeWithSha1And3KeyTripleDES-CBC (Legacy 3DES)
1.2.840.113549.1.5.13PBES2 → PBKDF2-HMAC-SHA256 + AES-256-CBC (modern)

Schlüsselableitung

Legacy 3DES PBE. Eine SHA-1/HMAC-SHA1-Kaskade über die Salts:

hp  = SHA1(globalSalt || primaryPassword)
chp = SHA1(hp || entrySalt)
k1  = HMAC-SHA1(chp, pes || entrySalt)      # pes = entrySalt padded to 20 bytes
tk  = HMAC-SHA1(chp, pes)
k2  = HMAC-SHA1(chp, tk || entrySalt)
k   = k1 || k2 ;  key = k[:24] ;  iv = k[-8:]

Modernes PBES2. Sauberer und heute der Regelfall:

k   = SHA1(globalSalt || primaryPassword)
key = PBKDF2-HMAC-SHA256(k, entrySalt, iterations, 32)
iv  = 0x04 0x0e || <14-byte stored IV>      # an NSS quirk: real IV is 16 bytes

So oder so fließt das Master-Passwort nur über das erste SHA1(globalSalt || password) ein. Kein Passwort gesetzt → das Passwort ist die leere Zeichenkette, und alles entschlüsselt sich ganz ohne Geheimnis.

Die Selbstprüfung, die es vertrauenswürdig macht

Sie müssen nie raten, ob die Ableitung funktioniert hat. Entschlüsseln Sie item2, und der Klartext muss exakt lauten:

password-check\x02\x02

(die literale Zeichenkette password-check plus ihre zwei PKCS#7-Padding-Bytes). Stimmt das überein, sind das Master-Passwort und die gesamte Ableitung korrekt — ein falsches Passwort scheitert also lautstark, statt stillschweigend Müll zu erzeugen. Das ist dieselbe "Entschlüsselung-beweist-sich-selbst"-Eigenschaft wie beim DPAPI-Masterkey-HMAC.

Nach erfolgter Prüfung entschlüsseln Sie a11, um den 24-Byte-3DES-Schlüssel wiederherzustellen, und entschlüsseln dann jeden logins.json-Eintrag damit (3DES-CBC, PKCS#7 entfernen), um den Klartext-Benutzernamen und das -Passwort zu erhalten.

Warum es in einem Browser-Tab läuft

Die gesamte Kette besteht aus SHA-1, HMAC-SHA1, PBKDF2, 3DES und AES — keine Betriebssystemaufrufe, kein Schlüsselspeicher. Das macht sie zu einem sauberen Kandidaten für ein WebAssembly-Modul: Unser Entschlüsseler ist ein kleines Rust-Crate (RustCrypto + ein winziger ASN.1-Reader), zu WASM kompiliert. Die Seite liest key4.db und logins.json, übergibt die rohen Blobs an das WASM und zeigt die entschlüsselten Anmeldedaten — ohne dass etwas hochgeladen wird. Legen Sie beide Dateien in den In-Browser-Parser, geben Sie das Master-Passwort ein (oder lassen Sie es leer) und entschlüsseln Sie.

Fallstricke

  • Master-Passwort. Hat der Benutzer eines gesetzt und Sie haben es nicht, scheitert die password-check, und es gibt keine Abkürzung — es schützt alles.
  • key3.db. Sehr alte Profile verwenden die Berkeley-DB-key3.db statt key4.db; das Schema ist ähnlich, aber der Container unterscheidet sich.
  • Vergessen Sie die Salt-Quelle nicht. Das globale Salt steht in key4.db, nicht in logins.json — Sie brauchen jedes Mal beide Dateien.

Weiterführende Lektüre