Firefox密碼讀取

Firefox

和Chrome瀏覽器不同,Mozilla擁有自己的加密庫,被稱爲網絡安全服務(NSS),特別之處是NSS使用了ASN.1進行數據序列化。

ASN1

  • ASN.1 – Abstract Syntax Notation dot one,數字1被ISO加在ASN的後邊,是爲了保持ASN的開放性,可以讓以後功能更加強大的ASN被命名爲ASN.2等,但至今也沒有出現。
  • ASN.1是一種對數據進行表示、編碼、傳輸和解碼的數據格式。它提供了一整套正規的格式用於描述對象的結構,而不管語言上如何執行及這些數據的具體指代,也不用去管到底是什麼樣的應用程序。

Chrome和Firefox之間的有一個很大的區別,那就是Firefox允許用戶提供一個主密碼來加密所有存儲的登錄名和密碼。如果用戶設置了主密碼,需要解密者提供主密碼才能解密登錄信息。

項目大量參考了https://github.com/lclevy/firepwd,以及下面這張Firefox的密碼加解密流程圖(原圖地址爲https://github.com/lclevy/firepwd/blob/master/mozilla_pbe.pdf),雖然是Firefox <32 版本的加密邏輯,但是可以幫助我們理清Firefox的加解密原理:

登錄信息存放位置

用戶的Firefox各種配置文件存儲在自己的Appdata\Roaming目錄下:

C:\Users\admin\AppData\Roaming\Firefox\Profiles\<random text>.default\

不同版本的Firefox瀏覽器,存放登錄信息文件和存放密鑰文件也不同,其中用到的加密方式也有少許不同:

Firefox 版本 <32 (key3.db, signons.sqlite)
Firefox 版本 >=32 (key3.db, logins.json)
Firefox 版本 >=58.0.2 (key4.db, logins.json)
Firefox 版本 >=75.0 (sha1 pbkdf2 sha256 aes256 cbc used by key4.db, logins.json)

如果Firefox 版本 >=58.0.2 那麼接下來需要找的兩個文件路徑分別是:

C:\Users\admin\AppData\Roaming\Firefox\Profiles\<random text>.default\key4.db
C:\Users\admin\AppData\Roaming\Firefox\Profiles\<random text>.default\logins.json

登錄信息存儲過程

以Firefox 版本 >=58.0.2爲例,logins.json將用戶所有登錄信息(包括URL,用戶名,密碼和其他元數據)存儲爲JSON。值得注意的是,這些文件中的用戶名和密碼均經過3DES加密,然後經過ASN.1編碼,最後寫入base64編碼的文件中,用一個測試登錄信息如下所示,其中encryptedUsername和encryptedPassword就是被加密的用戶名和密碼:

{
    "nextId": 2, 
    "logins": [
        {
            "id": 1, 
            "hostname": "http://192.168.18.1", 
            "httpRealm": null, 
            "formSubmitURL": "http://192.168.18.1", 
            "usernameField": "", 
            "passwordField": "Password", 
            "encryptedUsername": "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECNTQR/CqIN2qBAjp5XcZcmuibQ==", 
            "encryptedPassword": "MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECDUjhaRWzib+BBAUX/D1mTMqeccCSRJCkEbA", 
            "guid": "{b82c4d25-5fc6-47bc-8c31-b1bbeaff0807}", 
            "encType": 1, 
            "timeCreated": 1618124482800, 
            "timeLastUsed": 1618124482800, 
            "timePasswordChanged": 1618124482800, 
            "timesUsed": 1
        }
    ], 
    "potentiallyVulnerablePasswords": [ ], 
    "dismissedBreachAlertsByLoginGUID": { }, 
    "version": 3
}

key4.db是一個sqlite數據庫,裏面存儲用於3DES解密logins.json的密鑰,以及被加密的用於驗證主密鑰解密的password-check值,裏面有兩個表metaData和nssPrivate,

metaData中id爲password的item1列爲包含加密期間使用的全局鹽值(globalSalt);item2列爲ASN.1編碼後的加密password-check數據,裏面包含被加密的password-check字符串和用於加密的入口鹽值(entrySalt)

nssPrivate中 a11 列存放的是用於加解密的主密鑰。

登錄信息解密

