From cecf131528b543c4a024374d77315fa08b3c3dbf Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 18 Feb 2022 20:04:24 +0100 Subject: [PATCH 1/2] Island: Modify config to add exploiters and exploit options --- monkey/monkey_island/cc/services/config.py | 17 +++++++++-- .../monkey_island/cc/services/test_config.py | 29 +++++++++++-------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 6cb895ead..19a2a4497 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -602,7 +602,20 @@ class ConfigService: "WmiExploiter", } - formatted_exploiters_config = {"brute_force": [], "vulnerability": []} + exploit_options = {} + + for dropper_target in [ + "dropper_target_path_linux", + "dropper_target_path_win_32", + "dropper_target_path_win_64", + ]: + exploit_options[dropper_target] = config.get(dropper_target, "") + + formatted_exploiters_config = { + "options": exploit_options, + "brute_force": [], + "vulnerability": [], + } for exploiter in sorted(config[flat_config_exploiter_classes_field]): category = ( @@ -611,7 +624,7 @@ class ConfigService: else vulnerability_category ) - formatted_exploiters_config[category].append({"name": exploiter}) + formatted_exploiters_config[category].append({"name": exploiter, "options": {}}) config.pop(flat_config_exploiter_classes_field, None) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py b/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py index 60dd4e464..9bc86bb7f 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py @@ -171,21 +171,26 @@ def test_format_config_for_agent__network_scan(flat_monkey_config): def test_format_config_for_agent__exploiters(flat_monkey_config): expected_exploiters_config = { + "options": { + "dropper_target_path_linux": "/tmp/monkey", + "dropper_target_path_win_32": r"C:\Windows\temp\monkey32.exe", + "dropper_target_path_win_64": r"C:\Windows\temp\monkey64.exe", + }, "brute_force": [ - {"name": "MSSQLExploiter"}, - {"name": "PowerShellExploiter"}, - {"name": "SSHExploiter"}, - {"name": "SmbExploiter"}, - {"name": "WmiExploiter"}, + {"name": "MSSQLExploiter", "options": {}}, + {"name": "PowerShellExploiter", "options": {}}, + {"name": "SSHExploiter", "options": {}}, + {"name": "SmbExploiter", "options": {}}, + {"name": "WmiExploiter", "options": {}}, ], "vulnerability": [ - {"name": "DrupalExploiter"}, - {"name": "ElasticGroovyExploiter"}, - {"name": "HadoopExploiter"}, - {"name": "ShellShockExploiter"}, - {"name": "Struts2Exploiter"}, - {"name": "WebLogicExploiter"}, - {"name": "ZerologonExploiter"}, + {"name": "DrupalExploiter", "options": {}}, + {"name": "ElasticGroovyExploiter", "options": {}}, + {"name": "HadoopExploiter", "options": {}}, + {"name": "ShellShockExploiter", "options": {}}, + {"name": "Struts2Exploiter", "options": {}}, + {"name": "WebLogicExploiter", "options": {}}, + {"name": "ZerologonExploiter", "options": {}}, ], } ConfigService.format_flat_config_for_agent(flat_monkey_config) From c83285c782830edec03c49be8024a56073087c3a Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 18 Feb 2022 20:05:03 +0100 Subject: [PATCH 2/2] Agent: Modify exploiters to have general and exploiter options --- monkey/infection_monkey/master/exploiter.py | 32 +++++++++++++++---- .../infection_monkey/master/test_exploiter.py | 7 ++-- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/monkey/infection_monkey/master/exploiter.py b/monkey/infection_monkey/master/exploiter.py index 4355ecc16..8405fb6e8 100644 --- a/monkey/infection_monkey/master/exploiter.py +++ b/monkey/infection_monkey/master/exploiter.py @@ -1,6 +1,8 @@ import logging import queue import threading +from copy import deepcopy +from itertools import chain from queue import Queue from threading import Event from typing import Callable, Dict, List, Mapping @@ -36,12 +38,10 @@ class Exploiter: scan_completed: Event, stop: Event, ): - # Run vulnerability exploiters before brute force exploiters to minimize the effect of - # account lockout due to invalid credentials - exploiters_to_run = exploiter_config["vulnerability"] + exploiter_config["brute_force"] + exploiters_to_run = self._process_exploiter_config(exploiter_config) logger.debug( "Agent is configured to run the following exploiters in order: " - f"{','.join([e['name'] for e in exploiters_to_run])}" + f"{', '.join([e['name'] for e in exploiters_to_run])}" ) exploit_args = (exploiters_to_run, hosts_to_exploit, results_callback, scan_completed, stop) @@ -49,6 +49,22 @@ class Exploiter: target=self._exploit_hosts_on_queue, args=exploit_args, num_workers=self._num_workers ) + @staticmethod + def _process_exploiter_config(exploiter_config: Mapping) -> List[Mapping]: + # Run vulnerability exploiters before brute force exploiters to minimize the effect of + # account lockout due to invalid credentials + ordered_exploiters = chain( + exploiter_config["vulnerability"], exploiter_config["brute_force"] + ) + exploiters_to_run = list(deepcopy(ordered_exploiters)) + + for exploiter in exploiters_to_run: + # This order allows exploiter-specific options to + # override general options for all exploiters. + exploiter["options"] = {**exploiter_config["options"], **exploiter["options"]} + + return exploiters_to_run + def _exploit_hosts_on_queue( self, exploiters_to_run: List[Dict], @@ -83,19 +99,21 @@ class Exploiter: for exploiter in interruptable_iter(exploiters_to_run, stop): exploiter_name = exploiter["name"] - exploiter_results = self._run_exploiter(exploiter_name, victim_host, stop) + exploiter_results = self._run_exploiter( + exploiter_name, exploiter["options"], victim_host, stop + ) results_callback(exploiter_name, victim_host, exploiter_results) if exploiter_name != "ZerologonExploiter" and exploiter_results.success: break def _run_exploiter( - self, exploiter_name: str, victim_host: VictimHost, stop: Event + self, exploiter_name: str, options: Dict, victim_host: VictimHost, stop: Event ) -> ExploiterResultData: logger.debug(f"Attempting to use {exploiter_name} on {victim_host}") credentials = self._get_credentials_for_propagation() - options = {"credentials": credentials} + options = {"credentials": credentials, **options} return self._puppet.exploit_host(exploiter_name, victim_host.ip_addr, options, stop) diff --git a/monkey/tests/unit_tests/infection_monkey/master/test_exploiter.py b/monkey/tests/unit_tests/infection_monkey/master/test_exploiter.py index aaf30dc2d..9a276e9aa 100644 --- a/monkey/tests/unit_tests/infection_monkey/master/test_exploiter.py +++ b/monkey/tests/unit_tests/infection_monkey/master/test_exploiter.py @@ -35,12 +35,13 @@ def callback(): @pytest.fixture def exploiter_config(): return { + "options": {"dropper_path_linux": "/tmp/monkey"}, "brute_force": [ - {"name": "PowerShellExploiter"}, - {"name": "SSHExploiter"}, + {"name": "PowerShellExploiter", "options": {"timeout": 10}}, + {"name": "SSHExploiter", "options": {}}, ], "vulnerability": [ - {"name": "ZerologonExploiter"}, + {"name": "ZerologonExploiter", "options": {}}, ], }