From 08cbf75b5fcaf6ad4d65b56299794e7dc024c626 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 7 Mar 2022 12:21:24 +0530 Subject: [PATCH 01/19] Agent: Remove credential hashes in logging in Zerologon exploiter --- monkey/infection_monkey/exploit/zerologon.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index f05983d92..6f55ff106 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -329,12 +329,7 @@ class ZerologonExploiter(HostExploiter): self.remove_locally_saved_HKLM_keys() def save_HKLM_keys_locally(self, username: str, user_pwd_hashes: List[str]) -> bool: - logger.info( - f"Starting remote shell on victim with credentials:\n" - f"user: {username}\n" - f"hashes (SHA-512): {self._config.hash_sensitive_data(user_pwd_hashes[0])} : " - f"{self._config.hash_sensitive_data(user_pwd_hashes[1])}" - ) + logger.info(f"Starting remote shell on victim with user: {username}") wmiexec = Wmiexec( ip=self.dc_ip, From aee3566a0c1885dc3455b75aba12f498b9039125 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 7 Mar 2022 14:11:09 +0530 Subject: [PATCH 02/19] Agent: Remove WormConfiguration references in Zerologon exploiter --- monkey/infection_monkey/exploit/zerologon.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 6f55ff106..43b872635 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -269,7 +269,7 @@ class ZerologonExploiter(HostExploiter): self._extracted_creds[user]["lm_hash"], self._extracted_creds[user]["nt_hash"], ) - self.add_extracted_creds_to_monkey_config( + self.add_extracted_creds_to_exploiter_options( user, self._extracted_creds[user]["lm_hash"], self._extracted_creds[user]["nt_hash"], @@ -290,15 +290,15 @@ class ZerologonExploiter(HostExploiter): ) # so other exploiters can use these creds - def add_extracted_creds_to_monkey_config(self, user: str, lmhash: str, nthash: str) -> None: - if user not in self._config.exploit_user_list: - self._config.exploit_user_list.append(user) + def add_extracted_creds_to_exploiter_options(self, user: str, lmhash: str, nthash: str) -> None: + if user not in self.options["credentials"]["exploit_user_list"]: + self.options["credentials"]["exploit_user_list"].append(user) - if lmhash not in self._config.exploit_lm_hash_list: - self._config.exploit_lm_hash_list.append(lmhash) + if lmhash not in self.options["credentials"]["exploit_lm_hash_list"]: + self.options["credentials"]["exploit_lm_hash_list"].append(lmhash) - if nthash not in self._config.exploit_ntlm_hash_list: - self._config.exploit_ntlm_hash_list.append(nthash) + if nthash not in self.options["credentials"]["exploit_ntlm_hash_list"]: + self.options["credentials"]["exploit_ntlm_hash_list"].append(nthash) def get_original_pwd_nthash(self, username: str, user_pwd_hashes: List[str]) -> str: if not self.save_HKLM_keys_locally(username, user_pwd_hashes): From 040227286ad3e13d264129059e09d36c4ca666e6 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 7 Mar 2022 15:01:38 +0530 Subject: [PATCH 03/19] Agent: Send extracted creds as CredentialTelemetry from Zerologon exploiter --- monkey/infection_monkey/exploit/zerologon.py | 23 ++++++++------------ 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 43b872635..a1b8a3f42 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -16,11 +16,14 @@ from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport from impacket.dcerpc.v5.dtypes import NULL from common.utils.exploit_enum import ExploitType +from infection_monkey.credential_collectors import LMHash, NTHash, Username from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets from infection_monkey.exploit.zerologon_utils.options import OptionsForSecretsdump from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details, is_exploitable from infection_monkey.exploit.zerologon_utils.wmiexec import Wmiexec +from infection_monkey.i_puppet.credential_collection import Credentials +from infection_monkey.telemetry.credentials_telem import CredentialsTelem from infection_monkey.utils.capture_output import StdoutCapture logger = logging.getLogger(__name__) @@ -36,7 +39,6 @@ class ZerologonExploiter(HostExploiter): def __init__(self, host: object): super().__init__(host) - self.exploit_info["credentials"] = {} self.exploit_info["password_restored"] = None self._extracted_creds = {} self._secrets_dir = tempfile.TemporaryDirectory(prefix="zerologon") @@ -264,7 +266,7 @@ class ZerologonExploiter(HostExploiter): def store_extracted_creds_for_exploitation(self) -> None: for user in self._extracted_creds.keys(): - self.add_extracted_creds_to_exploit_info( + self.send_extracted_creds_as_credential_telemetry( user, self._extracted_creds[user]["lm_hash"], self._extracted_creds[user]["nt_hash"], @@ -275,18 +277,11 @@ class ZerologonExploiter(HostExploiter): self._extracted_creds[user]["nt_hash"], ) - def add_extracted_creds_to_exploit_info(self, user: str, lmhash: str, nthash: str) -> None: - # TODO exploit_info["credentials"] is discontinued, - # refactor to send a credential telemetry - self.exploit_info["credentials"].update( - { - user: { - "username": user, - "password": "", - "lm_hash": lmhash, - "ntlm_hash": nthash, - } - } + def send_extracted_creds_as_credential_telemetry( + self, user: str, lmhash: str, nthash: str + ) -> None: + self._telemetry_messenger.send_telemetry( + CredentialsTelem([Credentials([Username(user)], [LMHash(lmhash), NTHash(nthash)])]) ) # so other exploiters can use these creds From a927879334ec7de4cae86754ae6ced93f8455af9 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 7 Mar 2022 16:57:50 +0530 Subject: [PATCH 04/19] Agent: Remove `host` from Zerologon exploiter's constructor --- monkey/infection_monkey/exploit/zerologon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index a1b8a3f42..2ad1b0a36 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -37,8 +37,8 @@ class ZerologonExploiter(HostExploiter): MAX_ATTEMPTS = 2000 # For 2000, expected average number of attempts needed: 256. ERROR_CODE_ACCESS_DENIED = 0xC0000022 - def __init__(self, host: object): - super().__init__(host) + def __init__(self): + super().__init__() self.exploit_info["password_restored"] = None self._extracted_creds = {} self._secrets_dir = tempfile.TemporaryDirectory(prefix="zerologon") From 5ec05d56177b0bdf9aab3fe1323743f348604354 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 7 Mar 2022 17:00:38 +0530 Subject: [PATCH 05/19] UT: Fix Zerologon UTs --- .../unit_tests/infection_monkey/exploit/test_zerologon.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/test_zerologon.py b/monkey/tests/unit_tests/infection_monkey/exploit/test_zerologon.py index 95beb1778..4a6fbf53d 100644 --- a/monkey/tests/unit_tests/infection_monkey/exploit/test_zerologon.py +++ b/monkey/tests/unit_tests/infection_monkey/exploit/test_zerologon.py @@ -1,7 +1,5 @@ import pytest -from infection_monkey.model.host import VictimHost - DOMAIN_NAME = "domain-name" IP = "0.0.0.0" NETBIOS_NAME = "NetBIOS Name" @@ -19,8 +17,7 @@ def zerologon_exploiter_object(monkeypatch): def mock_report_login_attempt(**kwargs): return None - host = VictimHost(IP, DOMAIN_NAME) - obj = ZerologonExploiter(host) + obj = ZerologonExploiter() monkeypatch.setattr(obj, "dc_name", NETBIOS_NAME, raising=False) monkeypatch.setattr(obj, "report_login_attempt", mock_report_login_attempt) return obj From 325e58cea25b0c32954a1c10cf40bb12a66d1268 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 7 Mar 2022 15:21:24 +0200 Subject: [PATCH 06/19] Agent: explicitly specify some timeouts in zerologon exploiter --- .../infection_monkey/exploit/zerologon_utils/dump_secrets.py | 5 ++++- .../infection_monkey/exploit/zerologon_utils/remote_shell.py | 1 + monkey/infection_monkey/exploit/zerologon_utils/wmiexec.py | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon_utils/dump_secrets.py b/monkey/infection_monkey/exploit/zerologon_utils/dump_secrets.py index c208a61f6..7fb0c5288 100644 --- a/monkey/infection_monkey/exploit/zerologon_utils/dump_secrets.py +++ b/monkey/infection_monkey/exploit/zerologon_utils/dump_secrets.py @@ -56,6 +56,7 @@ from impacket.examples.secretsdump import ( ) from impacket.smbconnection import SMBConnection +from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT from infection_monkey.utils.capture_output import StdoutCapture logger = logging.getLogger(__name__) @@ -96,7 +97,9 @@ class DumpSecrets: self.__lmhash, self.__nthash = options.hashes.split(":") def connect(self): - self.__smb_connection = SMBConnection(self.__remote_name, self.__remote_host) + self.__smb_connection = SMBConnection( + self.__remote_name, self.__remote_host, timeout=LONG_REQUEST_TIMEOUT + ) self.__smb_connection.login( self.__username, self.__password, diff --git a/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py b/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py index d899c73e8..4d3de85bc 100644 --- a/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py +++ b/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py @@ -71,6 +71,7 @@ class RemoteShell(cmd.Cmd): self.__secrets_dir = secrets_dir # We don't wanna deal with timeouts from now on. + # TODO are we sure we don't need timeout anymore? if self.__transferClient is not None: self.__transferClient.setTimeout(100000) self.do_cd("\\") diff --git a/monkey/infection_monkey/exploit/zerologon_utils/wmiexec.py b/monkey/infection_monkey/exploit/zerologon_utils/wmiexec.py index ad5f2a9d3..e9816bde0 100644 --- a/monkey/infection_monkey/exploit/zerologon_utils/wmiexec.py +++ b/monkey/infection_monkey/exploit/zerologon_utils/wmiexec.py @@ -51,6 +51,7 @@ from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.dtypes import NULL from impacket.smbconnection import SMBConnection +from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT from infection_monkey.exploit.zerologon_utils.remote_shell import RemoteShell logger = logging.getLogger(__name__) @@ -74,7 +75,7 @@ class Wmiexec: self.shell = None def connect(self): - self.smbConnection = SMBConnection(self.__ip, self.__ip) + self.smbConnection = SMBConnection(self.__ip, self.__ip, timeout=LONG_REQUEST_TIMEOUT) self.smbConnection.login( user=self.__username, password=self.__password, From c322446aee84a9b6f5b7664402e3cfd657d04c3d Mon Sep 17 00:00:00 2001 From: vakarisz Date: Mon, 7 Mar 2022 16:42:57 +0200 Subject: [PATCH 07/19] Agent: use exploit_results in zerologon --- monkey/infection_monkey/exploit/zerologon.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 2ad1b0a36..0590326f3 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -22,6 +22,7 @@ from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets from infection_monkey.exploit.zerologon_utils.options import OptionsForSecretsdump from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details, is_exploitable from infection_monkey.exploit.zerologon_utils.wmiexec import Wmiexec +from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.i_puppet.credential_collection import Credentials from infection_monkey.telemetry.credentials_telem import CredentialsTelem from infection_monkey.utils.capture_output import StdoutCapture @@ -46,11 +47,12 @@ class ZerologonExploiter(HostExploiter): def __del__(self): self._secrets_dir.cleanup() - def _exploit_host(self) -> bool: + def _exploit_host(self) -> ExploiterResultData: self.dc_ip, self.dc_name, self.dc_handle = get_dc_details(self.host) can_exploit, rpc_con = is_exploitable(self) if can_exploit: + self.exploit_result.exploitation_success = True logger.info("Target vulnerable, changing account password to empty string.") # Start exploiting attempts. @@ -64,10 +66,11 @@ class ZerologonExploiter(HostExploiter): "Exploit not attempted. Target is most likely patched, or an error was " "encountered." ) - return False + return self.exploit_result # Restore DC's original password. if _exploited: + self.exploit_result.propagation_success = True if self.restore_password(): self.exploit_info["password_restored"] = True self.store_extracted_creds_for_exploitation() @@ -78,7 +81,7 @@ class ZerologonExploiter(HostExploiter): else: logger.info("System was not exploited.") - return _exploited + return self.exploit_result @staticmethod def connect_to_dc(dc_ip) -> object: From 118c2abaee16f7bfb3d1611470f226ba20745dcb Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 8 Mar 2022 10:32:16 -0500 Subject: [PATCH 08/19] Agent: Load ZerologonExploiter into the puppet --- monkey/infection_monkey/monkey.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 218b0e92a..d349954c8 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -20,6 +20,7 @@ from infection_monkey.exploit.hadoop import HadoopExploiter from infection_monkey.exploit.log4shell import Log4ShellExploiter from infection_monkey.exploit.sshexec import SSHExploiter from infection_monkey.exploit.wmiexec import WmiExploiter +from infection_monkey.exploit.zerologon import ZerologonExploiter from infection_monkey.i_puppet import IPuppet, PluginType from infection_monkey.master import AutomatedMaster from infection_monkey.master.control_channel import ControlChannel @@ -221,6 +222,11 @@ class InfectionMonkey: ) puppet.load_plugin("SSHExploiter", exploit_wrapper.wrap(SSHExploiter), PluginType.EXPLOITER) puppet.load_plugin("WmiExploiter", exploit_wrapper.wrap(WmiExploiter), PluginType.EXPLOITER) + puppet.load_plugin( + "ZerologonExploiter", + exploit_wrapper.wrap(ZerologonExploiter), + PluginType.EXPLOITER, + ) puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD) From 0d5fcf7fbf489921d7e3f6959a97e9e307889857 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 8 Mar 2022 10:35:04 -0500 Subject: [PATCH 09/19] Agent: Fix name of self.telemetry_messenger in ZerologonExploiter --- monkey/infection_monkey/exploit/zerologon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 0590326f3..54ea21cd7 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -283,7 +283,7 @@ class ZerologonExploiter(HostExploiter): def send_extracted_creds_as_credential_telemetry( self, user: str, lmhash: str, nthash: str ) -> None: - self._telemetry_messenger.send_telemetry( + self.telemetry_messenger.send_telemetry( CredentialsTelem([Credentials([Username(user)], [LMHash(lmhash), NTHash(nthash)])]) ) From 8bc6086e1a8395b681519b0d4a1b225ff9e8e126 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 8 Mar 2022 11:10:52 -0500 Subject: [PATCH 10/19] Agent: Correctly set propagation/exploitation status in Zerologon --- monkey/infection_monkey/exploit/zerologon.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 54ea21cd7..6f13f16c4 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -70,7 +70,8 @@ class ZerologonExploiter(HostExploiter): # Restore DC's original password. if _exploited: - self.exploit_result.propagation_success = True + self.exploit_result.propagation_success = False + self.exploit_result.exploitation_success = _exploited if self.restore_password(): self.exploit_info["password_restored"] = True self.store_extracted_creds_for_exploitation() From d6fe9c2ef24b2f51789cd0b37c405ac1d3944100 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 9 Mar 2022 14:08:06 +0530 Subject: [PATCH 11/19] Agent: Remove `add_extracted_creds_to_exploiter_options()` from Zerologon exploiter --- monkey/infection_monkey/exploit/zerologon.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 6f13f16c4..849e6935a 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -275,11 +275,6 @@ class ZerologonExploiter(HostExploiter): self._extracted_creds[user]["lm_hash"], self._extracted_creds[user]["nt_hash"], ) - self.add_extracted_creds_to_exploiter_options( - user, - self._extracted_creds[user]["lm_hash"], - self._extracted_creds[user]["nt_hash"], - ) def send_extracted_creds_as_credential_telemetry( self, user: str, lmhash: str, nthash: str @@ -288,17 +283,6 @@ class ZerologonExploiter(HostExploiter): CredentialsTelem([Credentials([Username(user)], [LMHash(lmhash), NTHash(nthash)])]) ) - # so other exploiters can use these creds - def add_extracted_creds_to_exploiter_options(self, user: str, lmhash: str, nthash: str) -> None: - if user not in self.options["credentials"]["exploit_user_list"]: - self.options["credentials"]["exploit_user_list"].append(user) - - if lmhash not in self.options["credentials"]["exploit_lm_hash_list"]: - self.options["credentials"]["exploit_lm_hash_list"].append(lmhash) - - if nthash not in self.options["credentials"]["exploit_ntlm_hash_list"]: - self.options["credentials"]["exploit_ntlm_hash_list"].append(nthash) - def get_original_pwd_nthash(self, username: str, user_pwd_hashes: List[str]) -> str: if not self.save_HKLM_keys_locally(username, user_pwd_hashes): return From 5e3829aab3420a34e6992cfbefe0d409807f867e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 9 Mar 2022 17:00:33 +0530 Subject: [PATCH 12/19] Island: Add field `propagated` to node and rename image files --- monkey/monkey_island/cc/services/node.py | 15 ++++++++++++++- .../cc/services/telemetry/processing/exploit.py | 2 ++ .../cc/services/utils/node_states.py | 2 ++ ...{exploited_linux.png => propagated_linux.png} | Bin ...loited_windows.png => propagated_windows.png} | Bin 5 files changed, 18 insertions(+), 1 deletion(-) rename monkey/monkey_island/cc/ui/src/images/nodes/{exploited_linux.png => propagated_linux.png} (100%) rename monkey/monkey_island/cc/ui/src/images/nodes/{exploited_windows.png => propagated_windows.png} (100%) diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index 74fb1b091..a1708e270 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -128,8 +128,16 @@ class NodeService: def get_node_group(node) -> str: if "group" in node and node["group"]: return node["group"] - node_type = "exploited" if node.get("exploited") else "clean" + + if node.get("exploited"): + node_type = "exploited" + elif node.get("propagated"): + node_type = "propagated" + else: + node_type = "clean" + node_os = NodeService.get_node_os(node) + return NodeStates.get_by_keywords([node_type, node_os]).value @staticmethod @@ -202,6 +210,7 @@ class NodeService: "ip_addresses": [ip_address], "domain_name": domain_name, "exploited": False, + "propagated": False, "os": {"type": "unknown", "version": "unknown"}, } ) @@ -288,6 +297,10 @@ class NodeService: def set_node_exploited(node_id): mongo.db.node.update({"_id": node_id}, {"$set": {"exploited": True}}) + @staticmethod + def set_node_propagated(node_id): + mongo.db.node.update({"_id": node_id}, {"$set": {"propagated": True}}) + @staticmethod def update_dead_monkeys(): # Update dead monkeys only if no living monkey transmitted keepalive in the last 10 minutes diff --git a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py index d035dedd3..da46cdcc7 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/exploit.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/exploit.py @@ -52,6 +52,8 @@ def update_network_with_exploit(edge: EdgeService, telemetry_json): edge.update_based_on_exploit(new_exploit) if new_exploit["exploitation_result"]: NodeService.set_node_exploited(edge.dst_node_id) + if new_exploit["propagation_result"]: + NodeService.set_node_propagated(edge.dst_node_id) def encrypt_exploit_creds(telemetry_json): diff --git a/monkey/monkey_island/cc/services/utils/node_states.py b/monkey/monkey_island/cc/services/utils/node_states.py index 0d6371111..476255de4 100644 --- a/monkey/monkey_island/cc/services/utils/node_states.py +++ b/monkey/monkey_island/cc/services/utils/node_states.py @@ -11,6 +11,8 @@ class NodeStates(Enum): CLEAN_WINDOWS = "clean_windows" EXPLOITED_LINUX = "exploited_linux" EXPLOITED_WINDOWS = "exploited_windows" + PROPAGATED_LINUX = "propagated_linux" + PROPAGATED_WINDOWS = "propagated_windows" ISLAND = "island" ISLAND_MONKEY_LINUX = "island_monkey_linux" ISLAND_MONKEY_LINUX_RUNNING = "island_monkey_linux_running" diff --git a/monkey/monkey_island/cc/ui/src/images/nodes/exploited_linux.png b/monkey/monkey_island/cc/ui/src/images/nodes/propagated_linux.png similarity index 100% rename from monkey/monkey_island/cc/ui/src/images/nodes/exploited_linux.png rename to monkey/monkey_island/cc/ui/src/images/nodes/propagated_linux.png diff --git a/monkey/monkey_island/cc/ui/src/images/nodes/exploited_windows.png b/monkey/monkey_island/cc/ui/src/images/nodes/propagated_windows.png similarity index 100% rename from monkey/monkey_island/cc/ui/src/images/nodes/exploited_windows.png rename to monkey/monkey_island/cc/ui/src/images/nodes/propagated_windows.png From a3eb0bc6f271562a91361c68902e686d7e7d0506 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 9 Mar 2022 17:04:07 +0530 Subject: [PATCH 13/19] Island: Remove unused `set_node_group()` in NodeService --- monkey/monkey_island/cc/services/node.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index a1708e270..fe0c9489a 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -172,10 +172,6 @@ class NodeService: "os": NodeService.get_node_os(node), } - @staticmethod - def set_node_group(node_id: str, node_group: NodeStates): - mongo.db.node.update({"_id": node_id}, {"$set": {"group": node_group.value}}, upsert=False) - @staticmethod def unset_all_monkey_tunnels(monkey_id): mongo.db.monkey.update({"_id": monkey_id}, {"$unset": {"tunnel": ""}}, upsert=False) From a8018a7956610263c91ceaa6fba764aa07614d86 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Wed, 9 Mar 2022 15:54:23 +0000 Subject: [PATCH 14/19] Agent: Add impacket_user decorator to the zerologon impacket_user decorator will awoid race conditions with other exploiters using wmi tools --- monkey/infection_monkey/exploit/zerologon.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 849e6935a..153b31bdd 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -18,6 +18,7 @@ from impacket.dcerpc.v5.dtypes import NULL from common.utils.exploit_enum import ExploitType from infection_monkey.credential_collectors import LMHash, NTHash, Username from infection_monkey.exploit.HostExploiter import HostExploiter +from infection_monkey.exploit.tools.wmi_tools import WmiTools from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets from infection_monkey.exploit.zerologon_utils.options import OptionsForSecretsdump from infection_monkey.exploit.zerologon_utils.vuln_assessment import get_dc_details, is_exploitable @@ -47,6 +48,7 @@ class ZerologonExploiter(HostExploiter): def __del__(self): self._secrets_dir.cleanup() + @WmiTools.impacket_user def _exploit_host(self) -> ExploiterResultData: self.dc_ip, self.dc_name, self.dc_handle = get_dc_details(self.host) From 2c8aef6d8019c1b5c85545cacef125741d45ed8e Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Wed, 9 Mar 2022 15:55:38 +0000 Subject: [PATCH 15/19] Island: remove unused node states Exploited node state is no longer used, returning it in the list caused errors on the ui --- monkey/monkey_island/cc/services/node.py | 4 +--- monkey/monkey_island/cc/services/utils/node_states.py | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index fe0c9489a..a006d9d7f 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -129,9 +129,7 @@ class NodeService: if "group" in node and node["group"]: return node["group"] - if node.get("exploited"): - node_type = "exploited" - elif node.get("propagated"): + if node.get("propagated"): node_type = "propagated" else: node_type = "clean" diff --git a/monkey/monkey_island/cc/services/utils/node_states.py b/monkey/monkey_island/cc/services/utils/node_states.py index 476255de4..cb8024bd2 100644 --- a/monkey/monkey_island/cc/services/utils/node_states.py +++ b/monkey/monkey_island/cc/services/utils/node_states.py @@ -9,8 +9,6 @@ class NodeStates(Enum): CLEAN_UNKNOWN = "clean_unknown" CLEAN_LINUX = "clean_linux" CLEAN_WINDOWS = "clean_windows" - EXPLOITED_LINUX = "exploited_linux" - EXPLOITED_WINDOWS = "exploited_windows" PROPAGATED_LINUX = "propagated_linux" PROPAGATED_WINDOWS = "propagated_windows" ISLAND = "island" From 720768e25de34359713dc4bda73abc79236c86f5 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 9 Mar 2022 14:43:10 -0500 Subject: [PATCH 16/19] Agent: Add debug logging to decorators in WmiTools --- monkey/infection_monkey/exploit/tools/wmi_tools.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/tools/wmi_tools.py b/monkey/infection_monkey/exploit/tools/wmi_tools.py index 30ae59107..976e462e5 100644 --- a/monkey/infection_monkey/exploit/tools/wmi_tools.py +++ b/monkey/infection_monkey/exploit/tools/wmi_tools.py @@ -24,11 +24,12 @@ class AccessDeniedException(Exception): class WmiTools(object): - @staticmethod def impacket_user(func): def _wrapper(*args, **kwarg): + logger.debug("Waiting for impacket lock") with lock: + logger.debug("Acquired impacket lock") return func(*args, **kwarg) return _wrapper @@ -93,8 +94,10 @@ class WmiTools(object): def dcom_wrap(func): def _wrapper(*args, **kwarg): try: + logger.debug("Running function from dcom_wrap") return func(*args, **kwarg) finally: + logger.debug("Running dcom cleanup") WmiTools.dcom_cleanup() return _wrapper From 27e3cc6b4cf0b57c54bb2635027aee786b841f06 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 9 Mar 2022 15:21:46 -0500 Subject: [PATCH 17/19] Agent: Add @wraps to WmiTools decorators --- monkey/infection_monkey/exploit/tools/wmi_tools.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkey/infection_monkey/exploit/tools/wmi_tools.py b/monkey/infection_monkey/exploit/tools/wmi_tools.py index 976e462e5..ab0afdb89 100644 --- a/monkey/infection_monkey/exploit/tools/wmi_tools.py +++ b/monkey/infection_monkey/exploit/tools/wmi_tools.py @@ -1,5 +1,6 @@ import logging import threading +from functools import wraps from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dcom.wmi import DCERPCSessionError @@ -26,6 +27,7 @@ class AccessDeniedException(Exception): class WmiTools(object): @staticmethod def impacket_user(func): + @wraps(func) def _wrapper(*args, **kwarg): logger.debug("Waiting for impacket lock") with lock: @@ -92,6 +94,7 @@ class WmiTools(object): @staticmethod def dcom_wrap(func): + @wraps(func) def _wrapper(*args, **kwarg): try: logger.debug("Running function from dcom_wrap") From d9ee377945f69b53a4821835e934ee410a061d31 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Thu, 10 Mar 2022 10:18:35 +0000 Subject: [PATCH 18/19] Agent: fix access denied error handling in wmi_tools.py --- monkey/infection_monkey/exploit/tools/wmi_tools.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/tools/wmi_tools.py b/monkey/infection_monkey/exploit/tools/wmi_tools.py index ab0afdb89..682dfee60 100644 --- a/monkey/infection_monkey/exploit/tools/wmi_tools.py +++ b/monkey/infection_monkey/exploit/tools/wmi_tools.py @@ -64,9 +64,13 @@ class WmiTools(object): wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login ) except Exception as exc: - dcom.disconnect() + try: + dcom.disconnect() + except KeyError: + # No connection to disconnect + pass - if "rpc_s_access_denied" == exc: + if "rpc_s_access_denied" == exc.error_string: raise AccessDeniedException(host, username, password, domain) raise From dd2168e8383edaab3b8b436437338f0f08b2368e Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Thu, 10 Mar 2022 12:00:27 -0500 Subject: [PATCH 19/19] Agent: Log exception information on dcom.disconnect() key error --- monkey/infection_monkey/exploit/tools/wmi_tools.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/tools/wmi_tools.py b/monkey/infection_monkey/exploit/tools/wmi_tools.py index 682dfee60..5b21d2d9f 100644 --- a/monkey/infection_monkey/exploit/tools/wmi_tools.py +++ b/monkey/infection_monkey/exploit/tools/wmi_tools.py @@ -67,8 +67,7 @@ class WmiTools(object): try: dcom.disconnect() except KeyError: - # No connection to disconnect - pass + logger.exception("Disconnecting the DCOMConnection failed") if "rpc_s_access_denied" == exc.error_string: raise AccessDeniedException(host, username, password, domain)