电子取证中Chrome各版本解密Cookies、LoginData账号密码、历史记录

news2024/11/17 17:53:10

文章目录

    • 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
  • History文件:记录了访问历史记录,本质为sqlite数据库

    • 80.X版本以前位于%localappdata%\Chromium\User Data\Default\History
    • 80.X版本以后位于%localappdata%\Google\Chrome\User Data\Default\History
  • Login Data文件:记录了用户保存的用户名密码,本质为sqlite数据库

    • 80.X版本以前位于%localappdata%\Chromium\User Data\Default\Login Data
    • 80.X版本以后位于%localappdata%\Google\Chrome\User Data\Default\Login Data
  • Local State文件:密钥文件,本质为json

    • 80.X版本以前位于%localappdata%\Chromium\User Data\Local State
    • 80.X版本以后位于%localappdata%\Google\Chrome\User Data\Local State

以上文件路径不一定完全正确并未测过所有版本,但基本上大差不差

在chrome中对于cookieslogin data的文件加密在windows中根据版本不同主要分为两种加密方式DPAPIAES-256-GCM

  • 1、没有以v10v11为前缀的加密值,主要是在80.X版本以前,为DPAPI加密

  • 2、以v10v11为前缀的加密值,主要是在80.X版本以后,为AES-256-GCM加密

可以使用DB Browser for SQLite或者Navicat查看数据库内容

80版本以后的v10前缀加密:

image-20231213082026448

80版本以前的无v10前缀(也可能有,但加密算法没变,v10后文会提到只是一个iv值),前缀似乎是固定的0x010000(不确定)

image-20231213090112852

2.对于80.X以前版本的解密

对于80以前版本的,采用了DPAPI加密,简单抄抄一下DPAPI:

DPAPI是Windows系统级对数据进行加解密的一种接口无需自实现加解密代码微软已经提供了经过验证的高质量加解密算法提供了用户态的接口对密钥的推导存储数据加解密实现透明并提供较高的安全保证

DPAPI提供了两个用户态接口CryptProtectData加密数据CryptUnprotectData解密数据加密后的数据由应用程序负责安全存储应用无需解析加密后的数据格式。但是加密后的数据存储需要一定的机制因为该数据可以被其他任何进程用来解密当然CryptProtectData也提供了用户输入额外数据来参与对用户数据进行加密的参数但依然无法放于暴力破解。

总体来说程序可以使用DPAPI来对自己敏感的数据进行加解密也可持久化存储程序或系统重启后可解密密文获取原文。如果应用程序对此敏感数据只是暂存于内存为了防止被黑客dump内存后进行破解也对此数据无需进行持久化存储微软还提供了加解密内存的接口CryptProtectMemoryCryptUnprotectMemory。加解密内存的接口并可指定Flag对此内存加解密的声明周期做控制详细见Memory加密及优缺点章节

对于其解密相对来说比较简单,这里主要采用mimikatz进行解密

如果有目标用户的桌面权限,先privilege::debug提权

然后直接使用命令

dpapi::chrome /in:"%localappdata%\Chromium\User Data\Default\Cookies" /unprotect

image-20231213113050511

如果脱机的时候解密(这里使用我win7虚拟机的cookies),会提示报错,需要对应guid的Masterkey

image-20231213110722158

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

(需目标用户已登陆)

image-20231213113818088

方法二 转储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获取获取用户密码

image-20231213115837820
接着找到masterkey文件位置

这种方法的文件位置在C:\Users{username}\AppData\Roaming\Microsoft\Protect\{SID}\{GUID}

image-20231213120001716

dpapi::masterkey /in:{masterkeyfile} /sid:{sid} /password:{password} /protected

image-20231213120155237

/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对应值,其实可以直接自动解密

image-20231213120628588

3.对于80.X以后版本的加密过程分析

80版本以后的cookies是没法再用masterkey来解密的,提前挖个坑,80版本后基本上失去脱机解密的可能性了,不知道以后有没有机会填坑

直接解会提示报错没有正确的aes的key,80版本后加密变成了aes256gcm

image-20231213121724756

对于cookies和logindata的加密过程详细解析参考

Chrome浏览器Cookie及密码解密的分析过程及Java实现(Windows平台下v10及以上Cookie文件encrypted_value及Login Data文件password_value的解密)-进城务工人员小梅 (meilongkui.com)

查看chrome的加密源码os_crypt_unittest.cc - Chromium Code Search

image-20231213133800964

os_crypt_win.cc文件里记录了具体加密过程,可以看到是用localstate文件内读取了key

image-20231213124112380

image-20231213124248889

结合源码可以看到这个encrypted_key是base64加密,且以DPAPI为开头的结果

在这里插入图片描述

密钥和NONCE/IV的长度也被记录在开头

