def handle(self): ip, port = self.client_address self.connect_time = datetime.datetime.now() self.storagepath = self.server.build_storage_path(ip) if not self.storagepath: return task, _ = self.server.get_ctx_for_ip(ip) task_log_start(task.id) # Create all missing folders for this analysis. self.create_folders() try: # Initialize the protocol handler class for this connection. self.negotiate_protocol() for event in self.protocol: if isinstance(self.protocol, BsonParser) and event["type"] == "process": self.open_process_log(event) except CuckooResultError as e: log.warning( "ResultServer connection stopping because of " "CuckooResultError: %s.", e ) except (Disconnect, socket.error): pass except: log.exception("FIXME - exception in resultserver connection %s", self.client_address) task_log_stop(task.id)
def handle(self): ip, port = self.client_address self.connect_time = datetime.datetime.now() self.storagepath = self.server.build_storage_path(ip) if not self.storagepath: return task, _ = self.server.get_ctx_for_ip(ip) task_log_start(task.id) # Create all missing folders for this analysis. self.create_folders() try: # Initialize the protocol handler class for this connection. self.negotiate_protocol() for event in self.protocol: if isinstance(self.protocol, BsonParser) and event["type"] == "process": self.open_process_log(event) except CuckooResultError as e: log.warning( "ResultServer connection stopping because of " "CuckooResultError: %s.", e) except (Disconnect, socket.error): pass except: log.exception("FIXME - exception in resultserver connection %s", self.client_address) task_log_stop(task.id)
def handle(self, sock, addr): """Handle the incoming connection. Gevent will close the socket when the function returns.""" ipaddr = addr[0] with self.task_mgmt_lock: task_id = self.tasks.get(ipaddr) if not task_id: log.warning("ResultServer did not have a task for IP %s", ipaddr) return self.storagepath = os.path.join(CUCKOO_ROOT, "storage", "analyses", str(task_id)) # Create all missing folders for this analysis. self.create_folders() ctx = HandlerContext(task_id, self.storagepath, sock) task_log_start(task_id) try: try: protocol = self.negotiate_protocol(task_id, ctx) except EOFError: return # Registering the context allows us to abort the handler by # shutting down its socket when the task is deleted; this should # prevent lingering sockets with self.task_mgmt_lock: # NOTE: the task may have been cancelled during the negotation # protocol and a different task for that IP address may have # been registered if self.tasks.get(ipaddr) != task_id: log.warning( "Task #%s for IP %s was cancelled during " "negotiation", task_id, ipaddr) return s = self.handlers.setdefault(task_id, set()) s.add(ctx) try: with protocol: protocol.handle() except CuckooOperationalError as e: log.error(e) finally: with self.task_mgmt_lock: s.discard(ctx) ctx.cancel() if ctx.buf: # This is usually not a good sign log.warning( "Task #%s with protocol %s has unprocessed " "data before getting disconnected", task_id, protocol) finally: task_log_stop(task_id)
def launch_analysis(self): """Start analysis.""" succeeded = False target = self.task.target if self.task.category == "file": target = os.path.basename(target) log.info("Starting analysis of %s \"%s\" (task #%d, options \"%s\")", self.task.category.upper(), target, self.task.id, emit_options(self.task.options)) # Initialize the analysis folders. if not self.init_storage(): return False # Initiates per-task logging. task_log_start(self.task.id) self.store_task_info() if self.task.category == "file": # Check if we have permissions to access the file. # And fail this analysis if we don't have access to the file. if not self.check_permissions(): return False # Check whether the file has been changed for some unknown reason. # And fail this analysis if it has been modified. if not self.check_file(): return False # Store a copy of the original file. if not self.store_file(): return False # Acquire analysis machine. try: self.acquire_machine() except CuckooOperationalError as e: machine_lock.release() log.error("Cannot acquire machine: {0}".format(e)) return False # At this point we can tell the ResultServer about it. try: ResultServer().add_task(self.task, self.machine) except Exception as e: machinery.release(self.machine.label) self.errors.put(e) # Initialize the guest manager. self.guest_manager = GuestManager( self.machine.name, self.machine.ip, self.machine.platform, self.task.id, self ) self.aux = RunAuxiliary(self.task, self.machine, self.guest_manager) self.aux.start() # Generate the analysis configuration file. options = self.build_options() try: unlocked = False self.interface = None # Mark the selected analysis machine in the database as started. guest_log = self.db.guest_start(self.task.id, self.machine.name, self.machine.label, machinery.__class__.__name__) # Start the machine. machinery.start(self.machine.label, self.task) # Enable network routing. self.route_network() # By the time start returns it will have fully started the Virtual # Machine. We can now safely release the machine lock. machine_lock.release() unlocked = True # Run and manage the components inside the guest unless this # machine has the "noagent" option specified (please refer to the # wait_finish() function for more details on this function). if "noagent" not in self.machine.options: self.guest_manage(options) else: self.wait_finish() succeeded = True except CuckooMachineError as e: if not unlocked: machine_lock.release() log.error( "Machinery error: %s", e, extra={"task_id": self.task.id} ) log.critical( "A critical error has occurred trying to use the machine " "with name %s during an analysis due to which it is no " "longer in a working state, please report this issue and all " "of the related environment details to the developers so we " "can improve this situation. (Note that before we would " "simply remove this VM from doing any more analyses, but as " "all the VMs will eventually be depleted that way, hopefully " "we'll find a better solution now).", self.machine.name, ) except CuckooGuestError as e: if not unlocked: machine_lock.release() log.error( "Error from the Cuckoo Guest: %s", e, extra={"task_id": self.task.id} ) finally: # Stop Auxiliary modules. self.aux.stop() # Take a memory dump of the machine before shutting it off. if self.cfg.cuckoo.memory_dump or self.task.memory: try: dump_path = os.path.join(self.storage, "memory.dmp") machinery.dump_memory(self.machine.label, dump_path) except NotImplementedError: log.error("The memory dump functionality is not available " "for the current machine manager.") except CuckooMachineError as e: log.error("Machinery error: %s", e) try: # Stop the analysis machine. machinery.stop(self.machine.label) except CuckooMachineError as e: log.warning("Unable to stop machine %s: %s", self.machine.label, e) # Mark the machine in the database as stopped. Unless this machine # has been marked as dead, we just keep it as "started" in the # database so it'll not be used later on in this session. self.db.guest_stop(guest_log) # After all this, we can make the ResultServer forget about the # internal state for this analysis task. ResultServer().del_task(self.task, self.machine) # Drop the network routing rules if any. self.unroute_network() try: # Release the analysis machine. But only if the machine has # not turned dead yet. machinery.release(self.machine.label) except CuckooMachineError as e: log.error("Unable to release machine %s, reason %s. " "You might need to restore it manually.", self.machine.label, e) return succeeded
def launch_analysis(self): """Start analysis.""" succeeded = False target = self.task.target if self.task.category == "file": target = os.path.basename(target) log.info("Starting analysis of %s \"%s\" (task #%d, options \"%s\")", self.task.category.upper(), target, self.task.id, emit_options(self.task.options)) # Initialize the analysis folders. if not self.init_storage(): return False # Initiates per-task logging. task_log_start(self.task.id) self.store_task_info() if self.task.category == "file": # Check if we have permissions to access the file. # And fail this analysis if we don't have access to the file. if not self.check_permissions(): return False # Check whether the file has been changed for some unknown reason. # And fail this analysis if it has been modified. if not self.check_file(): return False # Store a copy of the original file. if not self.store_file(): return False # Acquire analysis machine. try: self.acquire_machine() except CuckooOperationalError as e: machine_lock.release() log.error("Cannot acquire machine: {0}".format(e)) return False # At this point we can tell the ResultServer about it. try: ResultServer().add_task(self.task, self.machine) except Exception as e: machinery.release(self.machine.label) self.errors.put(e) # Initialize the guest manager. self.guest_manager = GuestManager(self.machine.name, self.machine.ip, self.machine.platform, self.task.id, self) self.aux = RunAuxiliary(self.task, self.machine, self.guest_manager) self.aux.start() # Generate the analysis configuration file. options = self.build_options() try: unlocked = False self.interface = None # Mark the selected analysis machine in the database as started. guest_log = self.db.guest_start(self.task.id, self.machine.name, self.machine.label, machinery.__class__.__name__) # Start the machine. machinery.start(self.machine.label, self.task) # Enable network routing. self.route_network() # By the time start returns it will have fully started the Virtual # Machine. We can now safely release the machine lock. machine_lock.release() unlocked = True # Run and manage the components inside the guest unless this # machine has the "noagent" option specified (please refer to the # wait_finish() function for more details on this function). if "noagent" not in self.machine.options: self.guest_manage(options) else: self.wait_finish() succeeded = True except CuckooMachineError as e: if not unlocked: machine_lock.release() log.error("Machinery error: %s", e, extra={"task_id": self.task.id}) log.critical( "A critical error has occurred trying to use the machine " "with name %s during an analysis due to which it is no " "longer in a working state, please report this issue and all " "of the related environment details to the developers so we " "can improve this situation. (Note that before we would " "simply remove this VM from doing any more analyses, but as " "all the VMs will eventually be depleted that way, hopefully " "we'll find a better solution now).", self.machine.name, ) except CuckooGuestError as e: if not unlocked: machine_lock.release() log.error("Error from the Cuckoo Guest: %s", e, extra={"task_id": self.task.id}) finally: # Stop Auxiliary modules. self.aux.stop() # Take a memory dump of the machine before shutting it off. if self.cfg.cuckoo.memory_dump or self.task.memory: try: dump_path = os.path.join(self.storage, "memory.dmp") machinery.dump_memory(self.machine.label, dump_path) except NotImplementedError: log.error("The memory dump functionality is not available " "for the current machine manager.") except CuckooMachineError as e: log.error("Machinery error: %s", e) try: # Stop the analysis machine. machinery.stop(self.machine.label) except CuckooMachineError as e: log.warning("Unable to stop machine %s: %s", self.machine.label, e) # Mark the machine in the database as stopped. Unless this machine # has been marked as dead, we just keep it as "started" in the # database so it'll not be used later on in this session. self.db.guest_stop(guest_log) # After all this, we can make the ResultServer forget about the # internal state for this analysis task. ResultServer().del_task(self.task, self.machine) # Drop the network routing rules if any. self.unroute_network() try: # Release the analysis machine. But only if the machine has # not turned dead yet. machinery.release(self.machine.label) except CuckooMachineError as e: log.error( "Unable to release machine %s, reason %s. " "You might need to restore it manually.", self.machine.label, e) return succeeded