Firefox 版本 >= 58.0.2 < 75

  1. 根據上述的描述,解密Firefox存儲在本地的登錄信息需要以下步驟:
  2. 找到當前計算機Firefox的profile目錄,檢查key4.dblogins.json文件是否存在。
  3. 如果存在,從key4.db中提取已編碼+加密的password-check數據,先ASN1解碼然後使用3DES解密被加密的password-check字符串(這樣做是爲了確認提取的密碼是否正確)。
  4. key4.db中提取編碼的+加密的主密鑰 ,ASN.1解碼,然後3DES解密主密鑰。
  5. logins.json中讀取加密的登錄名和密碼,ASN.1解碼,然後3DES使用主密鑰解密登錄數據

Firefox 版本 >= 75

和Firefox 版本 >= 58.0.2 < 75不同的是,在加密password-check數據和主密鑰使用了hmacWithSHA256的哈希算法和AES256 cbc的加密算法,所以解密步驟如下所示:

  1. 根據上述的描述,解密Firefox存儲在本地的登錄信息需要以下步驟:
  2. 找到當前計算機Firefox的profile目錄,檢查key4.dblogins.json文件是否存在。
  3. 如果存在,從key4.db中提取已編碼+加密的password-check數據,先ASN1解碼然後使用AES解密被加密的password-check字符串(這樣做是爲了確認提取的密碼是否正確)。
  4. key4.db中提取編碼的+加密的主密鑰 ,ASN.1解碼,然後3DES解密主密鑰。
  5. logins.json中讀取加密的登錄名和密碼,ASN.1解碼,然後3DES使用主密鑰解密登錄數據

以Firefox 版本 >= 75爲例,下面以項目部分代碼爲例講下實現細節:

爲了快速實現ASN1解碼,AES和3DES的解密,使用了大佬們github的開源項目代碼,鏈接放在最後的參考文章上,如果想深入瞭解ASN1的原理可以參考ASN.1 DER(可分辨編碼規則)等文章,Firefox的ASN.1使用TLV(類型,長度,值)數據格式,數據僅使用少量的DER數據類型,這使得解碼變得更加容易,TLV格式如下所示:

public enum Type
{
	Sequence = 0x30,
	Integer = 0x02,
	BitString = 0x03,
	OctetString = 0x04,
	Null = 0x05,
	ObjectIdentifier = 0x06
}

爲了判斷ASN1中ObjectIdentifier代表的加密方式,使用firepwd項目中提供的oid對應字典,具體編號對應參考http://oid-info.com/get/1.2.840.113549.2.9:

public static Dictionary<string, string> oidValues = new Dictionary<string, string>
{
	{ "2A864886F70D010C050103","1.2.840.113549.1.12.5.1.3 pbeWithSha1AndTripleDES-CBC" },
	{ "2A864886F70D0307","1.2.840.113549.3.7 des-ede3-cbc" },
	{ "2A864886F70D010101","1.2.840.113549.1.1.1 pkcs-1" },
	{ "2A864886F70D01050D","1.2.840.113549.1.5.13 pkcs5 pbes2" },
	{ "2A864886F70D01050C","1.2.840.113549.1.5.12 pkcs5 PBKDF2" },
	{ "2A864886F70D0209","1.2.840.113549.2.9 hmacWithSHA256" },
	{ "60864801650304012A","2.16.840.1.101.3.4.1.42 aes256-CBC" }
};

解析出來的結果樣例爲:

SEQUENCE {
SEQUENCE {
SEQUENCE {
        OBJECTIDENTIFIER 1.2.840.113549.1.5.13 pkcs5 pbes2
SEQUENCE {
SEQUENCE {
        OBJECTIDENTIFIER 1.2.840.113549.1.5.12 pkcs5 PBKDF2
SEQUENCE {
        OCTETSTRING 947EB49963185BD83E2BD77C074A4A982832515E775AC7B23577F15401E905BD
        INTEGER 01
        INTEGER 20
SEQUENCE {
        OBJECTIDENTIFIER 1.2.840.113549.2.9 hmacWithSHA256
        OBJECTIDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC
        OCTETSTRING 6C567DBF5EEC60AF7D2FB363035F
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
}
SEQUENCE {
}
        OBJECTIDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC
        OCTETSTRING 6C567DBF5EEC60AF7D2FB363035F
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
}
SEQUENCE {
}
        OBJECTIDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC
        OCTETSTRING 6C567DBF5EEC60AF7D2FB363035F
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
}
SEQUENCE {
}
        OBJECTIDENTIFIER 2.16.840.1.101.3.4.1.42 aes256-CBC
        OCTETSTRING 6C567DBF5EEC60AF7D2FB363035F
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
}
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
}
        OCTETSTRING 140D0C287323E3C1B404157C92973A17
}
}

