Chrome 80 如何解码 cookies

12

我有一个用于打开和解密Google Chrome Cookie的脚本,代码如下:

decrypted = win32crypt.CryptUnprotectData(enctypted_cookie_value, None, None, None, 0)

在80版本更新后,似乎这不再是一个有效的解决方案。

根据这篇博客文章 https://blog.nirsoft.net/2020/02/19/tools-update-new-encryption-chrome-chromium-version-80/ ,我需要从“本地状态”文件中使用CryptUnprotectData对加密密钥进行解密,然后通过解密后的密钥来解密Cookie。

对于第一部分,我已经获得了我的加密密钥。

path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
    encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = bytearray(encrypted_key, 'utf-8')

然后我尝试解密它

decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)

但是出现了异常:

pywintypes.error: (13, 'CryptProtectData', 'The data is invalid.')

我无法弄清楚如何修复它。

对于加密的第二部分,似乎我应该使用pycryptodome,类似于这个代码片段:

cipher = AES.new(encrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt(data)

但我无法确定应该从哪里获取nonce值。

有人能解释一下如何正确进行Chrome cookies解密吗?

2个回答

26
自Chrome 80版本及以上,使用AES-256和GCM模式加密cookie。应用的密钥使用DPAPI进行加密。此处详细描述了该过程,包括Chrome v80.0及以上版本。
加密密钥以ASCII编码的DPAPI(即0x4450415049)开头,并进行Base64编码,即必须先对密钥进行Base64解码并删除前5个字节。然后可以使用win32crypt.CryptUnprotectData进行解密。解密返回一个元组,其第二个值包含解密后的密钥。
import os
import json
import base64 
import win32crypt
from Crypto.Cipher import AES

path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
    encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = base64.b64decode(encrypted_key)                                       # Base64 decoding
encrypted_key = encrypted_key[5:]                                                     # Remove DPAPI
decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]  # Decrypt key

使用AES-256GCM模式下加密Cookie。这是经过验证的加密方式,它保证机密性和真实性/完整性。在加密过程中生成一个认证标签,用于在解密时进行完整性验证。GCM模式基于CTR模式,并使用IV(随机数)。除了32字节密钥外,还需要使用nonce和认证标签进行解密。

加密数据以ASCII编码的v10(即 0x763130)开头,后跟12字节的nonce、实际密文,最后是16字节的认证标签。各个组件可以分开如下:

data = bytes.fromhex('763130...') # the encrypted cookie
nonce = data[3:3+12]
ciphertext = data[3+12:-16]
tag = data[-16:]

其中 data 包含加密数据。解密本身使用PyCryptodome进行,具体如下:

cipher = AES.new(decrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag) # the decrypted cookie

注意:通常情况下,还存在使用Chrome版本低于v80保存的已加密DPAPI的Cookie。可以通过它们以0x01000000D08C9DDF0115D1118C7A00C04FC297EB序列开头来识别DPAPI加密的Cookie,详情请参见此处此处,关于DPAPI。当然,无法像上述描述那样解密这些Cookie,但是可以使用先前用于DPAPI加密Cookie的过程进行解密。查看未加密或加密形式的Cookie的工具分别为ChromeCookiesViewDB Browser for SQLite


1
你的解决方案有效,非常感谢!在我的情况下,我删除了“data = bytes.fromhex('763130...')#the encrypted cookie”部分,因为从sqlite3游标接收到的加密cookie已经是字节类型。 - Pavel Kaigorodov
2
你可以使用json.load(file)来代替json.loads(file.read()) - evandrix
有没有 Linux 的替代品? - Cenk Ten
1
@CenkTen - 我不知道。如果需要的话,你应该在SO上发布一个关于这个问题的提问。 - Topaco
1
@CenkTen 这是一个关于 Linux 的答案:https://dev59.com/32Ag5IYBdhLWcg3w0Noz#23727331 - JellicleCat

-1

可能你已经从Windows上的一个用户账户复制了DPAPI加密的密钥值,并且正在尝试在另一个用户登录时调用CryptUnprotectData WinAPI。由于DPAPI的本质,这是行不通的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接