diff --git a/envs/monkey_zoo/blackbox/config_templates/performance.py b/envs/monkey_zoo/blackbox/config_templates/performance.py index e5213b649..2662642e6 100644 --- a/envs/monkey_zoo/blackbox/config_templates/performance.py +++ b/envs/monkey_zoo/blackbox/config_templates/performance.py @@ -24,6 +24,7 @@ class Performance(ConfigTemplate): "HadoopExploiter", "VSFTPDExploiter", "MSSQLExploiter", + "PowerShellExploiter", "ZerologonExploiter", ], "basic_network.network_analysis.inaccessible_subnets": [ diff --git a/envs/monkey_zoo/blackbox/config_templates/powershell.py b/envs/monkey_zoo/blackbox/config_templates/powershell.py new file mode 100644 index 000000000..e6d2467ab --- /dev/null +++ b/envs/monkey_zoo/blackbox/config_templates/powershell.py @@ -0,0 +1,21 @@ +from copy import copy + +from envs.monkey_zoo.blackbox.config_templates.base_template import BaseTemplate +from envs.monkey_zoo.blackbox.config_templates.config_template import ConfigTemplate + + +class PowerShell(ConfigTemplate): + config_values = copy(BaseTemplate.config_values) + + config_values.update( + { + "basic.exploiters.exploiter_classes": ["PowerShellExploiter"], + "basic_network.scope.subnet_scan_list": ["10.2.3.45", "10.2.3.46"], + "basic.credentials.exploit_password_list": ["Passw0rd!"], + "basic_network.scope.depth": 2, + "basic.credentials.exploit_user_list": ["m0nk3y", "m0nk3y-user"], + "internal.classes.finger_classes": ["PingScanner"], + "internal.network.tcp_scanner.HTTP_PORTS": [], + "internal.network.tcp_scanner.tcp_target_ports": [], + } + ) diff --git a/envs/monkey_zoo/blackbox/gcp_test_machine_list.py b/envs/monkey_zoo/blackbox/gcp_test_machine_list.py index 43246ad24..86999ab6d 100644 --- a/envs/monkey_zoo/blackbox/gcp_test_machine_list.py +++ b/envs/monkey_zoo/blackbox/gcp_test_machine_list.py @@ -1,22 +1,28 @@ -GCP_TEST_MACHINE_LIST = [ - "sshkeys-11", - "sshkeys-12", - "elastic-4", - "elastic-5", - "hadoop-2", - "hadoop-3", - "mssql-16", - "mimikatz-14", - "mimikatz-15", - "struts2-23", - "struts2-24", - "tunneling-9", - "tunneling-10", - "tunneling-11", - "tunneling-12", - "weblogic-18", - "weblogic-19", - "shellshock-8", - "zerologon-25", - "drupal-28", -] +GCP_TEST_MACHINE_LIST = { + "europe-west3-a": [ + "sshkeys-11", + "sshkeys-12", + "elastic-4", + "elastic-5", + "hadoop-2", + "hadoop-3", + "mssql-16", + "mimikatz-14", + "mimikatz-15", + "struts2-23", + "struts2-24", + "tunneling-9", + "tunneling-10", + "tunneling-11", + "tunneling-12", + "weblogic-18", + "weblogic-19", + "shellshock-8", + "zerologon-25", + "drupal-28", + ], + "europe-west1-b": [ + "powershell-3-45", + "powershell-3-46", + ], +} diff --git a/envs/monkey_zoo/blackbox/start_all_gcp_machines.py b/envs/monkey_zoo/blackbox/start_all_gcp_machines.py index f31a072f9..c5e83671c 100755 --- a/envs/monkey_zoo/blackbox/start_all_gcp_machines.py +++ b/envs/monkey_zoo/blackbox/start_all_gcp_machines.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from gcp_test_machine_list import GCP_TEST_MACHINE_LIST -from utils.gcp_machine_handlers import GCPHandler +from utils.gcp_machine_handlers import initialize_gcp_client, start_machines -gcp_handler = GCPHandler() -gcp_handler.start_machines(" ".join(GCP_TEST_MACHINE_LIST)) +initialize_gcp_client() +start_machines(GCP_TEST_MACHINE_LIST) diff --git a/envs/monkey_zoo/blackbox/stop_all_gcp_machines.py b/envs/monkey_zoo/blackbox/stop_all_gcp_machines.py index 132191e94..d5a489a52 100755 --- a/envs/monkey_zoo/blackbox/stop_all_gcp_machines.py +++ b/envs/monkey_zoo/blackbox/stop_all_gcp_machines.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from gcp_test_machine_list import GCP_TEST_MACHINE_LIST -from utils.gcp_machine_handlers import GCPHandler +from utils.gcp_machine_handlers import initialize_gcp_client, stop_machines -gcp_handler = GCPHandler() -gcp_handler.stop_machines(" ".join(GCP_TEST_MACHINE_LIST)) +initialize_gcp_client() +stop_machines(GCP_TEST_MACHINE_LIST) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index 5cd67d7ec..221d783f6 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -13,6 +13,7 @@ from envs.monkey_zoo.blackbox.config_templates.elastic import Elastic from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop from envs.monkey_zoo.blackbox.config_templates.mssql import Mssql from envs.monkey_zoo.blackbox.config_templates.performance import Performance +from envs.monkey_zoo.blackbox.config_templates.powershell import PowerShell from envs.monkey_zoo.blackbox.config_templates.shellshock import ShellShock from envs.monkey_zoo.blackbox.config_templates.smb_mimikatz import SmbMimikatz from envs.monkey_zoo.blackbox.config_templates.smb_pth import SmbPth @@ -39,7 +40,11 @@ from envs.monkey_zoo.blackbox.tests.performance.report_generation_from_telemetri from envs.monkey_zoo.blackbox.tests.performance.telemetry_performance_test import ( TelemetryPerformanceTest, ) -from envs.monkey_zoo.blackbox.utils import gcp_machine_handlers +from envs.monkey_zoo.blackbox.utils.gcp_machine_handlers import ( + initialize_gcp_client, + start_machines, + stop_machines, +) from monkey_island.cc.services.mode.mode_enum import IslandModeEnum DEFAULT_TIMEOUT_SECONDS = 5 * 60 @@ -53,15 +58,15 @@ LOGGER = logging.getLogger(__name__) def GCPHandler(request, no_gcp): if not no_gcp: try: - GCPHandler = gcp_machine_handlers.GCPHandler() - GCPHandler.start_machines(" ".join(GCP_TEST_MACHINE_LIST)) + initialize_gcp_client() + start_machines(GCP_TEST_MACHINE_LIST) except Exception as e: LOGGER.error("GCP Handler failed to initialize: %s." % e) pytest.exit("Encountered an error while starting GCP machines. Stopping the tests.") wait_machine_bootup() def fin(): - GCPHandler.stop_machines(" ".join(GCP_TEST_MACHINE_LIST)) + stop_machines(GCP_TEST_MACHINE_LIST) request.addfinalizer(fin) @@ -156,6 +161,11 @@ class TestMonkeyBlackbox: def test_mssql_exploiter(self, island_client): TestMonkeyBlackbox.run_exploitation_test(island_client, Mssql, "MSSQL_exploiter") + def test_powershell_exploiter(self, island_client): + TestMonkeyBlackbox.run_exploitation_test( + island_client, PowerShell, "PowerShell_Remoting_exploiter" + ) + def test_smb_and_mimikatz_exploiters(self, island_client): TestMonkeyBlackbox.run_exploitation_test( island_client, SmbMimikatz, "SMB_exploiter_mimikatz" diff --git a/envs/monkey_zoo/blackbox/utils/config_generation_script.py b/envs/monkey_zoo/blackbox/utils/config_generation_script.py index b2c69acda..f38a48d39 100644 --- a/envs/monkey_zoo/blackbox/utils/config_generation_script.py +++ b/envs/monkey_zoo/blackbox/utils/config_generation_script.py @@ -8,6 +8,7 @@ from envs.monkey_zoo.blackbox.config_templates.elastic import Elastic from envs.monkey_zoo.blackbox.config_templates.hadoop import Hadoop from envs.monkey_zoo.blackbox.config_templates.mssql import Mssql from envs.monkey_zoo.blackbox.config_templates.performance import Performance +from envs.monkey_zoo.blackbox.config_templates.powershell import PowerShell from envs.monkey_zoo.blackbox.config_templates.shellshock import ShellShock from envs.monkey_zoo.blackbox.config_templates.smb_mimikatz import SmbMimikatz from envs.monkey_zoo.blackbox.config_templates.smb_pth import SmbPth @@ -40,6 +41,7 @@ CONFIG_TEMPLATES = [ Hadoop, Mssql, Performance, + PowerShell, ShellShock, SmbMimikatz, SmbPth, diff --git a/envs/monkey_zoo/blackbox/utils/gcp_machine_handlers.py b/envs/monkey_zoo/blackbox/utils/gcp_machine_handlers.py index c438e92f5..aa12bfe73 100644 --- a/envs/monkey_zoo/blackbox/utils/gcp_machine_handlers.py +++ b/envs/monkey_zoo/blackbox/utils/gcp_machine_handlers.py @@ -1,76 +1,82 @@ import logging import os import subprocess +from multiprocessing.dummy import Pool LOGGER = logging.getLogger(__name__) +AUTHENTICATION_COMMAND = "gcloud auth activate-service-account --key-file=%s" +SET_PROPERTY_PROJECT = "gcloud config set project %s" +MACHINE_STARTING_COMMAND = "gcloud compute instances start %s --zone=%s" +MACHINE_STOPPING_COMMAND = "gcloud compute instances stop %s --zone=%s" -class GCPHandler(object): - AUTHENTICATION_COMMAND = "gcloud auth activate-service-account --key-file=%s" - SET_PROPERTY_PROJECT = "gcloud config set project %s" - MACHINE_STARTING_COMMAND = "gcloud compute instances start %s --zone=%s" - MACHINE_STOPPING_COMMAND = "gcloud compute instances stop %s --zone=%s" +# Key path location relative to this file's directory +RELATIVE_KEY_PATH = "../../gcp_keys/gcp_key.json" +DEFAULT_PROJECT = "guardicore-22050661" - # Key path location relative to this file's directory - RELATIVE_KEY_PATH = "../../gcp_keys/gcp_key.json" - DEFAULT_ZONE = "europe-west3-a" - DEFAULT_PROJECT = "guardicore-22050661" - def __init__( - self, - zone=DEFAULT_ZONE, - project_id=DEFAULT_PROJECT, - ): - self.zone = zone - abs_key_path = GCPHandler.get_absolute_key_path() +def initialize_gcp_client(): + abs_key_path = get_absolute_key_path() - subprocess.call(GCPHandler.get_auth_command(abs_key_path), shell=True) # noqa: DUO116 - LOGGER.info("GCP Handler passed key") + subprocess.call(get_auth_command(abs_key_path), shell=True) # noqa: DUO116 + LOGGER.info("GCP Handler passed key") - subprocess.call(GCPHandler.get_set_project_command(project_id), shell=True) # noqa: DUO116 - LOGGER.info("GCP Handler set project") - LOGGER.info("GCP Handler initialized successfully") + subprocess.call(get_set_project_command(DEFAULT_PROJECT), shell=True) # noqa: DUO116 + LOGGER.info("GCP Handler set project") + LOGGER.info("GCP Handler initialized successfully") - @staticmethod - def get_absolute_key_path() -> str: - file_dir = os.path.dirname(os.path.realpath(__file__)) - absolute_key_path = os.path.join(file_dir, GCPHandler.RELATIVE_KEY_PATH) - absolute_key_path = os.path.realpath(absolute_key_path) - if not os.path.isfile(absolute_key_path): - raise FileNotFoundError( - "GCP key not found. " "Add a service key to envs/monkey_zoo/gcp_keys/gcp_key.json" - ) - return absolute_key_path +def get_absolute_key_path() -> str: + file_dir = os.path.dirname(os.path.realpath(__file__)) + absolute_key_path = os.path.join(file_dir, RELATIVE_KEY_PATH) + absolute_key_path = os.path.realpath(absolute_key_path) - def start_machines(self, machine_list): - """ - Start all the machines in the list. - :param machine_list: A space-separated string with all the machine names. Example: - start_machines(`" ".join(["elastic-3", "mssql-16"])`) - """ - LOGGER.info("Setting up all GCP machines...") - try: - subprocess.call( # noqa: DUO116 - (GCPHandler.MACHINE_STARTING_COMMAND % (machine_list, self.zone)), shell=True - ) - LOGGER.info("GCP machines successfully started.") - except Exception as e: - LOGGER.error("GCP Handler failed to start GCP machines: %s" % e) + if not os.path.isfile(absolute_key_path): + raise FileNotFoundError( + "GCP key not found. " "Add a service key to envs/monkey_zoo/gcp_keys/gcp_key.json" + ) + return absolute_key_path - def stop_machines(self, machine_list): - try: - subprocess.call( # noqa: DUO116 - (GCPHandler.MACHINE_STOPPING_COMMAND % (machine_list, self.zone)), shell=True - ) - LOGGER.info("GCP machines stopped successfully.") - except Exception as e: - LOGGER.error("GCP Handler failed to stop network machines: %s" % e) - @staticmethod - def get_auth_command(key_path): - return GCPHandler.AUTHENTICATION_COMMAND % key_path +def start_machines(machine_list): + """ + Start all the machines in the list. + :param machine_list: A dictionary with zone and machines per zone. + """ + LOGGER.info("Setting up all GCP machines...") + try: + run_gcp_pool(MACHINE_STARTING_COMMAND, machine_list) + LOGGER.info("GCP machines successfully started.") + except Exception as e: + LOGGER.error("GCP Handler failed to start GCP machines: %s" % e) + + +def stop_machines(machine_list): + try: + run_gcp_pool(MACHINE_STOPPING_COMMAND, machine_list) + LOGGER.info("GCP machines stopped successfully.") + except Exception as e: + LOGGER.error("GCP Handler failed to stop network machines: %s" % e) + + +def get_auth_command(key_path): + return AUTHENTICATION_COMMAND % key_path + + +def get_set_project_command(project): + return SET_PROPERTY_PROJECT % project + + +def run_gcp_command(arglist): + gcp_cmd, machine_list, zone = arglist + subprocess.call( # noqa DUO116 + (gcp_cmd % (" ".join(machine_list), zone)), + shell=True, + ) + + +def run_gcp_pool(gcp_command, machine_list): + arglist = [(gcp_command, machine_list[zone], zone) for zone in machine_list] + with Pool(2) as pool: + pool.map(run_gcp_command, arglist) - @staticmethod - def get_set_project_command(project): - return GCPHandler.SET_PROPERTY_PROJECT % project diff --git a/envs/monkey_zoo/terraform/images.tf b/envs/monkey_zoo/terraform/images.tf index 866a4f174..3f293736d 100644 --- a/envs/monkey_zoo/terraform/images.tf +++ b/envs/monkey_zoo/terraform/images.tf @@ -57,6 +57,14 @@ data "google_compute_image" "mssql-16" { name = "mssql-16" project = local.monkeyzoo_project } +data "google_compute_image" "powershell-3-46" { + name = "powershell-3-46" + project = local.monkeyzoo_project +} +data "google_compute_image" "powershell-3-45" { + name = "powershell-3-45" + project = local.monkeyzoo_project +} data "google_compute_image" "weblogic-18" { name = "weblogic-18" project = local.monkeyzoo_project diff --git a/envs/monkey_zoo/terraform/monkey_zoo.tf b/envs/monkey_zoo/terraform/monkey_zoo.tf index 5eabc160b..241828557 100644 --- a/envs/monkey_zoo/terraform/monkey_zoo.tf +++ b/envs/monkey_zoo/terraform/monkey_zoo.tf @@ -26,6 +26,12 @@ resource "google_compute_subnetwork" "monkeyzoo-main" { network = google_compute_network.monkeyzoo.self_link } +resource "google_compute_subnetwork" "monkeyzoo-main-1" { + name = "${local.resource_prefix}monkeyzoo-main-1" + ip_cidr_range = "10.2.3.0/24" + network = google_compute_network.monkeyzoo.self_link +} + resource "google_compute_subnetwork" "tunneling-main" { name = "${local.resource_prefix}tunneling-main" ip_cidr_range = "10.2.1.0/28" @@ -307,6 +313,36 @@ resource "google_compute_instance_from_template" "mssql-16" { } } +resource "google_compute_instance_from_template" "powershell-3-46" { + name = "${local.resource_prefix}powershell-3-46" + source_instance_template = local.default_windows + boot_disk{ + initialize_params { + image = data.google_compute_image.powershell-3-46.self_link + } + auto_delete = true + } + network_interface { + subnetwork="${local.resource_prefix}monkeyzoo-main-1" + network_ip="10.2.3.46" + } +} + +resource "google_compute_instance_from_template" "powershell-3-45" { + name = "${local.resource_prefix}powershell-3-45" + source_instance_template = local.default_windows + boot_disk{ + initialize_params { + image = data.google_compute_image.powershell-3-45.self_link + } + auto_delete = true + } + network_interface { + subnetwork="${local.resource_prefix}monkeyzoo-main" + network_ip="10.2.3.45" + } +} + /* 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 = "${local.resource_prefix}upgrader-17" diff --git a/vulture_allowlist.py b/vulture_allowlist.py index b39d61dd8..e1454d876 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -196,3 +196,4 @@ environment # unused variable (monkey/monkey_island/cc/models/monkey.py:59) _.environment # unused attribute (monkey/monkey_island/cc/services/telemetry/processing/system_info_collectors/environment.py:10) _.instance_name # unused attribute (monkey/common/cloud/azure/azure_instance.py:35) _.instance_name # unused attribute (monkey/common/cloud/azure/azure_instance.py:64) +GCPHandler # unused function (envs/monkey_zoo/blackbox/test_blackbox.py:57)