From d1a4018d5fc77d0feb33162a2859aa1b37e1aed2 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Wed, 16 Mar 2022 10:33:46 +0200 Subject: [PATCH 01/13] Agent: Pass interrupt event to HostExploiter --- monkey/infection_monkey/exploit/HostExploiter.py | 9 +++++++++ monkey/infection_monkey/exploit/exploiter_wrapper.py | 12 ++++++++++-- monkey/infection_monkey/puppet/plugin_registry.py | 3 ++- monkey/infection_monkey/puppet/puppet.py | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/exploit/HostExploiter.py b/monkey/infection_monkey/exploit/HostExploiter.py index 3bda4b0d7..d8afcf97b 100644 --- a/monkey/infection_monkey/exploit/HostExploiter.py +++ b/monkey/infection_monkey/exploit/HostExploiter.py @@ -1,4 +1,5 @@ import logging +import threading from abc import abstractmethod from datetime import datetime from typing import Dict @@ -66,12 +67,14 @@ class HostExploiter: telemetry_messenger: ITelemetryMessenger, agent_repository: IAgentRepository, options: Dict, + interrupt: threading.Event, ): self.host = host self.current_depth = current_depth self.telemetry_messenger = telemetry_messenger self.agent_repository = agent_repository self.options = options + self.interrupt = interrupt self.pre_exploit() try: @@ -91,6 +94,12 @@ class HostExploiter: ) self.set_start_time() + def is_interrupted(self): + # This method should be refactored to raise an exception to reduce duplication in the + # "if is_interrupted: return self.exploitation_results" + # Ideally the user should only do "check_for_interrupt()" + return self.interrupt.is_set() + def post_exploit(self): self.set_finish_time() diff --git a/monkey/infection_monkey/exploit/exploiter_wrapper.py b/monkey/infection_monkey/exploit/exploiter_wrapper.py index 5e855ff22..540e0b4a4 100644 --- a/monkey/infection_monkey/exploit/exploiter_wrapper.py +++ b/monkey/infection_monkey/exploit/exploiter_wrapper.py @@ -1,3 +1,4 @@ +import threading from typing import Dict, Type from infection_monkey.model import VictimHost @@ -26,10 +27,17 @@ class ExploiterWrapper: self._telemetry_messenger = telemetry_messenger self._agent_repository = agent_repository - def exploit_host(self, host: VictimHost, current_depth: int, options: Dict): + def exploit_host( + self, host: VictimHost, current_depth: int, options: Dict, interrupt: threading.Event + ): exploiter = self._exploit_class() return exploiter.exploit_host( - host, current_depth, self._telemetry_messenger, self._agent_repository, options + host, + current_depth, + self._telemetry_messenger, + self._agent_repository, + options, + interrupt, ) def __init__( diff --git a/monkey/infection_monkey/puppet/plugin_registry.py b/monkey/infection_monkey/puppet/plugin_registry.py index 2ec1e3900..1fdca5bd5 100644 --- a/monkey/infection_monkey/puppet/plugin_registry.py +++ b/monkey/infection_monkey/puppet/plugin_registry.py @@ -1,4 +1,5 @@ import logging +from typing import Any from infection_monkey.i_puppet import PluginType, UnknownPluginError @@ -27,7 +28,7 @@ class PluginRegistry: logger.debug(f"Plugin '{plugin_name}' loaded") - def get_plugin(self, plugin_name: str, plugin_type: PluginType) -> object: + def get_plugin(self, plugin_name: str, plugin_type: PluginType) -> Any: try: plugin = self._registry[plugin_type][plugin_name] except KeyError: diff --git a/monkey/infection_monkey/puppet/puppet.py b/monkey/infection_monkey/puppet/puppet.py index 95e72533f..d8bc8e0eb 100644 --- a/monkey/infection_monkey/puppet/puppet.py +++ b/monkey/infection_monkey/puppet/puppet.py @@ -66,7 +66,7 @@ class Puppet(IPuppet): interrupt: threading.Event, ) -> ExploiterResultData: exploiter = self._plugin_registry.get_plugin(name, PluginType.EXPLOITER) - return exploiter.exploit_host(host, current_depth, options) + return exploiter.exploit_host(host, current_depth, options, interrupt) def run_payload(self, name: str, options: Dict, interrupt: threading.Event): payload = self._plugin_registry.get_plugin(name, PluginType.PAYLOAD) From fae25939b53660a60d224e61a8b2ce9860fc5070 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Wed, 16 Mar 2022 10:34:11 +0200 Subject: [PATCH 02/13] Agent: Add interrupt to WMI exploiter --- monkey/infection_monkey/exploit/wmiexec.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 7fc229ebe..1371ae9f2 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -30,6 +30,9 @@ class WmiExploiter(HostExploiter): creds = generate_brute_force_combinations(self.options["credentials"]) for user, password, lm_hash, ntlm_hash in creds: + if self.is_interrupted(): + return self.exploit_result + creds_for_log = get_credential_string([user, password, lm_hash, ntlm_hash]) logger.debug(f"Attempting to connect to {self.host} using WMI with {creds_for_log}") From 520e98032a732516b251b57825f775cee055eb8d Mon Sep 17 00:00:00 2001 From: vakarisz Date: Wed, 16 Mar 2022 13:52:28 +0200 Subject: [PATCH 03/13] Agent, Island: Rename "alive" to "should_stop" in configuration "Alive" indicates state, when in fact we need a value indicating if stop command was sent to this monkey. Monkey alive state is already tracked elsewhere, in the Monkey document --- monkey/infection_monkey/config.py | 2 +- monkey/infection_monkey/example.conf | 2 +- monkey/monkey_island/cc/models/config.py | 2 +- .../monkey_island/cc/services/config_schema/internal.py | 7 +++---- monkey/monkey_island/cc/services/infection_lifecycle.py | 8 ++++---- monkey/monkey_island/cc/services/node.py | 2 +- .../monkey_island/cc/services/test_infection_lifecycle.py | 6 +++--- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index 9c239fd93..8a920cc52 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -81,7 +81,7 @@ class Configuration(object): # monkey config ########################### # sets whether or not the monkey is alive. if false will stop scanning and exploiting - alive = True + should_stop = False # depth of propagation depth = 2 diff --git a/monkey/infection_monkey/example.conf b/monkey/infection_monkey/example.conf index ebadf1429..f0cbb6e16 100644 --- a/monkey/infection_monkey/example.conf +++ b/monkey/infection_monkey/example.conf @@ -9,7 +9,7 @@ "inaccessible_subnets": [], "blocked_ips": [], "current_server": "192.0.2.0:5000", - "alive": true, + "should_stop": false, "collect_system_info": true, "should_use_mimikatz": true, "depth": 2, diff --git a/monkey/monkey_island/cc/models/config.py b/monkey/monkey_island/cc/models/config.py index 437f73b44..db5fd9e94 100644 --- a/monkey/monkey_island/cc/models/config.py +++ b/monkey/monkey_island/cc/models/config.py @@ -8,6 +8,6 @@ class Config(EmbeddedDocument): See https://mongoengine-odm.readthedocs.io/apireference.html#mongoengine.FieldDoesNotExist """ - alive = BooleanField() + should_stop = BooleanField() meta = {"strict": False} pass diff --git a/monkey/monkey_island/cc/services/config_schema/internal.py b/monkey/monkey_island/cc/services/config_schema/internal.py index 98ab8b95e..26326721c 100644 --- a/monkey/monkey_island/cc/services/config_schema/internal.py +++ b/monkey/monkey_island/cc/services/config_schema/internal.py @@ -19,11 +19,10 @@ INTERNAL = { "title": "Monkey", "type": "object", "properties": { - "alive": { - "title": "Alive", + "should_stop": { "type": "boolean", - "default": True, - "description": "Is the monkey alive", + "default": False, + "description": "Was stop command issued for this monkey", }, "aws_keys": { "type": "object", diff --git a/monkey/monkey_island/cc/services/infection_lifecycle.py b/monkey/monkey_island/cc/services/infection_lifecycle.py index 510e3deb6..871c279cc 100644 --- a/monkey/monkey_island/cc/services/infection_lifecycle.py +++ b/monkey/monkey_island/cc/services/infection_lifecycle.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) def set_stop_all(time: float): for monkey in Monkey.objects(): - monkey.config.alive = False + monkey.config.should_stop = True monkey.save() agent_controls = AgentControls.objects.first() agent_controls.last_stop_all = time @@ -25,11 +25,11 @@ def set_stop_all(time: float): def should_agent_die(guid: int) -> bool: monkey = Monkey.objects(guid=str(guid)).first() - return _is_monkey_marked_dead(monkey) or _is_monkey_killed_manually(monkey) + return _should_agent_stop(monkey) or _is_monkey_killed_manually(monkey) -def _is_monkey_marked_dead(monkey: Monkey) -> bool: - return not monkey.config.alive +def _should_agent_stop(monkey: Monkey) -> bool: + return monkey.config.should_stop def _is_monkey_killed_manually(monkey: Monkey) -> bool: diff --git a/monkey/monkey_island/cc/services/node.py b/monkey/monkey_island/cc/services/node.py index 688f67f92..6b672bc4d 100644 --- a/monkey/monkey_island/cc/services/node.py +++ b/monkey/monkey_island/cc/services/node.py @@ -249,7 +249,7 @@ class NodeService: # Cancel the force kill once monkey died if is_dead: - props_to_set["config.alive"] = True + props_to_set["config.should_stop"] = False mongo.db.monkey.update({"guid": monkey["guid"]}, {"$set": props_to_set}, upsert=False) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/test_infection_lifecycle.py b/monkey/tests/unit_tests/monkey_island/cc/services/test_infection_lifecycle.py index 4d4c229c8..541124248 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/test_infection_lifecycle.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/test_infection_lifecycle.py @@ -10,21 +10,21 @@ from monkey_island.cc.services.infection_lifecycle import should_agent_die @pytest.mark.usefixtures("uses_database") def test_should_agent_die_by_config(monkeypatch): monkey = Monkey(guid=str(uuid.uuid4())) - monkey.config = Config(alive=False) + monkey.config = Config(should_stop=True) monkey.save() assert should_agent_die(monkey.guid) monkeypatch.setattr( "monkey_island.cc.services.infection_lifecycle._is_monkey_killed_manually", lambda _: False ) - monkey.config.alive = True + monkey.config.should_stop = True monkey.save() assert not should_agent_die(monkey.guid) def create_monkey(launch_time): monkey = Monkey(guid=str(uuid.uuid4())) - monkey.config = Config(alive=True) + monkey.config = Config(should_stop=False) monkey.launch_time = launch_time monkey.save() return monkey From 1c79efc9410ab8d4753b9d4df3893d5d37bfb845 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Wed, 16 Mar 2022 15:58:34 +0000 Subject: [PATCH 04/13] Agent: Log why exploiter got interrupted when stopped --- monkey/infection_monkey/exploit/HostExploiter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/infection_monkey/exploit/HostExploiter.py b/monkey/infection_monkey/exploit/HostExploiter.py index d8afcf97b..54766d4b2 100644 --- a/monkey/infection_monkey/exploit/HostExploiter.py +++ b/monkey/infection_monkey/exploit/HostExploiter.py @@ -98,6 +98,8 @@ class HostExploiter: # This method should be refactored to raise an exception to reduce duplication in the # "if is_interrupted: return self.exploitation_results" # Ideally the user should only do "check_for_interrupt()" + if self.interrupt.is_set(): + logger.info("Exploiter has been interrupted by a stop signal from the Island") return self.interrupt.is_set() def post_exploit(self): From 1d748640926d4f3bf32ef92f31ccb08c5c0217b6 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Wed, 16 Mar 2022 16:00:58 +0000 Subject: [PATCH 05/13] Island: Fix agent stopping bugs 2 bugs fixed: UI used miliseconds instead of seconds and island kept stopping monkeys, but it should only stop monkey once to not prevent more runs --- monkey/monkey_island/cc/services/infection_lifecycle.py | 7 ++++++- monkey/monkey_island/cc/ui/src/components/pages/MapPage.js | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/services/infection_lifecycle.py b/monkey/monkey_island/cc/services/infection_lifecycle.py index 871c279cc..865602168 100644 --- a/monkey/monkey_island/cc/services/infection_lifecycle.py +++ b/monkey/monkey_island/cc/services/infection_lifecycle.py @@ -29,7 +29,12 @@ def should_agent_die(guid: int) -> bool: def _should_agent_stop(monkey: Monkey) -> bool: - return monkey.config.should_stop + if monkey.config.should_stop: + # Only stop the agent once, to allow further runs on that machine + monkey.config.should_stop = False + monkey.save() + return True + return False def _is_monkey_killed_manually(monkey: Monkey) -> bool: diff --git a/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js b/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js index 3c1350f58..9b4b09f4c 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js @@ -88,10 +88,11 @@ class MapPageComponent extends AuthComponent { { method: 'POST', headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({kill_time: Date.now()}) + // Python uses seconds, Date.now uses milliseconds, so convert + body: JSON.stringify({kill_time: Date.now() / 1000}) }) .then(res => res.json()) - .then(res => {this.setState({killPressed: true}); console.log(res)}); + .then(res => {this.setState({killPressed: true})}); }; renderKillDialogModal = () => { From 6bdd5ef1797d6c2fab67084b956c972003cdef8f Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Thu, 17 Mar 2022 13:50:02 +0000 Subject: [PATCH 06/13] Agent, UI: Improve style with small changes in interrupt code --- monkey/infection_monkey/exploit/HostExploiter.py | 1 + monkey/infection_monkey/exploit/wmiexec.py | 9 ++++++--- .../monkey_island/cc/ui/src/components/pages/MapPage.js | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/exploit/HostExploiter.py b/monkey/infection_monkey/exploit/HostExploiter.py index 54766d4b2..032a0564c 100644 --- a/monkey/infection_monkey/exploit/HostExploiter.py +++ b/monkey/infection_monkey/exploit/HostExploiter.py @@ -100,6 +100,7 @@ class HostExploiter: # Ideally the user should only do "check_for_interrupt()" if self.interrupt.is_set(): logger.info("Exploiter has been interrupted by a stop signal from the Island") + self.exploit_result["error_message"] = "Exploiter has been interrupted by a stop signal from the Island" return self.interrupt.is_set() def post_exploit(self): diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 1371ae9f2..a428a4759 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -15,6 +15,7 @@ from infection_monkey.utils.brute_force import ( get_credential_string, ) from infection_monkey.utils.commands import build_monkey_commandline +from infection_monkey.utils.threading import interruptable_iter logger = logging.getLogger(__name__) @@ -28,10 +29,12 @@ class WmiExploiter(HostExploiter): def _exploit_host(self) -> ExploiterResultData: creds = generate_brute_force_combinations(self.options["credentials"]) + intp_creds = interruptable_iter(creds, + self.interrupt, + "WMI exploiter has been interrupted by a stop signal from the Island", + logging.INFO) - for user, password, lm_hash, ntlm_hash in creds: - if self.is_interrupted(): - return self.exploit_result + for user, password, lm_hash, ntlm_hash in intp_creds: creds_for_log = get_credential_string([user, password, lm_hash, ntlm_hash]) logger.debug(f"Attempting to connect to {self.host} using WMI with {creds_for_log}") diff --git a/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js b/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js index 9b4b09f4c..fa782eac7 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/MapPage.js @@ -88,8 +88,8 @@ class MapPageComponent extends AuthComponent { { method: 'POST', headers: {'Content-Type': 'application/json'}, - // Python uses seconds, Date.now uses milliseconds, so convert - body: JSON.stringify({kill_time: Date.now() / 1000}) + // Python uses floating point seconds, Date.now uses milliseconds, so convert + body: JSON.stringify({kill_time: Date.now() / 1000.0}) }) .then(res => res.json()) .then(res => {this.setState({killPressed: true})}); From a002c96bc63bb0bf342319908329287eaafd20f0 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Thu, 17 Mar 2022 10:45:56 -0400 Subject: [PATCH 07/13] Agent: Add interrupt to powershell tests --- .../unit_tests/infection_monkey/exploit/test_powershell.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py b/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py index f75c57f17..21a0bdeb3 100644 --- a/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py +++ b/monkey/tests/unit_tests/infection_monkey/exploit/test_powershell.py @@ -1,3 +1,4 @@ +import threading from io import BytesIO from unittest.mock import MagicMock @@ -43,6 +44,7 @@ def powershell_arguments(): "current_depth": 2, "telemetry_messenger": MagicMock(), "agent_repository": mock_agent_repository, + "interrupt": threading.Event(), } return arguments From 040a23546ccfbf37422f2bde61bcffebb3f2db56 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Thu, 17 Mar 2022 12:45:37 -0400 Subject: [PATCH 08/13] Agent: Add a comment about Impacket timeouts --- monkey/infection_monkey/exploit/tools/wmi_tools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/infection_monkey/exploit/tools/wmi_tools.py b/monkey/infection_monkey/exploit/tools/wmi_tools.py index 5b21d2d9f..b6346ba14 100644 --- a/monkey/infection_monkey/exploit/tools/wmi_tools.py +++ b/monkey/infection_monkey/exploit/tools/wmi_tools.py @@ -49,6 +49,7 @@ class WmiTools(object): if not domain: domain = host.ip_addr + # Impacket has a hard-coded timeout of 30 seconds dcom = DCOMConnection( host.ip_addr, username=username, From 54bbe8bf2f77dd9ec9df52ec91e0360ded28c15b Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Thu, 17 Mar 2022 12:46:08 -0400 Subject: [PATCH 09/13] Agent: Add WMI error message to results if exploit failed --- monkey/infection_monkey/exploit/wmiexec.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index a428a4759..bfa428856 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -29,10 +29,12 @@ class WmiExploiter(HostExploiter): def _exploit_host(self) -> ExploiterResultData: creds = generate_brute_force_combinations(self.options["credentials"]) - intp_creds = interruptable_iter(creds, - self.interrupt, - "WMI exploiter has been interrupted by a stop signal from the Island", - logging.INFO) + intp_creds = interruptable_iter( + creds, + self.interrupt, + "WMI exploiter has been interrupted by a stop signal from the Island", + logging.INFO, + ) for user, password, lm_hash, ntlm_hash in intp_creds: @@ -66,6 +68,8 @@ class WmiExploiter(HostExploiter): self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) self.exploit_result.exploitation_success = True + # TODO: This check is racey at best. Is it really necessary? If we execute an agent on + # the victim and there's one already running, it will stop itself. # query process list and check if monkey already running on victim process_list = WmiTools.list_object( wmi_connection, @@ -126,7 +130,7 @@ class WmiExploiter(HostExploiter): self.add_vuln_port(port="unknown") self.exploit_result.propagation_success = True else: - logger.debug( + error_message = ( "Error executing dropper '%s' on remote victim %r (pid=%d, exit_code=%d, " "cmdline=%r)", remote_full_path, @@ -135,6 +139,8 @@ class WmiExploiter(HostExploiter): result.ReturnValue, cmdline, ) + logger.debug(error_message) + self.exploit_results.error_message = error_message result.RemRelease() wmi_connection.close() From b70144f5e1a674381c3bca51de8b02c70de67424 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Fri, 18 Mar 2022 08:43:28 +0000 Subject: [PATCH 10/13] Agent: Remove remote check for running monkey in WMI exploiter --- monkey/infection_monkey/exploit/wmiexec.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index bfa428856..4adce62d9 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -68,21 +68,6 @@ class WmiExploiter(HostExploiter): self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) self.exploit_result.exploitation_success = True - # TODO: This check is racey at best. Is it really necessary? If we execute an agent on - # the victim and there's one already running, it will stop itself. - # query process list and check if monkey already running on victim - process_list = WmiTools.list_object( - wmi_connection, - "Win32_Process", - fields=("Caption",), - where=f"Name='{ntpath.split(self.options['dropper_target_path_win_64'])[-1]}'", - ) - if process_list: - wmi_connection.close() - - logger.debug("Skipping %r - already infected", self.host) - return self.exploit_result - downloaded_agent = self.agent_repository.get_agent_binary(self.host.os["type"]) remote_full_path = SmbTools.copy_file( From bd07459dab0ad6b2cf5243d0a26c4c9883a92a28 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Fri, 18 Mar 2022 08:44:35 +0000 Subject: [PATCH 11/13] Agent: Fix typos and comments in WMI and HostExploiter.py --- monkey/infection_monkey/exploit/HostExploiter.py | 4 ++-- monkey/infection_monkey/exploit/wmiexec.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/exploit/HostExploiter.py b/monkey/infection_monkey/exploit/HostExploiter.py index 032a0564c..2e198ac4c 100644 --- a/monkey/infection_monkey/exploit/HostExploiter.py +++ b/monkey/infection_monkey/exploit/HostExploiter.py @@ -99,8 +99,8 @@ class HostExploiter: # "if is_interrupted: return self.exploitation_results" # Ideally the user should only do "check_for_interrupt()" if self.interrupt.is_set(): - logger.info("Exploiter has been interrupted by a stop signal from the Island") - self.exploit_result["error_message"] = "Exploiter has been interrupted by a stop signal from the Island" + logger.info("Exploiter has been interrupted") + self.exploit_result.error_message = "Exploiter has been interrupted" return self.interrupt.is_set() def post_exploit(self): diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 4adce62d9..69eab12dd 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -32,7 +32,7 @@ class WmiExploiter(HostExploiter): intp_creds = interruptable_iter( creds, self.interrupt, - "WMI exploiter has been interrupted by a stop signal from the Island", + "WMI exploiter has been interrupted", logging.INFO, ) @@ -125,7 +125,7 @@ class WmiExploiter(HostExploiter): cmdline, ) logger.debug(error_message) - self.exploit_results.error_message = error_message + self.exploit_result.error_message = error_message result.RemRelease() wmi_connection.close() From 13e5c03cf92d05362758be79cb034d0cc3452cd0 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Fri, 18 Mar 2022 14:14:22 +0200 Subject: [PATCH 12/13] Agent: Add interrupt check before/after agent upload in wmiexec.py --- monkey/infection_monkey/exploit/wmiexec.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 69eab12dd..b50e0830d 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -70,6 +70,9 @@ class WmiExploiter(HostExploiter): downloaded_agent = self.agent_repository.get_agent_binary(self.host.os["type"]) + if self.is_interrupted(): + return self.exploit_result + remote_full_path = SmbTools.copy_file( self.host, downloaded_agent, @@ -81,6 +84,9 @@ class WmiExploiter(HostExploiter): self.options["smb_download_timeout"], ) + if self.is_interrupted(): + return self.exploit_result + if not remote_full_path: wmi_connection.close() return self.exploit_result From bf6d856015f9dc94f1fa19ce1d7e957d46b8c786 Mon Sep 17 00:00:00 2001 From: vakarisz Date: Fri, 18 Mar 2022 14:27:30 +0200 Subject: [PATCH 13/13] Agent: Remove interrupt check after agent upload in wmiexec.py --- monkey/infection_monkey/exploit/wmiexec.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index b50e0830d..7b7c9ad1e 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -84,9 +84,6 @@ class WmiExploiter(HostExploiter): self.options["smb_download_timeout"], ) - if self.is_interrupted(): - return self.exploit_result - if not remote_full_path: wmi_connection.close() return self.exploit_result