// read logins.json file and deserialize the JSON into FirefoxLoginsJSON class public FirefoxLoginsJSON.Rootobject GetJSONLogins(string profileDir) { if (File.Exists(profileDir + @"\logins.json")) { //Read logins.json from file and deserialise JSON into FirefoxLoginsJson object string file = File.ReadAllText(profileDir + @"\logins.json"); FirefoxLoginsJSON.Rootobject JSONLogins = JsonConvert.DeserializeObject <FirefoxLoginsJSON.Rootobject>(file); return(JSONLogins); } else { throw new FileNotFoundException($"Could not find file '{profileDir}\\logins.json.\nUnable to decrypt logins for this profile.'"); } }
public FirefoxDatabaseDecryptor(string profile, string password) { ProfileDir = profile; Key4dbpath = ProfileDir + @"\key4.db"; MasterPassword = password; //Check profile for key4 database before attempting decryption if (File.Exists(Key4dbpath)) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine($"[+] Found Firefox credential database at: \"{Key4dbpath}\""); Console.ResetColor(); // If Firefox version >= 75.0, asn.1 parser will throw IndexOutOfRange exception when trying to parse encrypted data as asn.1 DER encoded try { Key4DatabaseConnection(Key4dbpath); } catch (IndexOutOfRangeException e) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"[-] Could not correctly parse the contents of {Key4dbpath} - possibly incorrect Firefox version."); Console.ResetColor(); } //Store a RootObject from FirefoxLoginsJSON (hopefully) containing multiple FirefoxLoginsJSON.Login instances FirefoxLoginsJSON.Rootobject JSONLogins = GetJSONLogins(ProfileDir); //Decrypt password-check value to ensure correct decryption DecryptedPasswordCheck = Decrypt3DES(GlobalSalt, EntrySaltPasswordCheck, CipherTextPasswordCheck, MasterPassword); if (PasswordCheck(DecryptedPasswordCheck)) { //Decrypt master key (this becomes padded EDE key for username / password decryption) //Master key should have 8 bytes of PKCS#7 Padding Decrypted3DESKey = Decrypt3DES(GlobalSalt, EntrySalt3DESKey, CipherText3DESKey, MasterPassword); //Check for PKCS#7 padding and remove if it exists Decrypted3DESKey = Unpad(Decrypted3DESKey); FirefoxLoginDataList = new List <BrowserLoginData>(); Console.ForegroundColor = ConsoleColor.Yellow; foreach (FirefoxLoginsJSON.Login login in JSONLogins.Logins) { try { if (!(login.FormSubmitURL.Equals(null))) { byte[] usernameBytes = Convert.FromBase64String(login.EncryptedUsername); byte[] passwordBytes = Convert.FromBase64String(login.EncryptedPassword); ASN1 usernameASN1 = new ASN1(usernameBytes); byte[] usernameIV = usernameASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[0]; byte[] usernameEncrypted = usernameASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[1]; //Extract password ciphertext from logins.json ASN1 passwordASN1 = new ASN1(passwordBytes); byte[] passwordIV = passwordASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[0]; byte[] passwordEncrypted = passwordASN1.RootSequence.Sequences[0].Sequences[0].OctetStrings[1]; string decryptedUsername = Encoding.UTF8.GetString(Unpad(Decrypt3DESLogins(usernameEncrypted, usernameIV, Decrypted3DESKey))); string decryptedPassword = Encoding.UTF8.GetString(Unpad(Decrypt3DESLogins(passwordEncrypted, passwordIV, Decrypted3DESKey))); BrowserLoginData loginData = new BrowserLoginData(login.FormSubmitURL, decryptedUsername, decryptedPassword, "Firefox"); FirefoxLoginDataList.Add(loginData); } } catch (NullReferenceException) { } } Console.ResetColor(); } } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"[-] No credential database found for Firefox profile: {ProfileDir}"); Console.ResetColor(); } }