Chrome 브라우저 Password 구조
•Chrome에서는 DPAPI(Data Protection API)인 CryptProtectData를 사용해 패스워드를 암호화 후 SQLite로 저장
Chrome 비밀번호를 해독하는 4가지 주요 단계
1. 암호화 키 찾기
- 암호화 키는 “%USERPROFILE%\AppData\Google\Chrome\User Data\Local State” 파일에 저장됨
2. 암호화된 비밀번호 찾기
- 해당 파일에서 encrypted_key 단어 검색, 검색값으로 패스워드를 해독
3. 암호 알고리즘(AES) 이해
-암호문에서 AES 암호화 방식은 Encrypt Key를 이용하여 수학적 연산이 이루어지며 초기화 벡터 값을 추가
※ AES 암호화란?
•Advanced Encryption Standard(고급 암호화 표준) 이라고 불리는 블록 암호 알고리즘
•DES(데이터 암호화 표준)를 대체한 암호 알고리즘으로 대칭키 알고리즘이다.
•블록 크기는 128비트이고, 키 길이에 따라 128, 192, 256비트로 분류
•키 크기에 따라 10/12/14회 Round 수행
•라운드키의 수 = N+1 개
4. 저장된 암호 해독
•C:\Users\계정명\AppData\Local\Google\Chrome\User Data
#1단계: 암호문에서 초기화 벡터 추출하기 initialisation_vector = ciphertext[3:15]
#2단계: 암호문에서 암호화된 비밀번호 추출
encrypted_password = ciphertext[15:-16]
#3단계:암호를 해독하는 AES 알고리즘 빌드 cipher = AES.new(secret_key, AES.MODE_GCM, initialisation_vector) decrypted_pass = cipher.decrypt(encrypted_password) decrypted_pass = decrypted_pass.decode()
#4단계: 암호 해독 암호 인쇄(decrypted_pass)
크롬 브라우저에 저장된 패스워드 복호화 방법
관련 라이브러리를 먼저 설치합니다.
pip install sqlite
pip install pycryptodomex
pip install csv
pip install pywin32
전체 코드 입니다.
#!/usr/bin/env python
# -*- coding: utf8 -*-
#Full Credits to LimerBoy
import os
import re
import sys
import json
import base64
import sqlite3
import win32crypt
from Cryptodome.Cipher import AES
import shutil
import csv
"""
pip install sqlite
pip install pycryptodomex
pip install csv
pip install pywin32
"""
#GLOBAL CONSTANT
CHROME_PATH_LOCAL_STATE = os.path.normpath(r"%s\AppData\Local\Google\Chrome\User Data\Local State"%(os.environ['USERPROFILE']))
CHROME_PATH = os.path.normpath(r"%s\AppData\Local\Google\Chrome\User Data"%(os.environ['USERPROFILE']))
def get_secret_key():
try:
#(1) Get secretkey from chrome local state
with open( CHROME_PATH_LOCAL_STATE, "r", encoding='utf-8') as f:
local_state = f.read()
local_state = json.loads(local_state)
secret_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
#Remove suffix DPAPI
secret_key = secret_key[5:]
secret_key = win32crypt.CryptUnprotectData(secret_key, None, None, None, 0)[1]
return secret_key
except Exception as e:
print("%s"%str(e))
print("[ERR] Chrome secretkey cannot be found")
return None
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:
#(3-a) Initialisation vector for AES decryption
initialisation_vector = ciphertext[3:15]
#(3-b) Get encrypted password by removing suffix bytes (last 16 bits)
#Encrypted password is 192 bits
encrypted_password = ciphertext[15:-16]
#(4) Build the cipher to decrypt the ciphertext
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:
print(chrome_path_login_db)
shutil.copy2(chrome_path_login_db, "Loginvault.db")
return sqlite3.connect("Loginvault.db")
except Exception as e:
print("%s"%str(e))
print("[ERR] Chrome database cannot be found")
return None
if __name__ == '__main__':
try:
#Create Dataframe to store passwords
with open('decrypted_password.csv', mode='w', newline='', encoding='utf-8') as decrypt_password_file:
csv_writer = csv.writer(decrypt_password_file, delimiter=',')
csv_writer.writerow(["index","url","username","password"])
#(1) Get secret key
secret_key = get_secret_key()
#Search user profile or default folder (this is where the encrypted login password is stored)
folders = [element for element in os.listdir(CHROME_PATH) if re.search("^Profile*|^Default$",element)!=None]
for folder in folders:
#(2) Get ciphertext from sqlite database
chrome_path_login_db = os.path.normpath(r"%s\%s\Login Data"%(CHROME_PATH,folder))
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]
print("URL:{0}".format(url))
print("user name:{0}".format(username))
print("ciphertext:{0}".format(ciphertext))
if(url!="" and username!="" and ciphertext!=""):
#(3) Filter the initialisation vector & encrypted password from ciphertext
#(4) Use AES algorithm to decrypt the password
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)
#(5) Save into CSV
csv_writer.writerow([index,url,username,decrypted_password])
#Close database connection
cursor.close()
conn.close()
#Delete temp login db
os.remove("Loginvault.db")
except Exception as e:
print("[ERR] "%str(e))
'공학속으로 > python' 카테고리의 다른 글
[python] 판다스 데이터프레임 저장하기 (0) | 2022.12.07 |
---|---|
[python] IP 후이즈(whois) 조회하기 (0) | 2022.11.11 |
[python] 파이썬 파일 속성 변경 없이 파일 복사 (0) | 2022.06.07 |
[python] 파이썬 Visual Studio Code에서 개발 환경 구축 (0) | 2022.06.07 |
[python] 트위터 크롤링 (0) | 2022.05.26 |
댓글