class apypykatz: def __init__(self, reader, sysinfo): self.reader = reader self.sysinfo = sysinfo self.credentials = [] self.architecture = None self.operating_system = None self.buildnumber = None self.lsa_decryptor = None self.logon_sessions = {} self.orphaned_creds = [] self.errors = [] self.kerberos_ccache = CCACHE() def to_dict(self): t = {} t['logon_sessions'] = {} for ls in self.logon_sessions: # print(ls) t['logon_sessions'][ls] = (self.logon_sessions[ls].to_dict()) t['orphaned_creds'] = [] for oc in self.orphaned_creds: t['orphaned_creds'].append(oc.to_dict()) t['errors'] = [] for pkg, err in self.errors: err_str = str(err) + '\r\n' + '\r\n'.join( traceback.format_tb(err.__traceback__)) err_str = base64.b64encode(err_str.encode()).decode() t['errors'].append((pkg, err_str)) return t def to_json(self): return json.dumps(self.to_dict(), cls=UniversalEncoder, indent=4, sort_keys=True) def to_grep(self): res = ':'.join(LogonSession.grep_header) + '\r\n' for luid in self.logon_sessions: for row in self.logon_sessions[luid].to_grep_rows(): res += ':'.join(row) + '\r\n' for cred in self.orphaned_creds: t = cred.to_dict() if t['credtype'] != 'dpapi': if t['password'] is not None: x = [ str(t['credtype']), str(t['domainname']), str(t['username']), '', '', '', '', '', str(t['password']) ] res += ':'.join(x) + '\r\n' else: t = cred.to_dict() x = [ str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), '' ] res += ':'.join(x) + '\r\n' for pkg, err in self.errors: err_str = str(err) + '\r\n' + '\r\n'.join( traceback.format_tb(err.__traceback__)) err_str = base64.b64encode(err_str.encode()).decode() x = [ pkg + '_exception_please_report', '', '', '', '', '', '', '', err_str ] res += ':'.join(x) + '\r\n' return res def __str__(self): res = '== Logon credentials ==\r\n' for luid in self.logon_sessions: res += str(self.logon_sessions[luid]) + '\r\n' if len(self.orphaned_creds) > 0: res += '== Orphaned credentials ==\r\n' for cred in self.orphaned_creds: res += str(cred) + '\r\n' if len(self.errors) > 0: res += '== Errors ==\r\n' for pkg, err in self.errors: err_str = str(err) + '\r\n' + '\r\n'.join( traceback.format_tb(err.__traceback__)) err_str = base64.b64encode(err_str.encode()).decode() res += '%s %s \r\n' % (pkg + '_exception_please_report', err_str) return res @staticmethod async def parse_minidump_file(filename, packages=['all'], chunksize=10 * 1024): try: minidump = await AMinidumpFile.parse(filename) reader = minidump.get_reader().get_buffered_reader(chunksize) sysinfo = KatzSystemInfo.from_minidump(minidump) except Exception as e: logger.exception('Minidump parsing error!') raise e try: mimi = apypykatz(reader, sysinfo) await mimi.start(packages) except Exception as e: #logger.info('Credentials parsing error!') mimi.log_basic_info() raise e return mimi @staticmethod async def parse_minidump_external(handle, packages=['all'], chunksize=10 * 1024): """ Parses LSASS minidump file based on the file object. File object can really be any object as longs as it implements read, seek, tell functions with the same parameters as a file object would. handle: file like object """ minidump = await AMinidumpFile.parse_external(handle) reader = minidump.get_reader().get_buffered_reader(chunksize) sysinfo = KatzSystemInfo.from_minidump(minidump) mimi = apypykatz(reader, sysinfo) await mimi.start(packages) return mimi def log_basic_info(self): """ In case of error, please attach this to the issues page """ logger.info('===== BASIC INFO. SUBMIT THIS IF THERE IS AN ISSUE =====') logger.info('pypyKatz version: %s' % __version__) logger.info('CPU arch: %s' % self.sysinfo.architecture.name) logger.info('OS: %s' % self.sysinfo.operating_system) logger.info('BuildNumber: %s' % self.sysinfo.buildnumber) logger.info('MajorVersion: %s ' % self.sysinfo.major_version) logger.info('MSV timestamp: %s' % self.sysinfo.msv_dll_timestamp) logger.info('===== BASIC INFO END =====') async def get_logoncreds(self): credman_template = CredmanTemplate.get_template(self.sysinfo) msv_template = MsvTemplate.get_template(self.sysinfo) logoncred_decryptor = MsvDecryptor(self.reader, msv_template, self.lsa_decryptor, credman_template, self.sysinfo) await logoncred_decryptor.start() self.logon_sessions = logoncred_decryptor.logon_sessions async def get_lsa_bruteforce(self): #good luck! logger.debug('Testing all available templates! Expect warnings!') for lsa_dec_template in LsaTemplate.get_template_brute(self.sysinfo): try: lsa_dec = LsaDecryptor.choose(self.reader, lsa_dec_template, self.sysinfo) await lsa_dec.acquire_crypto_material() lsa_dec.dump() except: pass else: logger.debug( 'Lucky you! Brutefoce method found a -probably- working template!' ) return lsa_dec async def get_lsa(self): #trying with automatic template detection try: lsa_dec_template = LsaTemplate.get_template(self.sysinfo) lsa_dec = LsaDecryptor.choose(self.reader, lsa_dec_template, self.sysinfo) await lsa_dec.acquire_crypto_material() lsa_dec.dump() except Exception as e: logger.debug( 'Failed to automatically detect correct LSA template! Reason: %s' % str(e)) lsa_dec = await self.get_lsa_bruteforce() if lsa_dec is None: raise Exception('All detection methods failed.') return lsa_dec else: return lsa_dec async def get_wdigest(self): decryptor_template = WdigestTemplate.get_template(self.sysinfo) decryptor = WdigestDecryptor(self.reader, decryptor_template, self.lsa_decryptor, self.sysinfo) await decryptor.start() for cred in decryptor.credentials: if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].wdigest_creds.append(cred) else: self.orphaned_creds.append(cred) async def get_tspkg(self): tspkg_dec_template = TspkgTemplate.get_template(self.sysinfo) tspkg_dec = TspkgDecryptor(self.reader, tspkg_dec_template, self.lsa_decryptor, self.sysinfo) await tspkg_dec.start() for cred in tspkg_dec.credentials: if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].tspkg_creds.append(cred) else: self.orphaned_creds.append(cred) async def get_ssp(self): dec_template = SspTemplate.get_template(self.sysinfo) dec = SspDecryptor(self.reader, dec_template, self.lsa_decryptor, self.sysinfo) await dec.start() for cred in dec.credentials: if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].ssp_creds.append(cred) else: self.orphaned_creds.append(cred) async def get_livessp(self): livessp_dec_template = LiveSspTemplate.get_template(self.sysinfo) livessp_dec = LiveSspDecryptor(self.reader, livessp_dec_template, self.lsa_decryptor, self.sysinfo) await livessp_dec.start() for cred in livessp_dec.credentials: if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].livessp_creds.append(cred) else: self.orphaned_creds.append(cred) async def get_dpapi(self): dec_template = DpapiTemplate.get_template(self.sysinfo) dec = DpapiDecryptor(self.reader, dec_template, self.lsa_decryptor, self.sysinfo) await dec.start() for cred in dec.credentials: if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].dpapi_creds.append(cred) else: self.orphaned_creds.append(cred) async def get_kerberos(self, with_tickets=True): dec_template = KerberosTemplate.get_template(self.sysinfo) dec = KerberosDecryptor(self.reader, dec_template, self.lsa_decryptor, self.sysinfo) await dec.start() for cred in dec.credentials: for ticket in cred.tickets: for fn in ticket.kirbi_data: self.kerberos_ccache.add_kirbi( ticket.kirbi_data[fn].native) if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].kerberos_creds.append(cred) else: self.orphaned_creds.append(cred) async def get_cloudap(self): cloudap_dec_template = CloudapTemplate.get_template(self.sysinfo) if cloudap_dec_template is None: return cloudap_dec = CloudapDecryptor(self.reader, cloudap_dec_template, self.lsa_decryptor, self.sysinfo) await cloudap_dec.start() for cred in cloudap_dec.credentials: if cred.luid in self.logon_sessions: self.logon_sessions[cred.luid].cloudap_creds.append(cred) else: self.orphaned_creds.append(cred) async def start(self, packages=['all']): #self.log_basic_info() #input() self.lsa_decryptor = await self.get_lsa() if 'msv' in packages or 'all' in packages: try: await self.get_logoncreds() except Exception as e: self.errors.append(('msv', e)) if 'wdigest' in packages or 'all' in packages: try: await self.get_wdigest() except Exception as e: self.errors.append(('wdigest', e)) if 'kerberos' in packages or 'ktickets' in packages or 'all' in packages: with_tickets = False if 'ktickets' in packages or 'all' in packages: with_tickets = True await self.get_kerberos(with_tickets) if 'tspkg' in packages or 'all' in packages: try: await self.get_tspkg() except Exception as e: self.errors.append(('tspkg', e)) if 'ssp' in packages or 'all' in packages: try: await self.get_ssp() except Exception as e: self.errors.append(('ssp', e)) if 'livessp' in packages or 'all' in packages: try: await self.get_livessp() except Exception as e: self.errors.append(('livessp', e)) if 'dpapi' in packages or 'all' in packages: try: await self.get_dpapi() except Exception as e: self.errors.append(('dpapi', e)) if 'cloudap' in packages or 'all' in packages: try: await self.get_cloudap() except Exception as e: self.errors.append(('cloudap', e))