image-20231213124512267

解密方法也写在同文件里了

image-20231213124745928

可以看出,encrypted_value的前缀v10后为12字节的NONCE(IV),然后再是真正的密文。Chrome使用的是AES-256-GCMAEAD对称加密,使用BoringsSSL实现:

image-20231213133938776

image-20231213134021445

GCM_TAG_LENGTH=16

image-20231213134105522

解密脚本(支持所有版本)

# -*- 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:
    @staticmethod
    def encrypt(cipher, plaintext, nonce):
        cipher.mode = modes.GCM(nonce)
        encryptor = cipher.encryptor()
        ciphertext = encryptor.update(plaintext)
        return cipher, ciphertext, nonce

    @staticmethod
    def decrypt(cipher, ciphertext, nonce):
        cipher.mode = modes.GCM(nonce)
        decryptor = cipher.decryptor()
        return decryptor.update(ciphertext)

    @staticmethod
    def get_cipher(key):
        cipher = Cipher(algorithms.AES(key), None, backend=default_backend())
        return cipher


def 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 result
    except Exception as e:
        print(f"Error in dpapi_decrypt: {e}")
        return None


def 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 result

def 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 result



if __name__ == '__main__':
    print("Decrypt Cookies:")
    cookies = query_cookie("chat.openai.com") # 可以传入参数筛选指定host_key
    for data in cookies:
        cok = data[0], data[1], chrome_decrypt(data[2])
        print(cok)
    print()
    print("Decrypt Login Data:")
    logindata = query_logindata("") # 可以传入参数筛选指定url
    for data in logindata:
        login = data[0], data[1], chrome_decrypt(data[2])
        print(login)

解析结果还不错
image-20231213141516280

由于其中对Locat Stateencrypt_keyDPAPI解密似乎是绑定操作系统本身环境的,尝试了各种方法暂未能够在更换主机的情况下解密encrypt_key

image-20231213141651483

History解析

history里面还是记录了很多东西的,包括访问历史记录、下载记录等等

但是都是以明文记录的,这里也就不做过多解释了

在内存取证中推荐一个volatility2的插件superponible/volatility-plugins: Plugins I’ve written for Volatility (github.com)

其中的chromehistory对chrome历史记录的解析还可以

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1309391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

el-select与treeselect下拉框重叠、兼容性问题

问题描述: 点击el-select的外部,el-select下拉框会自动收回,此操作触发了el-select的clickoutside事件,但当el-select与treeselect配合使用时,先点击el-select使下拉框出现,后再点击treeselect,…

浅谈 USB Bulk 深入浅出 (3) - USB Bulk 装置传输的注意事项

来源:大大通 作者:冷氣團 1 USB Bulk 是什么 USB 是即插即用使用差动信号的装置界面,是以 端点 ( Endpoint ),做为传输装置的输出入端,透过不同的端点 ( Endpoint ) 和模式,来进行与装置的沟通&#xff…

极狐在广告推广与客服系统中实现API集成,加快电商平台无代码开发进程

无代码开发:电商平台的新时代 随着科技的进步,电商平台正经历着一场变革,那就是无代码开发的兴起。在这个新时代里,企业不再需要耗费大量的时间和资源来进行繁杂的API开发。极狐GitLab作为一站式DevOps平台,提供了这样…

【C语言】动态内存规划# 这一篇就够了

目录 通过本篇文章,你可以了解到: (O)C/C中程序内存区域划分 (一)动态内存分配的作用 (二)动态内存函数的原理与使用 1.内存开辟malloc 2.初始并开辟calloc 3.调整已开辟的内存realloc 4.释放空间free …

TMTS汽车电子仿真及测试研讨会笔记请查收!

11月29日,德思特2023年度TMTS汽车电子仿真及测试研讨会圆满结束。感谢大家的观看与支持! 在直播间收到一些观众的技术问题,我们汇总了热点问题并请讲师详细解答,在此整理分享给大家,请查收! 面向汽车T-BOX…

2023年最佳推荐 | 值得收藏的 5大 SaaS 知识库

随着数字化时代的到来,SaaS(软件即服务)已经成为企业和个人日常工作中的重要工具。在众多的SaaS应用中,知识库是不可或缺的一部分,它可以帮助我们更好地管理和利用知识,提高工作效率和创新能力。接下来就跟…

小型洗衣机什么牌子好又便宜?内衣洗衣机品牌排行榜前十名

最近这两年在洗衣机中火出圈的内衣洗衣机,它不仅可以清洁我们较难清洗的衣物,自带除菌功能,可以让衣物上的细菌,还能在清洗的过程中呵护我们衣物的面料,虽然说它是内衣洗衣机,它的功能不止可以清洗内衣&…

