def stop(self): """Stop sniffing. @return: operation status. """ # The tcpdump process was never started in the first place. if not self.proc: return # The tcpdump process has already quit, generally speaking this # indicates an error such as "permission denied". if self.proc.poll(): out, err = self.proc.communicate() raise CuckooOperationalError( "Error running tcpdump to sniff the network traffic during " "the analysis; stdout = %r and stderr = %r. Did you enable " "the extra capabilities to allow running tcpdump as non-root " "user and disable AppArmor properly (the latter only applies " "to Ubuntu-based distributions with AppArmor, see also %s)?" % (out, err, faq("permission-denied-for-tcpdump")) ) try: self.proc.terminate() except: try: if not self.proc.poll(): log.debug("Killing sniffer") self.proc.kill() except OSError as e: log.debug("Error killing sniffer: %s. Continue", e) except Exception as e: log.exception("Unable to stop the sniffer with pid %d: %s", self.proc.pid, e) # Ensure expected output was received from tcpdump. out, err = self.proc.communicate() self._check_output(out, err)
def run(self): """Run debug analysis. @return: debug information dict. """ self.key = "debug" debug = { "log": [], "cuckoo": [], "action": [], "dbgview": [], "errors": [], } if os.path.exists(self.log_path): try: f = codecs.open(self.log_path, "rb", "utf-8") debug["log"] = f.readlines() except ValueError as e: raise CuckooProcessingError("Error decoding %s: %s" % (self.log_path, e)) except (IOError, OSError) as e: raise CuckooProcessingError("Error opening %s: %s" % (self.log_path, e)) else: log.error( "Error processing task #%d: it appears that the Virtual " "Machine (%s) hasn't been able to contact back to " "the Cuckoo Host. There could be a few reasons for this, " "please refer to our documentation on the matter: %s", self.task.id, self.machine.get("name"), faq("troubleshooting-vm-network-configuration"), extra={ "error_action": "vmrouting", "action": "guest.communication", "status": "error", "task_id": self.task.id, }) if os.path.exists(self.cuckoolog_path): debug["cuckoo"] = Logfile(self.cuckoolog_path) dbgview_log = os.path.join(self.analysis_path, "logs", "dbgview.log") if os.path.exists(dbgview_log): f = open(dbgview_log, "rb") # Ignore the first line which identifies the machine. f.readline() for line in f: idx, time, message = line.split("\t", 2) debug["dbgview"].append(message.strip()) debug["errors"] = [] for error in Database().view_errors(self.task["id"]): if error.message and error.message not in debug["errors"]: debug["errors"].append(error.message) if error.action and error.action not in debug["action"]: debug["action"].append(error.action) if os.path.exists(self.mitmerr_path): mitmerr = open(self.mitmerr_path, "rb").read() if mitmerr and mitmerr not in debug["errors"]: debug["errors"].append(mitmerr) return debug
def launch_analysis(self): """Start analysis.""" succeeded = False if self.task.category == "file" or self.task.category == "archive": target = os.path.basename(self.task.target) else: target = self.task.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), extra={ "action": "task.init", "status": "starting", "task_id": self.task.id, "target": target, "category": self.task.category, "package": self.task.package, "options": emit_options(self.task.options), "custom": self.task.custom, }) # Initialize the analysis. if not self.init(): logger("Failed to initialize", action="task.init", status="error") return False # Acquire analysis machine. try: self.acquire_machine() except CuckooOperationalError as e: machine_lock.release() log.error("Cannot acquire machine: %s", e, extra={ "action": "vm.acquire", "status": "error", }) return False self.rs_port = self.machine.resultserver_port or ResultServer().port # 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() # Check if the current task has remotecontrol # enabled before starting the machine. control_enabled = (config("cuckoo:remotecontrol:enabled") and "remotecontrol" in self.task.options) if control_enabled: try: machinery.enable_remote_control(self.machine.label) except NotImplementedError: log.error( "Remote control support has not been implemented for the " "configured machinery module: %s", config("cuckoo:cuckoo:machinery")) 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__) logger("Starting VM", action="vm.start", status="pending", vmname=self.machine.name) # Start the machine. machinery.start(self.machine.label, self.task) logger("Started VM", action="vm.start", status="success", vmname=self.machine.name) # retrieve the port used for remote control if control_enabled: try: params = machinery.get_remote_control_params( self.machine.label) self.db.set_machine_rcparams(self.machine.label, params) except NotImplementedError: log.error( "Remote control support has not been implemented for the " "configured machinery module: %s", config("cuckoo:cuckoo:machinery")) # 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 CuckooMachineSnapshotError as e: log.error( "Unable to restore to the snapshot for this Virtual Machine! " "Does your VM have a proper Snapshot and can you revert to it " "manually? VM: %s, error: %s", self.machine.name, e, extra={ "action": "vm.resume", "status": "error", "vmname": self.machine.name, }) except CuckooMachineError as e: if not unlocked: machine_lock.release() log.error("Error starting Virtual Machine! VM: %s, error: %s", self.machine.name, e, extra={ "action": "vm.start", "status": "error", "vmname": self.machine.name, }) except CuckooGuestCriticalTimeout as e: if not unlocked: machine_lock.release() log.error( "Error from machine '%s': it appears that this Virtual " "Machine hasn't been configured properly as the Cuckoo Host " "wasn't able to connect to the Guest. There could be a few " "reasons for this, please refer to our documentation on the " "matter: %s", self.machine.name, faq("troubleshooting-vm-network-configuration"), extra={ "error_action": "vmrouting", "action": "guest.handle", "status": "error", "task_id": self.task.id, }) except CuckooGuestError as e: if not unlocked: machine_lock.release() log.error("Error from the Cuckoo Guest: %s", e, extra={ "action": "guest.handle", "status": "error", "task_id": self.task.id, }) finally: # Stop Auxiliary modules. if not self.stopped_aux: self.stopped_aux = True self.aux.stop() # Take a memory dump of the machine before shutting it off. if self.cfg.cuckoo.memory_dump or self.task.memory: logger("Taking full memory dump", action="vm.memdump", status="pending", vmname=self.machine.name) try: dump_path = os.path.join(self.storage, "memory.dmp") machinery.dump_memory(self.machine.label, dump_path) logger("Taken full memory dump", action="vm.memdump", status="success", vmname=self.machine.name) except NotImplementedError: log.error( "The memory dump functionality is not available for " "the current machine manager.", extra={ "action": "vm.memdump", "status": "error", "vmname": self.machine.name, }) except CuckooMachineError as e: log.error("Machinery error: %s", e, extra={ "action": "vm.memdump", "status": "error", }) logger("Stopping VM", action="vm.stop", status="pending", vmname=self.machine.name) 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, extra={ "action": "vm.stop", "status": "error", "vmname": self.machine.name, }) logger("Stopped VM", action="vm.stop", status="success", vmname=self.machine.name) # Disable remote control after stopping the machine # if it was enabled for the task. if control_enabled: try: machinery.disable_remote_control(self.machine.label) except NotImplementedError: log.error( "Remote control support has not been implemented for the " "configured machinery module: %s", config("cuckoo:cuckoo:machinery")) # 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. if not self.unrouted_network: 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, extra={ "action": "vm.release", "status": "error", "vmname": self.machine.name, }) return succeeded
def run(self): """Run debug analysis. @return: debug information dict. """ self.key = "debug" debug = { "log": [], "cuckoo": [], "action": [], "dbgview": [], "errors": [], } if os.path.exists(self.log_path): try: f = codecs.open(self.log_path, "rb", "utf-8") debug["log"] = f.readlines() except ValueError as e: raise CuckooProcessingError( "Error decoding %s: %s" % (self.log_path, e) ) except (IOError, OSError) as e: raise CuckooProcessingError( "Error opening %s: %s" % (self.log_path, e) ) else: log.error( "Error processing task #%d: it appears that the Virtual " "Machine hasn't been able to contact back to " "the Cuckoo Host. There could be a few reasons for this, " "please refer to our documentation on the matter: %s", self.task.id, faq("troubleshooting-vm-network-configuration"), extra={ "error_action": "vmrouting", "action": "guest.communication", "status": "error", "task_id": self.task.id, } ) if os.path.exists(self.cuckoolog_path): debug["cuckoo"] = Logfile(self.cuckoolog_path) dbgview_log = os.path.join(self.analysis_path, "logs", "dbgview.log") if os.path.exists(dbgview_log): f = open(dbgview_log, "rb") # Ignore the first line which identifies the machine. f.readline() for line in f: idx, time, message = line.split("\t", 2) debug["dbgview"].append(message.strip()) debug["errors"] = [] for error in Database().view_errors(self.task["id"]): if error.message and error.message not in debug["errors"]: debug["errors"].append(error.message) if error.action and error.action not in debug["action"]: debug["action"].append(error.action) if os.path.exists(self.mitmerr_path): mitmerr = open(self.mitmerr_path, "rb").read() if mitmerr and mitmerr not in debug["errors"]: debug["errors"].append(mitmerr) return debug
def test_faq(): assert faq("hehe").startswith("http") assert faq("hehe").endswith("#hehe")
def launch_analysis(self): """Start analysis.""" succeeded = False if self.task.category == "file" or self.task.category == "archive": target = os.path.basename(self.task.target) else: target = self.task.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), extra={ "action": "task.init", "status": "starting", "task_id": self.task.id, "target": target, "category": self.task.category, "package": self.task.package, "options": emit_options(self.task.options), "custom": self.task.custom, } ) # Initialize the analysis. if not self.init(): logger("Failed to initialize", action="task.init", status="error") return False # Acquire analysis machine. try: self.acquire_machine() except CuckooOperationalError as e: machine_lock.release() log.error("Cannot acquire machine: %s", e, extra={ "action": "vm.acquire", "status": "error", }) 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() # Check if the current task has remotecontrol # enabled before starting the machine. control_enabled = ( config("cuckoo:remotecontrol:enabled") and "remotecontrol" in self.task.options ) if control_enabled: try: machinery.enable_remote_control(self.machine.label) except NotImplementedError: raise CuckooMachineError( "Remote control support has not been implemented " "for this machinery." ) 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__) logger( "Starting VM", action="vm.start", status="pending", vmname=self.machine.name ) # Start the machine. machinery.start(self.machine.label, self.task) logger( "Started VM", action="vm.start", status="success", vmname=self.machine.name ) # retrieve the port used for remote control if control_enabled: try: params = machinery.get_remote_control_params( self.machine.label ) self.db.set_machine_rcparams(self.machine.label, params) except NotImplementedError: raise CuckooMachineError( "Remote control support has not been implemented " "for this machinery." ) # 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 CuckooMachineSnapshotError as e: log.error( "Unable to restore to the snapshot for this Virtual Machine! " "Does your VM have a proper Snapshot and can you revert to it " "manually? VM: %s, error: %s", self.machine.name, e, extra={ "action": "vm.resume", "status": "error", "vmname": self.machine.name, } ) except CuckooMachineError as e: if not unlocked: machine_lock.release() log.error( "Error starting Virtual Machine! VM: %s, error: %s", self.machine.name, e, extra={ "action": "vm.start", "status": "error", "vmname": self.machine.name, } ) except CuckooGuestCriticalTimeout as e: if not unlocked: machine_lock.release() log.error( "Error from machine '%s': it appears that this Virtual " "Machine hasn't been configured properly as the Cuckoo Host " "wasn't able to connect to the Guest. There could be a few " "reasons for this, please refer to our documentation on the " "matter: %s", self.machine.name, faq("troubleshooting-vm-network-configuration"), extra={ "error_action": "vmrouting", "action": "guest.handle", "status": "error", "task_id": self.task.id, } ) except CuckooGuestError as e: if not unlocked: machine_lock.release() log.error("Error from the Cuckoo Guest: %s", e, extra={ "action": "guest.handle", "status": "error", "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: logger( "Taking full memory dump", action="vm.memdump", status="pending", vmname=self.machine.name ) try: dump_path = os.path.join(self.storage, "memory.dmp") machinery.dump_memory(self.machine.label, dump_path) logger( "Taken full memory dump", action="vm.memdump", status="success", vmname=self.machine.name ) except NotImplementedError: log.error( "The memory dump functionality is not available for " "the current machine manager.", extra={ "action": "vm.memdump", "status": "error", "vmname": self.machine.name, } ) except CuckooMachineError as e: log.error("Machinery error: %s", e, extra={ "action": "vm.memdump", "status": "error", }) logger( "Stopping VM", action="vm.stop", status="pending", vmname=self.machine.name ) 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, extra={ "action": "vm.stop", "status": "error", "vmname": self.machine.name, } ) logger( "Stopped VM", action="vm.stop", status="success", vmname=self.machine.name ) # Disable remote control after stopping the machine # if it was enabled for the task. if control_enabled: try: machinery.disable_remote_control(self.machine.label) except NotImplementedError: raise CuckooMachineError( "Remote control support has not been implemented " "for this machinery." ) # 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, extra={ "action": "vm.release", "status": "error", "vmname": self.machine.name, } ) return succeeded
def start_and_wait(self): """Start the analysis by running the auxiliary modules, adding the task to the resultserver, starting the machine and running a guest manager.""" # Set guest status to starting and start analysis machine self.set_analysis_status(Analysis.STARTING) target = self.target.target if self.target.target and self.target.is_file: target = os.path.basename(target) log.info( "Starting analysis (task #%s, options: '%s') type '%s'." " Target: %s '%s'", self.task.id, self.options["options"], self.task.type, self.target.category, target, extra={ "action": "task.init", "status": "starting", "task_id": self.task.id, "target": target, "category": self.target.category, "package": self.task.package, "options": self.options["options"], "custom": self.task.custom, "type": self.task.type }) ResultServer().add_task(self.task.db_task, self.machine, self.rt) # Start auxiliary modules self.aux.start() if self.control_enabled: try: self.machinery.enable_remote_control(self.machine.label) except NotImplementedError: self.control_enabled = False log.exception( "Remote control support has not been implemented " "for machinery %s.", self.machine.manager) # Json log for performance measurement purposes logger("Starting VM", action="vm.start", status="pending", vmname=self.machine.name) try: self.machinery.start(self.machine.label, self.task.db_task) except CuckooMachineSnapshotError as e: log.error( "Unable to restore to the snapshot for this Virtual Machine! " "Does your VM have a proper Snapshot and can you revert to it " "manually? VM: %s, error: %s", self.machine.name, e, extra={ "action": "vm.resume", "status": "error", "vmname": self.machine.name, }) return False except CuckooMachineError as e: log.error("Error starting Virtual Machine! VM: %s, error: %s", self.machine.name, e, extra={ "action": "vm.start", "status": "error", "vmname": self.machine.name, }) return False logger("Started VM", action="vm.start", status="success", vmname=self.machine.name) # retrieve the port used for remote control if self.control_enabled: try: params = self.machinery.get_remote_control_params( self.machine.label) self.db.set_machine_rcparams(self.machine.label, params) except NotImplementedError: log.exception( "Remote control support has not been implemented " "for machinery %s.", self.machine.manager) # Enable network routing self.route.route_network() # By the time start returns it will have fully started the Virtual # Machine. We can now safely release the machine lock. self.release_machine_lock() # Request scheduler action for status 'starting' self.request_scheduler_action(Analysis.STARTING) # Choose the correct way of waiting or managing the agent and # execute it try: self.manage() except CuckooGuestCriticalTimeout as e: log.error( "Error from machine '%s': it appears that this Virtual " "Machine hasn't been configured properly as the Cuckoo Host " "wasn't able to connect to the Guest. There could be a few " "reasons for this, please refer to our documentation on the " "matter: %s", self.machine.name, faq("troubleshooting-vm-network-configuration"), extra={ "error_action": "vmrouting", "action": "guest.handle", "status": "error", "task_id": self.task.id, }) except CuckooGuestError as e: log.error("Error from the Cuckoo Guest: %s", e, extra={ "action": "guest.handle", "status": "error", "task_id": self.task.id, }) return True