diff --git a/infection_monkey/config.py b/infection_monkey/config.py index 404dc194e..b9c3c8595 100644 --- a/infection_monkey/config.py +++ b/infection_monkey/config.py @@ -6,7 +6,7 @@ import uuid from abc import ABCMeta from itertools import product -from exploit import WmiExploiter, SmbExploiter, SSHExploiter, ShellShockExploiter, \ +from exploit import WmiExploiter, Ms08_067_Exploiter, SmbExploiter, RdpExploiter, SSHExploiter, ShellShockExploiter, \ SambaCryExploiter, ElasticGroovyExploiter from network import TcpScanner, PingScanner, SMBFinger, SSHFinger, HTTPFinger, MySQLFinger, ElasticFinger from network.range import FixedRange diff --git a/infection_monkey/control.py b/infection_monkey/control.py index 12f0cb754..0a32aa8b9 100644 --- a/infection_monkey/control.py +++ b/infection_monkey/control.py @@ -4,6 +4,7 @@ import platform from socket import gethostname import requests +from requests.exceptions import ConnectionError import monkeyfs import tunnel @@ -59,9 +60,11 @@ class ControlClient(object): if default_tunnel: LOG.debug("default_tunnel: %s" % (default_tunnel,)) + current_server = "" + for server in WormConfiguration.command_servers: try: - WormConfiguration.current_server = server + current_server = server debug_message = "Trying to connect to server: %s" % server if ControlClient.proxies: @@ -70,23 +73,29 @@ class ControlClient(object): requests.get("https://%s/api?action=is-up" % (server,), verify=False, proxies=ControlClient.proxies) + WormConfiguration.current_server = current_server break - except Exception as exc: - WormConfiguration.current_server = "" + except ConnectionError as exc: + current_server = "" LOG.warn("Error connecting to control server %s: %s", server, exc) - if not WormConfiguration.current_server: - if not ControlClient.proxies: + if current_server: + return True + else: + if ControlClient.proxies: + return False + else: LOG.info("Starting tunnel lookup...") proxy_find = tunnel.find_tunnel(default=default_tunnel) if proxy_find: proxy_address, proxy_port = proxy_find LOG.info("Found tunnel at %s:%s" % (proxy_address, proxy_port)) ControlClient.proxies['https'] = 'https://%s:%s' % (proxy_address, proxy_port) - ControlClient.find_server() + return ControlClient.find_server() else: LOG.info("No tunnel found") + return False @staticmethod def keepalive(): diff --git a/infection_monkey/dropper.py b/infection_monkey/dropper.py index 927ea7cf6..1e6bf2048 100644 --- a/infection_monkey/dropper.py +++ b/infection_monkey/dropper.py @@ -38,7 +38,7 @@ class MonkeyDrops(object): arg_parser.add_argument('-p', '--parent') arg_parser.add_argument('-t', '--tunnel') arg_parser.add_argument('-s', '--server') - arg_parser.add_argument('-d', '--depth') + arg_parser.add_argument('-d', '--depth', type=int) arg_parser.add_argument('-l', '--location') self.monkey_args = args[1:] self.opts, _ = arg_parser.parse_known_args(args) @@ -56,7 +56,7 @@ class MonkeyDrops(object): return # we copy/move only in case path is different - file_moved = (self._config['source_path'].lower() == self._config['destination_path'].lower()) + file_moved = os.path.samefile(self._config['source_path'], self._config['destination_path']) if not file_moved and os.path.exists(self._config['destination_path']): os.remove(self._config['destination_path']) @@ -108,9 +108,8 @@ class MonkeyDrops(object): except: LOG.warn("Cannot set reference date to destination file") - depth = int(self.opts.depth) if self.opts.depth is not None else None - monkey_options = build_monkey_commandline_explicitly( - self.opts.parent, self.opts.tunnel, self.opts.server, depth) + monkey_options =\ + build_monkey_commandline_explicitly(self.opts.parent, self.opts.tunnel, self.opts.server, self.opts.depth) if OperatingSystem.Windows == SystemInfoCollector.get_os(): monkey_cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': self._config['destination_path']} + monkey_options diff --git a/infection_monkey/monkey.py b/infection_monkey/monkey.py index 1065cf257..e9794355d 100644 --- a/infection_monkey/monkey.py +++ b/infection_monkey/monkey.py @@ -48,14 +48,13 @@ class InfectionMonkey(object): arg_parser.add_argument('-p', '--parent') arg_parser.add_argument('-t', '--tunnel') arg_parser.add_argument('-s', '--server') - arg_parser.add_argument('-d', '--depth') + arg_parser.add_argument('-d', '--depth', type=int) self._opts, self._args = arg_parser.parse_known_args(self._args) self._parent = self._opts.parent self._default_tunnel = self._opts.tunnel self._default_server = self._opts.server if self._opts.depth: - WormConfiguration.depth = int(self._opts.depth) WormConfiguration._depth_from_commandline = True self._keep_running = True self._network = NetworkScanner() @@ -71,9 +70,9 @@ class InfectionMonkey(object): def start(self): LOG.info("Monkey is running...") - if firewall.is_enabled(): - firewall.add_firewall_rule() - ControlClient.find_server(default_tunnel=self._default_tunnel) + if not ControlClient.find_server(default_tunnel=self._default_tunnel): + LOG.info("Monkey couldn't find server. Going down.") + return if WindowsUpgrader.should_upgrade(): self._upgrading_to_64 = True @@ -89,6 +88,9 @@ class InfectionMonkey(object): LOG.info("Marked not alive from configuration") return + if firewall.is_enabled(): + firewall.add_firewall_rule() + monkey_tunnel = ControlClient.create_control_tunnel() if monkey_tunnel: monkey_tunnel.start() @@ -227,21 +229,27 @@ class InfectionMonkey(object): LOG.info("Monkey cleanup started") self._keep_running = False - # Signal the server (before closing the tunnel) - if not self._upgrading_to_64: - ControlClient.send_telemetry("state", {'done': True}) + if self._upgrading_to_64: + InfectionMonkey.close_tunnel() + firewall.close() + else: + ControlClient.send_telemetry("state", {'done': True}) # Signal the server (before closing the tunnel) + InfectionMonkey.close_tunnel() + firewall.close() + self._singleton.unlock() - # Close tunnel + InfectionMonkey.self_delete() + LOG.info("Monkey is shutting down") + + @staticmethod + def close_tunnel(): tunnel_address = ControlClient.proxies.get('https', '').replace('https://', '').split(':')[0] if tunnel_address: LOG.info("Quitting tunnel %s", tunnel_address) tunnel.quit_tunnel(tunnel_address) - firewall.close() - - if not self._upgrading_to_64: - self._singleton.unlock() - + @staticmethod + def self_delete(): if WormConfiguration.self_delete_in_cleanup \ and -1 == sys.executable.find('python'): try: @@ -257,5 +265,3 @@ class InfectionMonkey(object): os.remove(sys.executable) except Exception as exc: LOG.error("Exception in self delete: %s", exc) - - LOG.info("Monkey is shutting down") diff --git a/infection_monkey/windows_upgrader.py b/infection_monkey/windows_upgrader.py index c63b64524..996e2a856 100644 --- a/infection_monkey/windows_upgrader.py +++ b/infection_monkey/windows_upgrader.py @@ -3,6 +3,7 @@ import os import struct import subprocess import sys +import shutil import time @@ -23,9 +24,11 @@ else: class WindowsUpgrader(object): + __UPGRADE_WAIT_TIME__ = 3 + @staticmethod def is_64bit_os(): - return os.environ.has_key('PROGRAMFILES(X86)') + return 'PROGRAMFILES(X86)' in os.environ @staticmethod def is_64bit_python(): @@ -44,13 +47,10 @@ class WindowsUpgrader(object): def upgrade(opts): monkey_64_path = ControlClient.download_monkey_exe_by_os(True, False) with monkeyfs.open(monkey_64_path, "rb") as downloaded_monkey_file: - monkey_bin = downloaded_monkey_file.read() - with open(WormConfiguration.dropper_target_path_win_64, 'wb') as written_monkey_file: - written_monkey_file.write(monkey_bin) + with open(WormConfiguration.dropper_target_path_win_64, 'wb') as written_monkey_file: + shutil.copyfileobj(downloaded_monkey_file, written_monkey_file) - depth = int(opts.depth) if opts.depth is not None else None - monkey_options = build_monkey_commandline_explicitly( - opts.parent, opts.tunnel, opts.server, depth) + monkey_options = build_monkey_commandline_explicitly(opts.parent, opts.tunnel, opts.server, opts.depth) monkey_cmdline = MONKEY_CMDLINE_WINDOWS % { 'monkey_path': WormConfiguration.dropper_target_path_win_64} + monkey_options @@ -62,6 +62,6 @@ class WindowsUpgrader(object): LOG.info("Executed 64bit monkey process (PID=%d) with command line: %s", monkey_process.pid, monkey_cmdline) - time.sleep(3) + time.sleep(WindowsUpgrader.__UPGRADE_WAIT_TIME__) if monkey_process.poll() is not None: - LOG.warn("Seems like monkey died too soon") + LOG.error("Seems like monkey died too soon") diff --git a/monkey_island/cc/services/config.py b/monkey_island/cc/services/config.py index 3001ed768..82e536c24 100644 --- a/monkey_island/cc/services/config.py +++ b/monkey_island/cc/services/config.py @@ -444,13 +444,15 @@ SCHEMA = { "title": "Dropper target path on Windows (32bit)", "type": "string", "default": "C:\\Windows\\monkey32.exe", - "description": "Determines where should the dropper place the monkey on a Windows machine" + "description": "Determines where should the dropper place the monkey on a Windows machine " + "(32bit)" }, "dropper_target_path_win_64": { "title": "Dropper target path on Windows (64bit)", "type": "string", "default": "C:\\Windows\\monkey64.exe", - "description": "Determines where should the dropper place the monkey on a Windows machine" + "description": "Determines where should the dropper place the monkey on a Windows machine " + "(64 bit)" }, "dropper_try_move_first": { "title": "Try to move first",