diff --git a/monkey/infection_monkey/control_channel.py b/monkey/infection_monkey/control_channel.py new file mode 100644 index 000000000..90076cbdb --- /dev/null +++ b/monkey/infection_monkey/control_channel.py @@ -0,0 +1,53 @@ +import json +import logging + +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() + +logger = logging.getLogger(__name__) + + +class ControlChannel(IControlChannel): + control_channel_server = WormConfiguration.current_server + + def should_agent_stop(self) -> bool: + if not self.control_channel_server: + return + + try: + response = requests.get( # noqa: DUO123 + f"{self.control_channel_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"An error occurred while trying to connect to server. {e}") + + def get_config(self) -> dict: + ControlClient.load_control_config() + return WormConfiguration.as_dict() + + def get_credentials_for_propagation(self) -> dict: + if not self.control_channel_server: + return + + try: + response = requests.get( # noqa: DUO123 + f"{self.control_channel_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}") diff --git a/monkey/infection_monkey/i_control_channel.py b/monkey/infection_monkey/i_control_channel.py new file mode 100644 index 000000000..6f287671d --- /dev/null +++ b/monkey/infection_monkey/i_control_channel.py @@ -0,0 +1,34 @@ +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: + """ + 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 diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 7ea91c0db..a45800b9f 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -33,12 +33,14 @@ 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 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 @@ -164,10 +166,12 @@ 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/") 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} 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..74e99b10d --- /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..280cdf763 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -407,3 +407,21 @@ 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), + } 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