网页抓取解密(谷歌浏览器存储密码的方式在使用谷歌时,)

优采云 发布时间: 2022-04-01 12:17

  网页抓取解密(谷歌浏览器存储密码的方式在使用谷歌时,)

  谷歌浏览器如何存储密码

  在使用谷歌浏览器时,如果我们输入某个网站的账号密码,他会自动询问我们是否要保存密码,这样我们下次登录时可以自动填写账号密码

  

  登录账号和密码可以在设置里找到

  

  也可以直接看密码,不过需要证书

  

  这其实就是windows的DPAPI机制

  DPAPI

  数据保护应用程序编程接口(数据保护 API)

  DPAPI 是用于在 Windows 系统级别加密和解密数据的接口。它不需要自行实现加解密代码。Microsoft 提供了经过验证的高质量加密和解密算法,并提供了用户模式界面。密钥派生和存储的加解密透明,提供高安全保障

  DPAPI 提供两个用户模式接口 CryptProtectData 加密数据 CryptUnprotectData 解密数据 加密数据是应用程序安全存储加密数据的责任。应用程序不需要解析加密的数据格式。但是,加密数据存储需要某种机制,因为数据可以通过任何其他进程解密。当然,CryptProtectData也提供了参数供用户输入额外数据参与加密用户数据,但仍然不能用于暴力破解。

  微软提供了加密和解密两个接口,CryptProtectMemory 和 CryptUnprotectMemory

  事实上,在旧版本(80 之前)的谷歌浏览器中,只有 CryptProtectMemory 用于加密密码

  80版本之前的Chrome实验环境实验流程

  Chrome 的密码被加密并存储在

  %LocalAppData%\Google\Chrome\User Data\Default\Login Data

  如果你用二进制文本编辑器看,你会发现它其实是一个sqlite数据库文件

  

  您可以使用工具 SQLiteStudio 打开它

  双击登录

  

  选择数据

  

  可以看到有用户名和网址,但没有密码

  但是密码的二进制实际上是有价值的

  

  解密脚本

  python的解密最简洁,这里是一个三好学生的代码

  from os import getenv

import sqlite3

import win32crypt

import binascii

conn = sqlite3.connect(getenv("APPDATA") + "\..\Local\Google\Chrome\User Data\Default\Login Data")

cursor = conn.cursor()

cursor.execute('SELECT action_url, username_value, password_value FROM logins')

for result in cursor.fetchall():

password = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]

if password:

print 'Site: ' + result[0]

print 'Username: ' + result[1]

print 'Password: ' + password

else:

print "no password found"

  但我还是想用 C++ 写一个

  写之前需要先配置好sqlite3环境,下载并归档

  如果当前用户使用的是谷歌,则无法打开数据库,所以我们可以制作一个副本进行操作

  

  然后通过sql语句找到logins表

  

  在回调函数中解密

  

  看效果完美解密码

  

  和上面在谷歌浏览器上看到的一样,不需要验证用户密码

  

  80 版以后的 Chrome

  那么 80.x 之后 Chrome 是如何解密的呢?

  实验环境实验分析

  下面我们来看看Chrome的存储方式和之前版本有什么区别

  

  

  判断是不是新版Chrome加密其实就是看它的加密值前面是v10还是v11

  看官方文档,分析一下新的加密算法

  密钥的初始化

  +/master:components/os_crypt/;l=192;drc=f59fc2f1cf0efae49ea96f9070bead4991f53fea

  

  

  注意:尝试从本地状态中提取密钥。

  并且可以看到kDPAPIKeyPrefix其实是一个字符串“DPAPI”

  

  然后解密DPAPI,如果key不在本地状态或者DPAPI解密失败,最后重新生成一个key。

  从这里我们可以大致分析一下key初始化的动作:

  从本地状态文件中提取keybase64解密密钥,去掉密钥开头的“DPAPI”DPAPI解密,得到最终密钥

  跟进GetString函数的参数kOsCryptEncryptedKeyPrefName

  

  知道密钥存储在本地状态文件的os_crypt.encrypted_key字段中,即

  

  并且本地状态文件在本地默认目录下:

  %LocalAppData%\Google\Chrome\用户数据\本地状态

  Local State 是 JSON 格式的文件

  明文加密

  见源代码注释

  

  密钥加密后的数据前缀为“v10”

  

  key和NONCE/IV的长度分别为:32字节和12字节

  

  以下是对 NONCE/IV 的解释:

  如果我们不希望密钥加密后的明文相同,则密文相同(这样攻击者很容易知道两个密文的明文相同),解决方法是使用IV(初始向量)或随机数(仅使用一次的值)。因为对于每条加密消息,我们可以使用不同的字节串。它们是需要制作无法区分的副本的不确定理论的起源。这些消息通常不是秘密的,但我们在分发它们以进行解密时会对其进行加密。IV 和 nonce 之间的区别是有争议的,但并非不相关。不同的加密方案有不同的保护点:有的方案只要求密文不重复,通常称为nonce;有些方案要求密文是随机的,甚至是完全不可预测的。我们通常称之为IV的条件。这里其实是希望即使明文一样,加密后的密文也不一样。

  再次向下滚动,您实际上可以看到解密功能

  

  encrypted_value 以 v10 为前缀,后跟一个 12 字节的 NONCE (IV),然后是真正的密文。Chrome 使用 AEAD 对称加密和 AES-256-GCM,

  那么思路就清楚了,这里我自己画图总结一下算法

  

  自动捕获密码

  解密使用了一个非常强大的库,cryptopp

  首先获取原创密钥

<p>string GetOriginalkey()

{

string Decoded = "";

//获取Local State中的未解密的key

string key = "RFBBUEkBAAAA0Iyd3wEV0RGMegDAT8KX6wEAAADWXmStECIlTZZxWMAYf5UmAAAAAAIAAAAAABBmAAAAAQAAIAAAAP8V1h3J1qhN1Hks1TbInimvYa0TnMfPa0j。。。。。。。。。。。。。。WLC2oU3TkysoXmUAAAAAtPkLwNaInulyoGNH4GDxlwbzAW4DP7T8XWsZ/2QB0YrcLqxSNytHlV1qvVyO8D20Eu7jKqD/bMW2MzwEa40iF";

StringSource((BYTE*)key.c_str(), key.size(), true, new Base64Decoder(new StringSink(Decoded)));

key = Decoded;

key = key.substr(5);//去除首位5个字符DPAPI

Decoded.clear();//DPAPI解密

int i;

char result[1000] = "";

DATA_BLOB DataOut = { 0 };

DATA_BLOB DataVerify = { 0 };

DataOut.pbData = (BYTE*)key.c_str();

DataOut.cbData = 1000;

if (!CryptUnprotectData(&DataOut, nullptr, NULL, NULL, NULL, 0, &DataVerify)) {

printf("[!] Decryption failure: %d\n", GetLastError());

}

else {

printf("[+] Decryption successfully!\n");

for (i = 0; i

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线