def _status(self, label): """Gets current status of a physical machine. @param label: physical machine name. @return: status string. """ # For physical machines, the agent can either be contacted or not. # However, there is some information to be garnered from potential # exceptions. log.debug("Getting status for machine: %s.", label) machine = self._get_machine(label) # The status is only used to determine whether the Guest is running # or whether it is in a stopped status, therefore the timeout can most # likely be fairly arbitrary. TODO This is a temporary fix as it is # not compatible with the new Cuckoo Agent, but it will have to do. url = "http://{0}:{1}".format(machine.ip, CUCKOO_GUEST_PORT) server = TimeoutServer(url, allow_none=True, timeout=60) try: status = server.get_status() except xmlrpclib.Fault as e: # Contacted Agent, but it threw an error. log.debug("Agent error: %s (%s) (Error: %s).", machine.id, machine.ip, e) return self.ERROR except socket.error as e: # Could not contact agent. log.debug("Agent unresponsive: %s (%s) (Error: %s).", machine.id, machine.ip, e) return self.STOPPED except Exception as e: # TODO Handle this better. log.debug("Received unknown exception: %s.", e) return self.ERROR # If the agent responded successfully, then the physical machine # is running if status: return self.RUNNING return self.ERROR
class OldGuestManager(object): """Old and deprecated Guest Manager. This class handles the communications with the old agent running in the virtual machine. """ def __init__(self, vm_id, ip, platform, task_id): """@param ip: guest's IP address. @param platform: guest's operating system type. """ self.id = vm_id self.ip = ip self.platform = platform self.task_id = task_id # initialized in start_analysis so we can update the critical timeout # TODO, pull options parameter into __init__ so we can do this here self.timeout = None self.server = None def wait(self, status): """Waiting for status. @param status: status. @return: always True. """ log.debug("%s: waiting for status 0x%.04x", self.id, status) end = time.time() + self.timeout self.server._set_timeout(self.timeout) while db.guest_get_status(self.task_id) == "starting": # Check if we've passed the timeout. if time.time() > end: raise CuckooGuestCriticalTimeout( "Machine %s: the guest initialization hit the " "critical timeout, analysis aborted." % self.id) try: # If the server returns the given status, break the loop # and return. if self.server.get_status() == status: log.debug("%s: status ready", self.id) break except: pass log.debug("%s: not ready yet", self.id) time.sleep(1) self.server._set_timeout(None) return True def upload_analyzer(self, monitor): """Upload analyzer to guest. @return: operation status. """ zip_data = analyzer_zipfile(self.platform, monitor) log.debug( "Uploading analyzer to guest (id=%s, ip=%s, monitor=%s, size=%d)", self.id, self.ip, monitor, len(zip_data)) # Send the zip containing the analyzer to the agent running inside # the guest. try: self.server.add_analyzer(xmlrpclib.Binary(zip_data)) except socket.timeout: raise CuckooGuestError("{0}: guest communication timeout: unable " "to upload agent, check networking or try " "to increase timeout".format(self.id)) def start_analysis(self, options, monitor): """Start analysis. @param options: options. @return: operation status. """ # TODO Deal with unicode URLs, should probably try URL encoding. # Unicode files are being taken care of. self.timeout = options["timeout"] + config("cuckoo:timeouts:critical") url = "http://{0}:{1}".format(self.ip, CUCKOO_GUEST_PORT) self.server = TimeoutServer(url, allow_none=True, timeout=self.timeout) try: # Wait for the agent to respond. This is done to check the # availability of the agent and verify that it's ready to receive # data. self.wait(CUCKOO_GUEST_INIT) # Invoke the upload of the analyzer to the guest. self.upload_analyzer(monitor) # Give the analysis options to the guest, so it can generate the # analysis.conf inside the guest. try: self.server.add_config(options) except: raise CuckooGuestError( "%s: unable to upload config to analysis machine" % self.id) # If the target of the analysis is a file, upload it to the guest. if options["category"] in ("file", "archive"): try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError("Unable to read %s, error: %s" % (options["target"], e)) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, options["file_name"]) except Exception as e: raise CuckooGuestError( "#%s: unable to upload malware to analysis " "machine: %s" % (self.id, e)) # Launch the analyzer. pid = self.server.execute() log.debug("%s: analyzer started with PID %d", self.id, pid) # If something goes wrong when establishing the connection, raise an # exception and abort the analysis. except (socket.timeout, socket.error): raise CuckooGuestError( "%s: guest communication timeout, check networking or try " "to increase timeout" % self.id) def wait_for_completion(self): """Wait for analysis completion. @return: operation status. """ log.debug("%s: waiting for completion", self.id) end = time.time() + self.timeout self.server._set_timeout(self.timeout) while db.guest_get_status(self.task_id) == "running": time.sleep(1) # If the analysis hits the critical timeout, just return straight # away and try to recover the analysis results from the guest. if time.time() > end: log.info("%s: end of analysis reached!", self.id) return try: status = self.server.get_status() except Exception as e: log.debug("%s: error retrieving status: %s", self.id, e) continue # React according to the returned status. if status == CUCKOO_GUEST_COMPLETED: log.info("%s: analysis completed successfully", self.id) break elif status == CUCKOO_GUEST_FAILED: error = self.server.get_error() raise CuckooGuestError("Analysis failed: %s" % (error or "unknown error")) else: log.debug("%s: analysis not completed yet (status=%s)", self.id, status) self.server._set_timeout(None)
class OldGuestManager(object): """Old and deprecated Guest Manager. This class handles the communications with the old agent running in the virtual machine. """ def __init__(self, vm_id, ip, platform, task_id): """@param ip: guest's IP address. @param platform: guest's operating system type. """ self.id = vm_id self.ip = ip self.platform = platform self.task_id = task_id # initialized in start_analysis so we can update the critical timeout # TODO, pull options parameter into __init__ so we can do this here self.timeout = None self.server = None def wait(self, status): """Waiting for status. @param status: status. @return: always True. """ log.debug("%s: waiting for status 0x%.04x", self.id, status) end = time.time() + self.timeout self.server._set_timeout(self.timeout) while db.guest_get_status(self.task_id) == "starting": # Check if we've passed the timeout. if time.time() > end: raise CuckooGuestCriticalTimeout( "Machine %s: the guest initialization hit the " "critical timeout, analysis aborted." % self.id ) try: # If the server returns the given status, break the loop # and return. if self.server.get_status() == status: log.debug("%s: status ready", self.id) break except: pass log.debug("%s: not ready yet", self.id) time.sleep(1) self.server._set_timeout(None) return True def upload_analyzer(self, monitor): """Upload analyzer to guest. @return: operation status. """ zip_data = analyzer_zipfile(self.platform, monitor) log.debug( "Uploading analyzer to guest (id=%s, ip=%s, monitor=%s, size=%d)", self.id, self.ip, monitor, len(zip_data) ) # Send the zip containing the analyzer to the agent running inside # the guest. try: self.server.add_analyzer(xmlrpclib.Binary(zip_data)) except socket.timeout: raise CuckooGuestError("{0}: guest communication timeout: unable " "to upload agent, check networking or try " "to increase timeout".format(self.id)) def start_analysis(self, options, monitor): """Start analysis. @param options: options. @return: operation status. """ # TODO Deal with unicode URLs, should probably try URL encoding. # Unicode files are being taken care of. self.timeout = options["timeout"] + config("cuckoo:timeouts:critical") url = "http://{0}:{1}".format(self.ip, CUCKOO_GUEST_PORT) self.server = TimeoutServer(url, allow_none=True, timeout=self.timeout) try: # Wait for the agent to respond. This is done to check the # availability of the agent and verify that it's ready to receive # data. self.wait(CUCKOO_GUEST_INIT) # Invoke the upload of the analyzer to the guest. self.upload_analyzer(monitor) # Give the analysis options to the guest, so it can generate the # analysis.conf inside the guest. try: self.server.add_config(options) except: raise CuckooGuestError( "%s: unable to upload config to analysis machine" % self.id ) # If the target of the analysis is a file, upload it to the guest. if options["category"] in ("file", "archive"): try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError( "Unable to read %s, error: %s" % (options["target"], e) ) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, options["file_name"]) except Exception as e: raise CuckooGuestError( "#%s: unable to upload malware to analysis " "machine: %s" % (self.id, e) ) # Launch the analyzer. pid = self.server.execute() log.debug("%s: analyzer started with PID %d", self.id, pid) # If something goes wrong when establishing the connection, raise an # exception and abort the analysis. except (socket.timeout, socket.error): raise CuckooGuestError( "%s: guest communication timeout, check networking or try " "to increase timeout" % self.id ) def wait_for_completion(self): """Wait for analysis completion. @return: operation status. """ log.debug("%s: waiting for completion", self.id) end = time.time() + self.timeout self.server._set_timeout(self.timeout) while db.guest_get_status(self.task_id) == "running": time.sleep(1) # If the analysis hits the critical timeout, just return straight # away and try to recover the analysis results from the guest. if time.time() > end: raise CuckooGuestError( "The analysis hit the critical timeout, terminating." ) try: status = self.server.get_status() except Exception as e: log.debug("%s: error retrieving status: %s", self.id, e) continue # React according to the returned status. if status == CUCKOO_GUEST_COMPLETED: log.info("%s: analysis completed successfully", self.id) break elif status == CUCKOO_GUEST_FAILED: error = self.server.get_error() raise CuckooGuestError( "Analysis failed: %s" % (error or "unknown error") ) else: log.debug("%s: analysis not completed yet (status=%s)", self.id, status) self.server._set_timeout(None)