From 7766e27f16083d345cae5b30bbe5a3e84a965b39 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 22 Nov 2021 13:46:09 +0100 Subject: [PATCH 1/6] Island: Add mock endpoint to check if the agent should stop --- monkey/monkey_island/cc/app.py | 2 ++ .../cc/resources/monkey_control/stop_agent_check.py | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 monkey/monkey_island/cc/resources/monkey_control/stop_agent_check.py diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 7ea91c0db..113c20d06 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -33,6 +33,7 @@ from monkey_island.cc.resources.monkey import Monkey from monkey_island.cc.resources.monkey_configuration import MonkeyConfiguration from monkey_island.cc.resources.monkey_control.remote_port_check import RemotePortCheck from monkey_island.cc.resources.monkey_control.started_on_island import StartedOnIsland +from monkey_island.cc.resources.monkey_control.stop_agent_check import StopAgentCheck from monkey_island.cc.resources.monkey_download import MonkeyDownload from monkey_island.cc.resources.netmap import NetMap from monkey_island.cc.resources.node import Node @@ -168,6 +169,7 @@ def init_api_resources(api): api.add_resource(VersionUpdate, "/api/version-update", "/api/version-update/") api.add_resource(RemotePortCheck, "/api/monkey_control/check_remote_port/") api.add_resource(StartedOnIsland, "/api/monkey_control/started_on_island") + api.add_resource(StopAgentCheck, "/api/monkey_control/") api.add_resource(ScoutSuiteAuth, "/api/scoutsuite_auth/") api.add_resource(AWSKeys, "/api/aws_keys") diff --git a/monkey/monkey_island/cc/resources/monkey_control/stop_agent_check.py b/monkey/monkey_island/cc/resources/monkey_control/stop_agent_check.py new file mode 100644 index 000000000..817d6db94 --- /dev/null +++ b/monkey/monkey_island/cc/resources/monkey_control/stop_agent_check.py @@ -0,0 +1,9 @@ +import flask_restful + + +class StopAgentCheck(flask_restful.Resource): + def get(self, monkey_guid: int): + if monkey_guid % 2: + return {"stop_agent": True} + else: + return {"stop_agent": False} From 0d8070080ae8b199ffe3ac3ada90e21c5895c7a2 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 22 Nov 2021 14:27:39 +0100 Subject: [PATCH 2/6] Agent: Implement ControlChannel should_agent_stop --- monkey/infection_monkey/control_channel.py | 32 ++++++++++++++++++++ monkey/infection_monkey/i_control_channel.py | 27 +++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 monkey/infection_monkey/control_channel.py create mode 100644 monkey/infection_monkey/i_control_channel.py diff --git a/monkey/infection_monkey/control_channel.py b/monkey/infection_monkey/control_channel.py new file mode 100644 index 000000000..639991e71 --- /dev/null +++ b/monkey/infection_monkey/control_channel.py @@ -0,0 +1,32 @@ +import json +import logging +from abc import ABC + +import requests + +from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT +from infection_monkey.config import GUID, WormConfiguration +from monkey.infection_monkey.i_control_channel import IControlChannel + +requests.packages.urllib3.disable_warnings() + +logger = logging.getLogger(__name__) + + +class ControlChannel(IControlChannel, ABC): + def should_agent_stop(self) -> bool: + server = WormConfiguration.current_server + if not server: + return + + try: + response = requests.get( # noqa: DUO123 + f"{server}/api/monkey_control/{GUID}", + verify=False, + timeout=SHORT_REQUEST_TIMEOUT, + ) + + response = json.loads(response.content.decode()) + return response["stop_agent"] + except Exception as e: + logger.error(f"Error happened while trying to connect to server. {e}") diff --git a/monkey/infection_monkey/i_control_channel.py b/monkey/infection_monkey/i_control_channel.py new file mode 100644 index 000000000..eb1a4d5b2 --- /dev/null +++ b/monkey/infection_monkey/i_control_channel.py @@ -0,0 +1,27 @@ +import abc + + +class IControlChannel(metaclass=abc.ABCMeta): + @abc.abstractmethod + def should_agent_stop(self) -> bool: + """ + Checks if the agent should stop + return: True if the agent should stop, False otherwise + rtype: bool + """ + + @abc.abstractmethod + def get_config(self) -> dict: + """ + :return: A dictionary containing Agent Configuration + :rtype: dict + """ + pass + + @abc.abstractmethod + def get_credentials_for_propagation(self) -> dict: + """ + :return: A dictionary containing propagation credentials data + :rtype: dict + """ + pass From 3aad64dff7c4a42c36a29faa4a39f2e14d89b280 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 22 Nov 2021 19:58:49 +0100 Subject: [PATCH 3/6] Island: Add endpoint to retrive propagation credentials --- monkey/monkey_island/cc/app.py | 2 ++ .../cc/resources/propagation_credentials.py | 9 +++++++++ monkey/monkey_island/cc/services/config.py | 16 ++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 monkey/monkey_island/cc/resources/propagation_credentials.py diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 113c20d06..a45800b9f 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -40,6 +40,7 @@ from monkey_island.cc.resources.node import Node from monkey_island.cc.resources.node_states import NodeStates from monkey_island.cc.resources.pba_file_download import PBAFileDownload from monkey_island.cc.resources.pba_file_upload import FileUpload +from monkey_island.cc.resources.propagation_credentials import PropagationCredentials from monkey_island.cc.resources.ransomware_report import RansomwareReport from monkey_island.cc.resources.remote_run import RemoteRun from monkey_island.cc.resources.root import Root @@ -165,6 +166,7 @@ def init_api_resources(api): "/api/fileUpload/?load=", "/api/fileUpload/?restore=", ) + api.add_resource(PropagationCredentials, "/api/propagationCredentials") api.add_resource(RemoteRun, "/api/remote-monkey", "/api/remote-monkey/") api.add_resource(VersionUpdate, "/api/version-update", "/api/version-update/") api.add_resource(RemotePortCheck, "/api/monkey_control/check_remote_port/") diff --git a/monkey/monkey_island/cc/resources/propagation_credentials.py b/monkey/monkey_island/cc/resources/propagation_credentials.py new file mode 100644 index 000000000..16699300e --- /dev/null +++ b/monkey/monkey_island/cc/resources/propagation_credentials.py @@ -0,0 +1,9 @@ +import flask_restful + +from monkey_island.cc.services.config import ConfigService + + +class PropagationCredentials(flask_restful.Resource): + def get(self): + + return {'propagation_credentials': ConfigService.get_config_propagation_credentials()} diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 0214a957e..4be546c57 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -407,3 +407,19 @@ class ConfigService: @staticmethod def set_started_on_island(value: bool): ConfigService.set_config_value(STARTED_ON_ISLAND_PATH, value) + + @staticmethod + def get_config_propagation_credentials(): + return { + "exploit_user_list": ConfigService.get_config_value(USER_LIST_PATH, should_decrypt=False), + "exploit_password_list": ConfigService.get_config_value( + PASSWORD_LIST_PATH, should_decrypt=False + ), + "exploit_lm_hash_list": ConfigService.get_config_value( + LM_HASH_LIST_PATH, should_decrypt=False + ), + "exploit_ntlm_hash_list": ConfigService.get_config_value( + NTLM_HASH_LIST_PATH, should_decrypt=False + ), + "exploit_ssh_keys": ConfigService.get_config_value(SSH_KEYS_PATH, should_decrypt=False), + } From 65bc0efc5ad4980eb00b00123edc3856949ed708 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Mon, 22 Nov 2021 19:59:35 +0100 Subject: [PATCH 4/6] Agent: Implement get config and get propagation credentials --- monkey/infection_monkey/control_channel.py | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/control_channel.py b/monkey/infection_monkey/control_channel.py index 639991e71..d8ec17c6e 100644 --- a/monkey/infection_monkey/control_channel.py +++ b/monkey/infection_monkey/control_channel.py @@ -1,11 +1,11 @@ import json import logging -from abc import ABC import requests from common.common_consts.timeouts import SHORT_REQUEST_TIMEOUT from infection_monkey.config import GUID, WormConfiguration +from infection_monkey.control import ControlClient from monkey.infection_monkey.i_control_channel import IControlChannel requests.packages.urllib3.disable_warnings() @@ -13,7 +13,7 @@ requests.packages.urllib3.disable_warnings() logger = logging.getLogger(__name__) -class ControlChannel(IControlChannel, ABC): +class ControlChannel(IControlChannel): def should_agent_stop(self) -> bool: server = WormConfiguration.current_server if not server: @@ -29,4 +29,24 @@ class ControlChannel(IControlChannel, ABC): response = json.loads(response.content.decode()) return response["stop_agent"] except Exception as e: - logger.error(f"Error happened while trying to connect to server. {e}") + logger.error(f"An error occurred while trying to connect to server. {e}") + + def get_config(self) -> dict: + return ControlClient.load_control_config() + + def get_credentials_for_propagation(self) -> dict: + server = WormConfiguration.current_server + if not server: + return + + try: + response = requests.get( # noqa: DUO123 + f"{server}/api/propagationCredentials", + verify=False, + timeout=SHORT_REQUEST_TIMEOUT, + ) + + response = json.loads(response.content.decode())["propagation_credentials"] + return response + except Exception as e: + logger.error(f"An error occurred while trying to connect to server. {e}") From 56f07e01882fcb45677b5e26bd538765ac25f12d Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Tue, 23 Nov 2021 11:13:14 +0100 Subject: [PATCH 5/6] Agent: Add control channel server property --- monkey/infection_monkey/control_channel.py | 15 ++++++++------- monkey/infection_monkey/i_control_channel.py | 7 +++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/monkey/infection_monkey/control_channel.py b/monkey/infection_monkey/control_channel.py index d8ec17c6e..90076cbdb 100644 --- a/monkey/infection_monkey/control_channel.py +++ b/monkey/infection_monkey/control_channel.py @@ -14,14 +14,15 @@ logger = logging.getLogger(__name__) class ControlChannel(IControlChannel): + control_channel_server = WormConfiguration.current_server + def should_agent_stop(self) -> bool: - server = WormConfiguration.current_server - if not server: + if not self.control_channel_server: return try: response = requests.get( # noqa: DUO123 - f"{server}/api/monkey_control/{GUID}", + f"{self.control_channel_server}/api/monkey_control/{GUID}", verify=False, timeout=SHORT_REQUEST_TIMEOUT, ) @@ -32,16 +33,16 @@ class ControlChannel(IControlChannel): logger.error(f"An error occurred while trying to connect to server. {e}") def get_config(self) -> dict: - return ControlClient.load_control_config() + ControlClient.load_control_config() + return WormConfiguration.as_dict() def get_credentials_for_propagation(self) -> dict: - server = WormConfiguration.current_server - if not server: + if not self.control_channel_server: return try: response = requests.get( # noqa: DUO123 - f"{server}/api/propagationCredentials", + f"{self.control_channel_server}/api/propagationCredentials", verify=False, timeout=SHORT_REQUEST_TIMEOUT, ) diff --git a/monkey/infection_monkey/i_control_channel.py b/monkey/infection_monkey/i_control_channel.py index eb1a4d5b2..6f287671d 100644 --- a/monkey/infection_monkey/i_control_channel.py +++ b/monkey/infection_monkey/i_control_channel.py @@ -2,6 +2,13 @@ import abc class IControlChannel(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def control_channel_server(self): + """ + :return: Worm configuration server + """ + @abc.abstractmethod def should_agent_stop(self) -> bool: """ From 839024f2437cd04fd4ecc5d5ce91cde870b8fe7b Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Tue, 23 Nov 2021 15:20:19 +0100 Subject: [PATCH 6/6] Island: Fix formatting in config --- monkey/monkey_island/cc/resources/propagation_credentials.py | 2 +- monkey/monkey_island/cc/services/config.py | 4 +++- vulture_allowlist.py | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/resources/propagation_credentials.py b/monkey/monkey_island/cc/resources/propagation_credentials.py index 16699300e..74e99b10d 100644 --- a/monkey/monkey_island/cc/resources/propagation_credentials.py +++ b/monkey/monkey_island/cc/resources/propagation_credentials.py @@ -6,4 +6,4 @@ from monkey_island.cc.services.config import ConfigService class PropagationCredentials(flask_restful.Resource): def get(self): - return {'propagation_credentials': ConfigService.get_config_propagation_credentials()} + return {"propagation_credentials": ConfigService.get_config_propagation_credentials()} diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 4be546c57..280cdf763 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -411,7 +411,9 @@ class ConfigService: @staticmethod def get_config_propagation_credentials(): return { - "exploit_user_list": ConfigService.get_config_value(USER_LIST_PATH, should_decrypt=False), + "exploit_user_list": ConfigService.get_config_value( + USER_LIST_PATH, should_decrypt=False + ), "exploit_password_list": ConfigService.get_config_value( PASSWORD_LIST_PATH, should_decrypt=False ), diff --git a/vulture_allowlist.py b/vulture_allowlist.py index f2c6edf3a..4f67c9860 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -209,3 +209,6 @@ scan_tcp_port fingerprint interrupt MockPuppet +ControlChannel +should_agent_stop +get_credentials_for_propagation