From c83285c782830edec03c49be8024a56073087c3a Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Fri, 18 Feb 2022 20:05:03 +0100 Subject: [PATCH] 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": {}}, ], }