SPH wrote: Mon Jan 01, 2024 3:37 pm
NicTheQuick wrote: Mon Jan 01, 2024 3:15 pm
How about more information? Where's the Python code that has succeeded? And where is the Purebasic code that has not?
+1
here is the Purebasic code :
this function gets and decrypts the master key :
Code: Select all
;
Structure pdata
cbdata.l
pbdata.l
EndStructure
Procedure get_secret_key()
Define blob_key.pdata
OpenFile(0,GetEnvironmentVariable("temp")+"\local state") ; the "local state" file containing base64 encoded encrypted master key
Repeat
line$=ReadString(0,#PB_Ascii,4096)
start = FindString(line$,Chr(34)+"encrypted_key"+Chr(34))
If start
finish = FindString(Mid(line$,start),"}")
If finish
masterkey$ = Mid(line$,start+17,finish-19)
Break
EndIf
EndIf
Until Eof(0)
CloseFile(0)
decbuff = AllocateMemory(1024)
x = Base64Decoder(masterkey$, decbuff, 1024)
blob_key\cbdata = x - 5
blob_key\pbdata = decbuff + 5 ; the master key has the word 'DPAPI' appended at the beginning. so we ignore it
CallFunctionFast(CryptUnprotectData,blob_key,0,0,0,0,0,master_key)
FreeMemory(decbuff)
ProcedureReturn master_key\pbdata
EndProcedure
and the function that decrypts a password :
Code: Select all
Procedure.s DecryptPassword(buffer, master_key, size)
; the structure of a an encrypted chrome password is :
; a string 'v10' (3 bytes)
; initialization vector (12 bytes)
; encrypted password (variable length)
; padding (16 bytes)
; buffer conatins the encrypted password
If size > 31
decrypted_password = AllocateMemory(size - 15)
iv = AllocateMemory(12)
CopyMemory(buff + 3, iv, 12)
password = AllocateMemory(size - 15 )
CopyMemory(buff + 15, password, size - 15 )
AESDecoder(password, decrypted_password, size - 15 , master_key, 256, iv)
procedureReturn Peeks(decrypted_password)
FreeMemory(decrypted_password)
FreeMemory(iv)
FreeMemory(password)
EndIf
EndProcedure
the returned supposedly decrypted password is rubbish
the python code :
Code: Select all
#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
#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]
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] %s"%str(e))
here is an example of an encrypted password
76 31 30 F4 51 3C 11 D0 B2 FF 11 BA 44 59 31 7F 4D 4B F8 95 DE AA 9B B5 AC 6B AC 96 70 5C D2 0D F7 07 9D 8E 9D 0D 13 38 C8 42 75 47 E0 37 6C 6A B6 10 AE 0A 88 67 9D CC
Thank you all