asaix/mozdmp
GitHub: asaix/mozdmp
mozdmp 是一款 Firefox 配置数据离线解密工具,能够从 NSS 数据库提取密钥并解密 logins.json 中的用户密码,支持主密码字典破解。
Stars: 0 | Forks: 0
# mozdmp
mozdmp 是一款用于 Mozilla Firefox 浏览器的离线配置解密工具。它通过从 NSS 数据库(`key4.db`)中提取密钥,能够对包含用户密码的 `logins.json` 文件进行解密。
**重要功能:**
- 支持最新版本的 Firefox,这些版本使用 SHA384 来派生 PBKDF2 输入。工具会自动选择正确的哈希类型。
- 支持使用字典进行多核主密码破解。*\*在 Windows 和 MacOS 上,破解将仅限于单核。*
**快速开始**
下载并解压最新的二进制发布版本。然后运行:
```
mozdmp
```
该二进制文件仅在 Linux 上运行。如果你想 Windows/Mac 上运行该程序,请克隆源代码,从 `requirements.txt` 安装所需的依赖包,并使用 Python 3 运行脚本。
**许可证与免责声明**
本代码基于 MIT 许可证发布。请注意,本工具仅限在法律允许的范围内进行授权使用,开发者对任何非法或有害的使用行为不承担任何责任。
## 演示
```
≻ ./mozdmp data/psw_1looove/key4.db data/psw_1looove/logins.json
[*] Checking Master Password...
>> Check Master Password == '' ... NO
[*] Attempting to crack master password...
[+] Multi-Core Enabled
[?] Enter wordlist path: rockyou.txt
[?] Workers (default 20):
[*] Loading wordlist...
W0: ▎ | 2407/717220 [00:11<56:18, 211.60pwd/s]
W15: ▎ | 2325/717220 [00:11<56:54, 209.39pwd/s]
W8: ▎ | 2278/717220 [00:11<58:55, 202.20pwd/s]
W10: ▎ | 2389/717220 [00:11<55:57, 212.89pwd/s]
W14: ▎ | 2222/717220 [00:11<59:41, 199.66pwd/s]
W11: ▎ | 2186/717220 [00:11<1:01:03, 195.17pwd/s]
W6: ▎ | 2425/717220 [00:11<55:29, 214.69pwd/s]
W1: ▎ | 2314/717220 [00:11<58:31, 203.61pwd/s]
W18: ▎ | 2203/717220 [00:11<59:40, 199.70pwd/s]
W19: ▎ | 2217/717203 [00:11<59:11, 201.32pwd/s]
W7: ▎ | 2295/717220 [00:11<58:35, 203.38pwd/s]
W3: ▎ | 2608/717220 [00:11<51:47, 229.99pwd/s]
W4: ▎ | 2444/717220 [00:11<55:12, 215.79pwd/s]
W16: ▎ | 2501/717220 [00:11<52:47, 225.66pwd/s]
W13: ▎ | 2440/717220 [00:11<54:28, 218.70pwd/s]
W9: ▎ | 2377/717220 [00:11<56:23, 211.30pwd/s]
W5: ▎ | 2280/717220 [00:11<59:07, 201.54pwd/s]
W2: ▎ | 2506/717220 [00:11<53:58, 220.70pwd/s]
W12: ▏ | 2159/717220 [00:11<1:01:43, 193.08pwd/s]
W17: ▎ | 2290/717220 [00:11<57:34, 206.96pwd/s]
[+] FOUND MASTER KEY: 1looove
[*] ASN.1 Structure:
{
"0": {
"0": "1.2.840.113549.1.5.13",
"1": {
"0": {
"0": "1.2.840.113549.1.5.12",
"1": {
"0": "2a24f5f8ec2fc74eccd6fa396f11aa34f1c8d3de269af38ca1324539ec5a4894",
"1": 10000,
"2": 32,
"3": {
"0": "1.2.840.113549.2.9"
}
}
},
"1": {
"0": "2.16.840.1.101.3.4.1.42",
"1": "d33681631562b28ee4494725e9bc"
}
}
},
"1": "1012c08ee92981434c59134564e2684df5188b3aac4e7ade234c0accc853d31a40c7d2a3373c5e4af7b7f6835042df57"
}
[*] KDF Parameters:
{
"salt": "2a24f5f8ec2fc74eccd6fa396f11aa34f1c8d3de269af38ca1324539ec5a4894",
"iterations": 10000,
"keylen": 32
}
[*] AES Parameters:
{
"iv": "040ed33681631562b28ee4494725e9bc"
}
[*] Global salt: 733f22304895df339a778680cbda652191f0b46fd240f1340b81e79c4997dcac11b25b897bc779cdbad0eb6cbe1696e5
[*] Ciphertext: 1012c08ee92981434c59134564e2684df5188b3aac4e7ade234c0accc853d31a40c7d2a3373c5e4af7b7f6835042df57
[*] KDF input (SHA384(global_salt + password)): aa5bf320258a8f9c10dc1a23dc415e3143d258c36c3218018672f0df1a6b9edb3174198700bf463201e8017d7f42767e
[*] KDF Output (Wrapped AES Key): 3dd4e31d292fd8ee4bbaf995074a28e98365c8466cab24f84e75c2e843b97234
[+] Decrypted AES key: 462f7891ab8e708c1a93122a3b2857a5b016472b9d58cb40b52449db64e4a68a
[*] Decrypting passwords from logins...
╭────────────────────────────┬────────────────────────────┬────────────┬────────────┬────────────────────┬────────────────────┬────────────────────┬──────────╮
│ Hostname │ Form Submit URL │ Username │ Password │ Created At │ Last Used │ Last Changed │ # uses │
├────────────────────────────┼────────────────────────────┼────────────┼────────────┼────────────────────┼────────────────────┼────────────────────┼──────────┤
│ https://auth.wikimedia.org │ https://auth.wikimedia.org │ joog │ boog │ 08 June 2026 11:40 │ 08 June 2026 11:40 │ 08 June 2026 11:40 │ 1 │
╰────────────────────────────┴────────────────────────────┴────────────┴────────────┴────────────────────┴────────────────────┴────────────────────┴──────────╯
```
## 解密过程详解
本部分解释了 Firefox 中的配置文件解密是如何运作的。这并非使用本程序的必需前提,但如果你打算贡献代码,了解这些是非常有价值的。
与基于 Chromium 的浏览器(它们使用诸如 keyring 和 DPAPI 密钥等操作系统级别的身份验证工具来保护敏感文件)不同,Firefox 没有采取此类额外措施,这可能是考虑到此类保护机制终究会被绕过。
也就是说,`logins.json` 中的所有登录数据都可以使用 `key4.db` 文件中提供的 NSS 密钥进行解密,而无需依赖任何*不包含在这些文件中*的信息(例如 NTLM 哈希等)来解密这些密钥。
现在,用于解密密码的 AES 密钥并不是以明文形式存在的。它必须通过派生出另一个密钥(以下称为 **wrapper key**)来解密。
本指南将带你详细了解在哪里找到所需的参数,如何使用它们派生 wrapper key,并最终使用解密后的 AES 登录密钥来解密实际数据。
### 1. 提取 Global Salt 与 Password Check ASN.1 Blob
Global Salt 存储在 `metadata` 表中,可以通过查询 `id="password"` 时的 `item1` 列来提取。
| id (UNIQUE) | item1 | item2 |
| ----------- | ------------- | --------------------------- |
| password | *global salt* | *Password Check ASN.1 Blob* |
| ... | ... | ... |
为了快速测试输入的密码是否正确,Firefox 存储了一个 ASN.1 blob,其中包含使用主密钥加密的短语 `password-check`,以及用于生成加密该 `password-check` 短语的 AES 密钥的 PBKDF2 函数参数。
我们可以按如下方式索引该 blob,以获取 PBKDF2 的参数:
- Salt: 0.1.0.1.0
- Iterations: 0.1.0.1.1
- Key length: 0.1.0.1.2
这些可用于生成 wrapper key。要解密密文,我们还需要两个字段:
- Ciphertext: 1.
- Initialization Vector (IV): 0.1.1.1
请注意,根据你使用的 ASN 解析库(如在 python.asn1crypto 中所见),解析器可能会在返回 IV 时去掉其 TLV 标头。这可以通过检查返回的 IV 长度来识别。如果长度小于 16,则说明 TLV 标头被去掉了。在这种情况下,可以在 IV 值前面加上字节序列 `0x04` 以及 IV 字节序列的长度。即 `IV = BYTES([0x04, len(IV)]) + IV`。
### 2. 校验主密码
利用在第 1 步中获得的信息,我们现在可以通过使用上面获取的参数解密密文来测试主密码。默认情况下,Firefox 使用空字符串作为主密码,并且不会提示用户设置密码。
Firefox 使用 SHA1 或 SHA384 来派生 PBKDF2 函数的输入,如下所示:
```
KDF_INPUT = SHA*(global_salt + password)
KDF_OUTPUT = PBKDF2("sha256", KDF_INPUT, salt, iterations, keylength)
```
**如果 global salt 的长度为 48,请使用 SHA384。如果不是,则使用 SHA1。**
现在,利用我们生成的密钥 `KDF_OUTPUT`,就可以解密密文了
```
PLAINTEXT = AES-256-CBC-DECRYPT(ciphertext, KDF_OUTPUT, iv)
```
如果获得的明文等于 `password-check`,则说明密码正确。如果不正确(通常 `AES-256-CBC-DECRYPT` 会因为无法剥离 PKCS#7 填充而报错),则说明用户设置了主密码,必须通过使用不同的 `password` 值运行此函数来对其进行破解。
### 3. 获取真实密钥
有了主密码,我们现在可以继续派生 wrapper key,并最终获得真实密钥。
`nssPrivate` 数据库存储了大量信息,其中包含许多指向 NSS 协议不同部分的键。然而在我们的场景中,加密过程相当直接,我们只需要两列:`a0` 和 `a11`。
该表有多行。`a0` 列表示其存储的数据类型,这与 NSS 的机制是一致的。
带有 CKO_SECRET_KEY 的行是其 `a0` = `f8000000000000000000000000000004`(字节序列)的行。我们想要的行是唯一以 0x04 结尾的行,因此只需通过检查该值的最后一个字节即可将其筛选出来。
```
res = db.run("SELECT a0, a11 from nssPrivate")
for row in res:
if row[0][-1] == 0x04:
...
```
a11 列中对应的值是一个 ASN.1 blob。
与第 1 步类似,我们可以提取有关加密和密钥生成算法的详细信息:
PBKDF2:
- Salt: 0.1.0.1.0
- Iterations: 0.1.0.1.1
- Key length: 0.1.0.1.2
AES:
- IV: 0.1.1.1
- Ciphertext: 1.
由此,可以使用与第 2 步相同的步骤以及这些更新后的参数值来获取真实密钥。
### 4. 解密 logins.json
`logins.json` 文件中,每次登录只包含两个加密字段:"encryptedUsername" 和 "encryptedPassword"。
这两个都是经过 base64 编码的 ASN.1 blob。解密步骤如下所示。
1. 对这些值进行 Base64 解码。
2. 在 ASN blob 的 1.1 处获取 IV。
3. 在 2 处获取密文。
4. 使用在第 3 步中获取的真实密钥和 IV,通过 AES-256-CBC-DECRYPT 解密密文。
标签:DOS头擦除, Python, 凭证提取, 密码破解, 数据解密, 无后门, 逆向工具