LED恒流调节器FP7125,应用LED街道照明、调光电源、汽车大灯、T5T8日光灯

目录 一、FP7125概述 二、FP7125功能 三、应用领域 近年来,随着人们环保意识的不断增强,LED照明产品逐渐成为照明行业的主流。而作为LED照明产品中的重要配件,LED恒流调节器FP7125的出现为LED照明带来了全新的发展机遇。 一、FP7125概述 FP…

工业应用新典范,飞凌嵌入式FET-D9360-C核心板发布!

来源:飞凌嵌入式官网 当前新一轮科技革命和产业变革突飞猛进,工业领域对高性能、高可靠性、高稳定性的计算需求也在日益增长。为了更好地满足这一需求,飞凌嵌入式与芯驰科技(SemiDrive)强强联合,基于芯驰D9…

迅速理解什么是通信前置机

通信前置机设在两个通信对象之间,是实质性的物理服务器,适应不同通信协议或数据格式之间的相互转换。 前置机的作用: 隔离——隔离客户端与服务端,保障后端安全减负——处理非核心业务,分担后端服务器压力&#xff0…

yolov8实时推理目标识别、区域分割、姿态识别 Qt GUI

介绍一个GUI工具,可以实时做yolov8模型推理,包括目标检测、姿态识别、跟踪、区域分割等操作。 可以接入图像、视频或者RTSP视频流进行验证。 推理模型用的是yolov8转onnx之后的。用ultralytics自带的转换即可,不用带NMS。 框架用的是Qt 任…

javaspringboot--AOP

AOP AOP:Aspect Oriented Programming (面向切面编程、面向方面编程)&#xff0c;其实就是面向特定方法编程 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency…

vue2+Echarts数据可视化 【帕累托图】

接口得到的数据如下 要经过排序 &#xff0c;计算累计百分比得到数据 蓝色 柱状图数据&#xff1a; 取count字段值 横坐标&#xff1a;取 id值 折线图&#xff1a;根据柱状图的数据计算累计百分比 getInterface(data) {getParetoChart(data).then((res) > {if (res) {thi…

qiankun中主系统启动子系统本地静态图片加载404或者跨域问题

由于本地启动主系统和子系统&#xff0c;如果主系统内不放子系统的图片就会导致主系统访问不到子系统的图片 对于这个问题有三种解决方案&#xff0c;这里一一说明 1、第一种也是我常用的&#xff0c;就是把子系统中的静态图片全部转为base64这样通过主系统访问的时候就不是通…

EMC辐射发射RE整改方法?|深圳比创达电子EMC

一、排除外界因素 1、将被测设备关电&#xff0c;确认背景噪声是否满足标准要求(标准要求―电波暗室的背景噪声在限值线以下6dB)&#xff1b; 2、确认测试布置是否满足标准要求。 二、宽带噪声抑制方法 1、谱线问题描述&#xff1a;30&#xff5e;300MHz频段内出现宽带噪声…

C++类-派生类

类之间的关系 类之间的三种关系&#xff1a; 包含关系&#xff1a;class B{ private: A a;}使用关系&#xff1a;class B{public: void method(A &a);}继承关系&#xff1a;class B: public A{} 继承 继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护…

C语言实现简易版扫雷游戏

由于前面所讲知识点有限&#xff0c;无法实现扫雷游戏的全部功能&#xff0c;本期为各位呈现的是相对简单且易于编写的扫雷游戏。 第一步 设计游戏可玩多次的循环框架 这里在之前猜数字游戏时使用的循环框架一致&#xff0c;但是上次讲解不够深入&#xff0c;这里补充一下。这…

Java8新特性:强大的Stream API

5.1 说明 Java8中有两大最为重要的改变。第一个是 Lambda 表达式&#xff1b;另外一个则是 Stream API。Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充&#xff0c;因为Stream API可以极大提供Java程序员的生产力&am…

为养宠家庭量身打造,352 X63 Pet宠物专效空气净化器“养宠安馨,人宠共护”

当下,养宠人群日益增多,宠物在给家庭带来了欢乐的同时,也产生了一系列困扰,如何在健康环境中快乐养宠,成为很多家养宠家庭的新需求。成立于2014年的北京三五二环保科技有限公司是一家立足于家庭洁净空气和安全用水领域的科技创新型公司。以“安全、健康、舒适”等消费需求为核心…

AUTOSAR_RS_LogAndTrace中文翻译(待更)

4功能概述 5.功能要求 5.2.1.1通用型 1.日志记录应支持初始化和注册 2. 日志功能应该使应用程序提供日志信息 3. 日志功能应能和追踪应用程序之间通信&#xff0c; 4. 日志应支持对日志信息进行分组&#xff0c;使用案例&#xff1a;关联过滤所有属于一起的日志信息 5. 日志记…