ASN.1解析器類將ASN.1編碼的BLOB遞歸地解析爲一個對象。每個對象都包含一個對象列表,這些Sequence對象代表處理編碼的登錄數據和主密鑰的情況,通過oid得知加密方法後,從解析器裏提取entrySalt,iterationCount,keyLength。之後先獲取globalSalt的sha1加密值,和entrySalt一起做hmacWithSHA256加密來獲取密鑰,最後提取cipherT做AES解密,通過decryptPEB函數可以獲取解密後的password-check字符串和主密鑰,代碼如下所示:

else if(pbeAlgo.Contains("1.2.840.113549.1.5.13"))
{
    byte[] entrySalt = asn.objects[0].objects[0].objects[1].objects[0].objects[1].objects[0].Data;
    int iterationCount = asn.objects[0].objects[0].objects[1].objects[0].objects[1].objects[1].Data[0];
    int keyLength = asn.objects[0].objects[0].objects[1].objects[0].objects[1].objects[2].Data[0];

    byte[] k = SHA1.Create().ComputeHash(globalSalt);
    var hmac = new HMACSHA256();
    var df = new Pbkdf2(hmac, k, entrySalt, iterationCount);
    byte[] key = df.GetBytes(32);
    Console.WriteLine(BitConverter.ToString(key));
    byte[] source = { 0x4, 0xe };
    byte[] iv = byteCpy(source, asn.objects[0].objects[0].objects[1].objects[2].objects[1].Data);
    Console.WriteLine(BitConverter.ToString(iv));
    byte[] cipherT = asn.objects[0].objects[1].Data;
    Console.WriteLine(BitConverter.ToString(cipherT));
    byte[] clearText = AESDecrypt(cipherT, key, iv);
    return clearText;
}

現在剩下的就是使用密鑰和IV執行3DES解密登錄信息了,讀取logins.json文件

  1. 遍歷中的每個Login對象JSONLogins
  2. ASN.1解碼每個用戶名和密碼
  3. 3DES使用主密鑰解密每個用戶名和密碼
  4. 輸出hostname,username,password
FFLogins ffLoginData;
using (StreamReader sr = new StreamReader(userFireFoxloginPath))
{
    string json = sr.ReadToEnd();
    ffLoginData = JsonConvert.DeserializeObject<FFLogins>(json);
}

foreach (LoginData loginData in ffLoginData.logins)
{
    try
    {
        Asn1DerObject user = asn.Parse(Convert.FromBase64String(loginData.encryptedUsername));
        Asn1DerObject pwd = asn.Parse(Convert.FromBase64String(loginData.encryptedPassword));
        string hostname = loginData.hostname;
        string decryptedUser = TripleDESHelper.DESCBCDecryptor(privateKey, user.objects[0].objects[1].objects[1].Data, user.objects[0].objects[2].Data);
        string decryptedPwd = TripleDESHelper.DESCBCDecryptor(privateKey, pwd.objects[0].objects[1].objects[1].Data, pwd.objects[0].objects[2].Data);
        string username = Regex.Replace(decryptedUser, @"[^\u0020-\u007F]", "");
        string password = Regex.Replace(decryptedPwd, @"[^\u0020-\u007F]", "");

        Console.WriteLine(hostname);
        Console.WriteLine(username);
        Console.WriteLine(password);
        Console.WriteLine("");
    }
    catch(Exception e)
    {
        Console.WriteLine(e);
    }
}

最終結果如下圖所示:

工具加入知識星球獲取,現在只是個基礎,後期會逐步更新所有瀏覽器的解密工具,還不加入星球一起快樂擊劍?

號外

寬字節安全團隊第一期線下網絡安全就業班開班了,由寬字節安全團隊獨立運營,一線紅隊大佬帶隊,有豐富的漏洞研究、滲透測試、應急響應的經驗與沉澱,乾貨多多,歡迎添加客服諮詢

點擊查看詳情

客服微信:unicodesec

參考文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章