def upload_support_files(self, options): """ Upload supporting files from zip temp directory if they exist :param options: options :return: """ log.info("Uploading support files to guest (id=%s, ip=%s)", self.id, self.ip) basedir = os.path.dirname(options["target"]) for dirpath, _, files in os.walk(basedir): for xf in files: target = os.path.join(dirpath, xf) # Copy all files except for the original target if not target == options["target"]: try: file_data = open(target, "rb").read() except (IOError, OSError) as e: raise CuckooGuestError( "Unable to read {}, error: {}".format(target, e)) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, xf) except Exception as e: raise CuckooGuestError( "{}: unable to upload support file to " "analysis machine: {}".format(self.id, e)) return
def start_analysis(self, options): """Start analysis. @param options: options. @return: operation status. """ log.info("Starting analysis on guest (id=%s, ip=%s)", self.id, self.ip) # TODO: deal with unicode URLs. if options["category"] == "file": options["file_name"] = sanitize_filename(options["file_name"]) # If the analysis timeout is higher than the critical timeout, # automatically increase the critical timeout by one minute. if options["timeout"] > self.timeout: log.debug("Automatically increased critical timeout to %s", self.timeout) self.timeout = options["timeout"] + 60 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() # 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("{0}: unable to upload config to " "analysis machine".format(self.id)) # If the target of the analysis is a file, upload it to the guest. if options["category"] == "file": try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError("Unable to read {0}, error: " "{1}".format(options["target"], e)) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, options["file_name"]) except Exception as e: raise CuckooGuestError("{0}: unable to upload malware to " "analysis machine: {1}".format( 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("{0}: guest communication timeout, 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"] + self.cfg.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("{0}: unable to upload config to " "analysis machine".format(self.id)) # If the target of the analysis is a file, upload it to the guest. if options["category"] == "file": try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError("Unable to read {0}, error: " "{1}".format(options["target"], e)) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, options["file_name"]) except Exception as e: raise CuckooGuestError("{0}: unable to upload malware to " "analysis machine: {1}".format( 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("{0}: guest communication timeout, check " "networking or try to increase " "timeout".format(self.id))
def wait_for_completion(self): """Wait for analysis completion. @return: operation status. """ log.debug("%s: waiting for completion", self.id) # Same procedure as in self.wait(). Just look at the comments there. abort = Event() abort.clear() def die(): abort.set() timer = Timer(self.timeout, die) timer.start() self.server._set_timeout(self.timeout) while True: time.sleep(1) # If the analysis hits the critical timeout, just return straight # straight away and try to recover the analysis results from the # guest. if abort.is_set(): 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() if not error: error = "unknown error" raise CuckooGuestError("Analysis failed: {0}".format(error)) else: log.debug("%s: analysis not completed yet (status=%s)", self.id, status) self.server._set_timeout(None)
def wait(self, status): """Waiting for status. @param status: status. @return: always True. """ log.info("%s: waiting for status 0x%.04x", self.id, status) end = time.time() + self.timeout self.server._set_timeout(self.timeout) while True: # Check if we've passed the timeout. if time.time() > end: raise CuckooGuestError("{0}: the guest initialization hit the " "critical timeout, analysis " "aborted.".format(self.id)) try: # If the server returns the given status, break the loop # and return. if self.server.get_status() == status: log.info("%s: status ready", self.id) break except: pass log.info("%s: not ready yet", self.id) time.sleep(1) self.server._set_timeout(None) return True
def wait_for_completion(self): if self.is_old: self.old.wait_for_completion() return end = time.time() + self.timeout while db.guest_get_status(self.task_id) == "running": log.debug("%s: analysis still processing", self.vmid) 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.get("/status", timeout=5).json() except Exception as e: log.info("Virtual Machine /status failed (%r)", e) # this might fail due to timeouts or just temporary network issues # thus we don't want to abort the analysis just yet and wait for things to # recover continue if status["status"] == "complete": log.info("%s: analysis completed successfully", self.vmid) return elif status["status"] == "exception": log.info("%s: analysis caught an exception\n%s", self.vmid, status["description"]) return
def wait_for_completion(self): if self.is_old: self.old.wait_for_completion() return end = time.time() + self.timeout while True: 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.get("/status", timeout=5).json() except: log.info("Virtual Machine stopped abruptly") break if status["status"] == "complete": log.info("%s: analysis completed successfully", self.vmid) return elif status["status"] == "exception": log.info("%s: analysis caught an exception\n%s", self.vmid, status["description"]) return log.debug("%s: analysis still processing", self.vmid)
def start_analysis(self, options): """Start analysis. @param options: options. @return: operation status. """ if not os.path.exists(options["file_path"]): return False log.info("Starting analysis on guest (id=%s, ip=%s)" % (self.id, self.ip)) socket.setdefaulttimeout(180) try: self.wait(CUCKOO_GUEST_INIT) self.upload_analyzer() self.server.add_config(options) file_data = open(options["file_path"], "rb").read() data = xmlrpclib.Binary(file_data) self.server.add_malware(data, options["file_name"]) self.server.execute() except socket.timeout: 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 True: 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: self._fm.turn_off() 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: self._fm.turn_off() log.info("%s: analysis completed successfully", self.id) break elif status == CUCKOO_GUEST_FAILED: error = self.server.get_error() if not error: error = "unknown error" self._fm.turn_off() raise CuckooGuestError("Analysis failed: {0}".format(error)) elif self._fm.check_frida_status(): raise CuckooGuestError( "Analysis failed: {0}".format("Frida is not working")) else: log.debug("%s: analysis not completed yet (status=%s)", self.id, status) self.server._set_timeout(None)
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 True: time.sleep(0.2) # 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() if not error: error = "unknown error" raise CuckooGuestError("Analysis failed: {0}".format(error)) elif status == CUCKOO_GUEST_INIT: # means the system must have bluescreened or restarted and now we're getting the initial agent.py request again raise CuckooGuestError( "Analysis failed: system restarted unexpectedly") else: log.debug("%s: analysis not completed yet (status=%s)", self.id, status) self.server._set_timeout(None)
def analyzer_zipfile(platform, monitor): """Creates the Zip file that is sent to the Guest.""" t = time.time() zip_data = io.BytesIO() zip_file = ZipFile(zip_data, "w", ZIP_STORED) # Select the proper analyzer's folder according to the operating # system associated with the current machine. root = os.path.join(CUCKOO_ROOT, "analyzer", platform) root_len = len(os.path.abspath(root)) if not os.path.exists(root): log.error("No valid analyzer found at path: %s", root) raise CuckooGuestError("No valid analyzer found for %s platform!" % platform) # Walk through everything inside the analyzer's folder and write # them to the zip archive. for root, dirs, files in os.walk(root): archive_root = os.path.abspath(root)[root_len:] for name in files: path = os.path.join(root, name) archive_name = os.path.join(archive_root, name) zip_file.write(path, archive_name) # Include the chosen monitoring component. if platform == "windows": dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", monitor) # Sometimes we might get a file instead of a symbolic link, in that # case we follow the semi-"symbolic link" manually. if os.path.isfile(dirpath): monitor = os.path.basename(open(dirpath, "rb").read().strip()) dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", monitor) for name in os.listdir(dirpath): path = os.path.join(dirpath, name) archive_name = os.path.join("/bin", name) zip_file.write(path, archive_name) zip_file.close() data = zip_data.getvalue() if time.time() - t > 10: log.warning( "It took more than 10 seconds to build the Analyzer Zip for the " "Guest. This might be a serious performance penalty. Is your " "analyzer/windows/ directory bloated with unnecessary files?") return data
def wait_for_completion(self): if self.is_old: self.old.wait_for_completion() return end = time.time() + self.timeout s = 0 burn = False # custom child = os.popen('python ~/cuckoo/child.py') # custom log.debug('[MADE Child FLAG] python ~/cuckoo/child.py') FIN_flag = False 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.get("/status", timeout=5).json() except: log.info("Virtual Machine stopped abruptly") break if status["status"] == "complete" or FIN_flag == True: #custom log.info("%s: analysis completed successfully", self.vmid) return elif status["status"] == "exception": log.info("%s: analysis caught an exception\n%s", self.vmid, status["description"]) return log.debug( "%s: analysis not completed yet (status=%s) (spent=%ds/%s)", self.vmid, status, s, self.timeout) # custom ############### custom from here ################# if burn == False: s, FIN_flag = internet_control.check(self.hv, self.timeout, log, int(self.burn_limit)) if FIN_flag != True: burn = True log.debug("[return odoriba] internet control out.. %ds" % s) if subprocess.check_output(['ps']).find('child.py') == -1: FIN_flag = True log.debug('[Analysis Finished] FIN_flag set in guest.py')
def upload_analyzer(self, monitor): """Upload analyzer to guest. @return: operation status. """ zip_data = StringIO() zip_file = ZipFile(zip_data, "w", ZIP_STORED) # Select the proper analyzer's folder according to the operating # system associated with the current machine. root = os.path.join(CUCKOO_ROOT, "analyzer", self.platform) root_len = len(os.path.abspath(root)) if not os.path.exists(root): log.error("No valid analyzer found at path: %s", root) return False # Walk through everything inside the analyzer's folder and write # them to the zip archive. for root, dirs, files in os.walk(root): archive_root = os.path.abspath(root)[root_len:] for name in files: path = os.path.join(root, name) archive_name = os.path.join(archive_root, name) zip_file.write(path, archive_name) # Include the chosen monitoring component. if self.platform == "windows": dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", monitor) for name in os.listdir(dirpath): path = os.path.join(dirpath, name) archive_name = os.path.join("/bin", name) zip_file.write(path, archive_name) zip_file.close() data = xmlrpclib.Binary(zip_data.getvalue()) zip_data.close() log.debug("Uploading analyzer to guest (id=%s, ip=%s, monitor=%s)", self.id, self.ip, monitor) # Send the zip containing the analyzer to the agent running inside # the guest. try: self.server.add_analyzer(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 analyzer_zipfile(platform): """Create the zip file that is sent to the Guest.""" t = time.time() zip_data = BytesIO() zip_file = ZipFile(zip_data, "w", ZIP_STORED) # Select the proper analyzer's folder according to the operating # system associated with the current machine. root = os.path.join(CUCKOO_ROOT, "analyzer", platform) root_len = len(os.path.abspath(root)) if not os.path.exists(root): log.error("No valid analyzer found at path: %s", root) raise CuckooGuestError( "No valid analyzer found for %s platform!" % platform ) # Walk through everything inside the analyzer's folder and write # them to the zip archive. for root, dirs, files in os.walk(root): archive_root = os.path.abspath(root)[root_len:] for name in files: path = os.path.join(root, name) archive_name = os.path.join(archive_root, name) zip_file.write(path, archive_name) #ToDo remove """ for name in os.listdir(dirpath): zip_file.write( os.path.join(dirpath, name), os.path.join("bin", name) ) """ zip_file.close() data = zip_data.getvalue() zip_data.close() if time.time() - t > 10: log.warning( "It took more than 10 seconds to build the Analyzer Zip for the " "Guest. This might be a serious performance penalty. Is your " "analyzer/windows/ directory bloated with unnecessary files?" ) return data
def wait_available(self): """Wait until the Virtual Machine is available for usage.""" end = time.time() + self.timeout while True: try: socket.create_connection((self.ipaddr, self.port), 1).close() break except socket.timeout: log.debug("%s: not ready yet", self.vmid) except socket.error: log.debug("%s: not ready yet", self.vmid) time.sleep(1) if time.time() > end: raise CuckooGuestError("{0}: the guest initialization hit the " "critical timeout, analysis " "aborted.".format(self.vmid))
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 True: # Check if we've passed the timeout. if time.time() > end: raise CuckooGuestError("{0}: the guest initialization hit the " "critical timeout, analysis " "aborted.".format(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: if self.id == "aosx" and self._fm and check_ping(self.ip): if not self._fm.process_on: run_cmd_with_timeout("killall adb", 4) run_cmd_with_timeout("adb root", 4) run_cmd_with_timeout("adb connect {}".format(self.ip), 4) run_cmd_with_timeout( "adb shell am start -n com.cuckoo.agent/com.cuckoo.agent.MainActivity -a android.intent.action.MAIN,android.intent.action.BOOT_COMPLETED -c android.intent.category.LAUNCHER", 4) time.sleep(2) self._fm.set_frida_server() time.sleep(2) run_cmd_with_timeout("adb shell am restart", 4) self._fm.process_on = True time.sleep(10) pass log.debug("%s: not ready yet", self.id) time.sleep(1) self.server._set_timeout(None) return True
def post(self, method, *args, **kwargs): """Simple wrapper around requests.post().""" url = "http://%s:%s%s" % (self.ipaddr, self.port, method) session = requests.Session() session.trust_env = False session.proxies = None try: r = session.post(url, *args, **kwargs) except requests.ConnectionError: raise CuckooGuestError( "CAPE Agent failed without error status, please try " "upgrading to the latest version of agent.py (>= 0.10) and " "notify us if the issue persists.") r.raise_for_status() return r
def get(self, method, *args, **kwargs): """Simple wrapper around requests.get().""" do_raise = kwargs.pop("do_raise", True) url = f"http://{self.ipaddr}:{self.port}{method}" with requests.Session() as session: session.trust_env = False session.proxies = None try: r = session.get(url, *args, **kwargs) except requests.ConnectionError: raise CuckooGuestError( "CAPE Agent failed without error status, please try " "upgrading to the latest version of agent.py (>= 0.10) and " "notify us if the issue persists") do_raise and r.raise_for_status() return r
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 wait_available(self): """Wait until the Virtual Machine is available for usage.""" end = time.time() + self.timeout while db.guest_get_status(self.task_id) == "starting": try: socket.create_connection((self.ipaddr, self.port), 1).close() break except socket.timeout: log.debug("%s: not ready yet", self.vmid) except socket.error: log.debug("%s: not ready yet", self.vmid) time.sleep(1) if time.time() > end: raise CuckooGuestError( "%s: the guest initialization hit the critical timeout, " "analysis aborted." % self.vmid)
def wait(self, status): """Waiting for status. @param status: status. @return: always True. """ log.debug("%s: waiting for status 0x%.04x", self.id, status) # Create an event that will invoke a function to stop the loop when # the critical timeout is h it. abort = Event() abort.clear() def die(): abort.set() # Initialize the timer. timer = Timer(self.timeout, die) timer.start() self.server._set_timeout(self.timeout) while True: # Check if the timer was hit and the abort event was set. if abort.is_set(): raise CuckooGuestError("{0}: the guest initialization hit the " "critical timeout, analysis " "aborted".format(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 wait_for_completion(self): if self.is_old: self.old.wait_for_completion() return end = time.time() + 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.get("/status", timeout=5).json() except: log.info("Virtual Machine stopped abruptly") break if status["status"] == "complete": log.info("%s: analysis completed successfully", self.vmid) # TODO: dirty-hack for non-rooter system import subprocess subprocess.Popen( "vboxmanage hostonlyif ipconfig vboxnet0 --ip 10.31.37.1 --netmask 255.255.255.0" .split()) return elif status["status"] == "exception": log.info("%s: analysis caught an exception\n%s", self.vmid, status["description"]) return log.debug("%s: analysis still processing", self.vmid)
def start_analysis(self, options): """Start analysis. @param options: options. @return: operation status. """ log.info("Starting analysis on guest (id=%s, ip=%s)", self.id, self.ip) # TODO: deal with unicode URLs. if options["category"] == "file": options["file_name"] = "'" + sanitize_filename( options["file_name"]) + "'" self.timeout = options["timeout"] + self.cfg.timeouts.critical # Get and set dynamically generated resultserver port. options["port"] = str(ResultServer().port) 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() # 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("{0}: unable to upload config to " "analysis machine".format(self.id)) # If the target of the analysis is a file, upload it to the guest. if options["category"] == "file": try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError("Unable to read {0}, error: " "{1}".format(options["target"], e)) data = xmlrpclib.Binary(file_data) try: # strip off the added surrounding quotes self.server.add_malware(data, options["file_name"][1:-1]) except Exception as e: raise CuckooGuestError("{0}: unable to upload malware to " "analysis machine: {1}".format( self.id, e)) # check for support files and upload them to guest. self.upload_support_files(options) # Debug analyzer.py in vm if "CUCKOO_DBG" in os.environ: while True: pass # 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("{0}: guest communication timeout, check " "networking or try to increase " "timeout".format(self.id))
def wait_for_completion(self, machine, storage, machinery): """Wait for analysis completion. @return: operation status. """ log.debug("%s: waiting for completion", self.id) # Same procedure as in self.wait(). Just look at the comments there. abort = Event() abort.clear() def die(): abort.set() # CHANGED: Added time-based dumps here. resumableTimer = ResumableTimer(self.timeout, die) resumableTimer.start() sec_counter = 0 mem_analysis_conf = Config( os.path.join(CUCKOO_ROOT, "conf", "memoryanalysis.conf")) time_to_sleep = int( mem_analysis_conf.time_based.time_to_sleep_before_dump_in_seconds) number_of_dumps = int(mem_analysis_conf.basic.max_number_of_dumps) memory_results_dir = os.path.join(storage, "memory") dumps_dir = os.path.join(memory_results_dir, "dumps") create_dir_safe(memory_results_dir) create_dir_safe(dumps_dir) while True: if abort.is_set(): info_dict = { "trigger": { "name": "End", "args": {} }, "time": str(sec_counter) } log.info("Taking dump before termination...") self.take_mem_dump(dumps_dir, machine, machinery, info_dict) raise CuckooGuestError( "The analysis hit the critical timeout, terminating") while Event(STOP_EVENT).is_set(): time.sleep(0.005) time.sleep(1) sec_counter += 1 if mem_analysis_conf.basic.time_based and sec_counter % time_to_sleep == 0: resumableTimer.stop() info_dict = { "trigger": { "name": "Time", "args": { "interval": time_to_sleep } } } self.take_mem_dump(dumps_dir, machine, machinery, info_dict) resumableTimer.resume() 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() if not error: error = "unknown error" info_dict = {"trigger": {"name": "End", "args": {}}} log.info("Taking dump before termination...") self.take_mem_dump(dumps_dir, machine, machinery, info_dict) raise CuckooGuestError("Analysis failed: {0}".format(error)) # TODO: suspend machine and take dump else: log.debug("%s: analysis not completed yet (status=%s)", self.id, status) self.server._set_timeout(None) log.info("Taking dump before termination...") info_dict = {"trigger": {"name": "End", "args": {}}} self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
def start_analysis(self, options): """Start analysis. @param options: options. @return: operation status. """ log.info("Starting analysis on guest (id=%s, ip=%s)", self.id, self.ip) if misc_config.ENABLE_CUCKOO_EXTRA_INFO: time.sleep(10) subprocess.call([misc_config.ADB_PATH, "connect", "192.168.56.10"]) log.info("Starting to collect information") # Custom: Get process information try: self.getProcessList() # Get listening Ports self.getListeningPorts() self.generateFileList() except: log.info("ADB Error occured! Try again...") try: subprocess.Popen([misc_config.ADB_PATH, "kill-server"]) subprocess.Popen(["killall adb"]) time.sleep(2) subprocess.call( [misc_config.ADB_PATH, "connect", "192.168.56.10"]) time.sleep(5) self.getProcessList() # Get listening Ports self.getListeningPorts() self.generateFileList() except: log.info("ADB Error for the second time!") # TODO: deal with unicode URLs. if options["category"] == "file": options["file_name"] = sanitize_filename(options["file_name"]) # If the analysis timeout is higher than the critical timeout, # automatically increase the critical timeout by one minute. if options["timeout"] > self.timeout: log.debug("Automatically increased critical timeout to %s", self.timeout) self.timeout = options["timeout"] + 60 # Get and set dynamically generated resultserver port. options["port"] = str(ResultServer().port) 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() # 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("{0}: unable to upload config to " "analysis machine".format(self.id)) # If the target of the analysis is a file, upload it to the guest. if options["category"] == "file": try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError("Unable to read {0}, error: " "{1}".format(options["target"], e)) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, options["file_name"]) except Exception as e: raise CuckooGuestError("{0}: unable to upload malware to " "analysis machine: {1}".format( 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("{0}: guest communication timeout, check " "networking or try to increase " "timeout".format(self.id)) # Custom # Give the app some time to start up log.debug("Starting to simulate user interaction") time.sleep(10) self.simulateUserInteraction()
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) s = 0 burn = False # custom home = os.path.expanduser('~') child = os.popen('python %s/odoriba/child.py' % home) # custom print "A" * 100 log.debug('[MADE Child FLAG] python ~/odoriba/child.py') FIN_flag = False while db.guest_get_status(self.task_id) == "running": time.sleep(1) s += 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 or FIN_flag == True: #custom log.info("%s: analysis completed successfully", self.id) status = CUCKOO_GUEST_COMPLETED #custom break elif status == CUCKOO_GUEST_FAILED: error = self.server.get_error() if not error: error = "unknown error" raise CuckooGuestError("Analysis failed: {0}".format(error)) else: log.debug( "%s: analysis not completed yet (status=%s) (spent=%ds/%s)", self.id, status, s, self.timeout) # custom ############### custom from here ################# if burn == False: s, FIN_flag = internet_control.check( self.hv, self.timeout, log, int(self.burn_limit)) if FIN_flag != True: burn = True log.debug( "[return odoriba] internet control out.. %ds" % s) if subprocess.check_output(['ps']).find('child.py') == -1: FIN_flag = True log.debug('[Analysis Finished] FIN_flag set in guest.py') ############### custom until here ################# self.server._set_timeout(None)
def analyzer_zipfile(platform, monitor, options): """Creates the Zip file that is sent to the Guest.""" t = time.time() zip_data = io.BytesIO() zip_file = ZipFile(zip_data, "w", ZIP_STORED) # Select the proper analyzer's folder according to the operating # system associated with the current machine. root = os.path.join(CUCKOO_ROOT, "analyzer", platform) root_len = len(os.path.abspath(root)) if not os.path.exists(root): log.error("No valid analyzer found at path: %s", root) raise CuckooGuestError("No valid analyzer found for %s platform!" % platform) user_options = {} try: # Split the options by comma. fields = options["options"].split(",") except ValueError as e: log.error("Khaled: error while split options") pass else: for field in fields: # Split the name and the value of the option. try: key, value = field.split("=", 1) #log.debug("Key: " + key + " value: " + value) except ValueError as e: #log.debug("Error while split in loop" + e) pass else: # If the parsing went well we add the option to the # dictionary. user_options[key.strip()] = value.strip() submit_file = None pass_check = True pass_type = "cuckoo" if "request_file" in user_options: submit_file = user_options["request_file"] log.debug("Submit file: " + submit_file) elif "formatted_request_file" in user_options: submit_file = user_options["formatted_request_file"] log.debug("Submit file: " + submit_file) pass_type = "lwr" pass_check = False #If a "pass type" option is present in the request, then simply use that pass type #Else, check the request file (if present) to see what type of pass this is if pass_check: if "pass_type" in user_options: pass_type = user_options["pass_type"] elif submit_file: if "LWR.txt" in submit_file: pass_type = "lwr" elif "EMP_Request.bin" in submit_file: pass_type = "dynamorio" #Eventually we may be able to make this in the configuration file: copy_dict = { "dynamorio": "dynamorio", "dvasion_vm.dll": "dynamorio", "dvasion_vm1.dll": "dynamorio", "dvasion_vm2.dll": "dynamorio", "dvasion_exp.exe": "lwr", "dvasion_exp.dll": "lwr" } # Walk through everything inside the analyzer's folder and write # them to the zip archive. for root, dirs, files in os.walk(root): archive_root = os.path.abspath(root)[root_len:] for name in files: path = os.path.join(root, name) archive_name = os.path.join(archive_root, name) #Kapil:Transfer whole dynamo rio only if this is first pass if name in copy_dict and not copy_dict[name] == pass_type: log.debug("Not Writing to zip: " + archive_name) continue zip_file.write(path, archive_name) if submit_file: dest_path = os.path.join("processing_files", submit_file.split("/")[-1]) submit_file_path = os.path.join(CUCKOO_ROOT, "leader", submit_file) if (not os.path.isfile(submit_file_path)): log.critical("File does not exist at " + submit_file_path) raise CuckooGuestError("Submit_File was not found on disk") zip_file.write(os.path.join(CUCKOO_ROOT, "leader", submit_file), dest_path) log.debug("Added submit file to zip at: " + dest_path) # Include the chosen monitoring component. if platform == "windows": dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", monitor) # Sometimes we might get a file instead of a symbolic link, in that # case we follow the semi-"symbolic link" manually. if os.path.isfile(dirpath): monitor = os.path.basename(open(dirpath, "rb").read().strip()) dirpath = os.path.join(CUCKOO_ROOT, "data", "monitor", monitor) for name in os.listdir(dirpath): path = os.path.join(dirpath, name) archive_name = os.path.join("/bin", name) zip_file.write(path, archive_name) zip_file.close() data = zip_data.getvalue() if time.time() - t > 10: log.warning( "It took more than 10 seconds to build the Analyzer Zip for the " "Guest. This might be a serious performance penalty. Is your " "analyzer/windows/ directory bloated with unnecessary files?") return data
def start_analysis(self, options): """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. # If the analysis timeout is higher than the critical timeout, # automatically increase the critical timeout by one minute. if options["timeout"] > self.timeout: log.debug("Automatically increased critical timeout to %s", self.timeout) self.timeout = options["timeout"] + 60 opt = {} for row in options["options"].split(","): if "=" not in row: continue key, value = row.split("=", 1) opt[key.strip()] = value.strip() # Check whether the hashes file exists if it was provided. if "hashes-path" in opt: if not os.path.isfile(opt["hashes-path"]): raise CuckooGuestError("Non-existing hashing file provided!") 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(opt.get("hashes-path")) # 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("{0}: unable to upload config to " "analysis machine".format(self.id)) # If the target of the analysis is a file, upload it to the guest. if options["category"] == "file": try: file_data = open(options["target"], "rb").read() except (IOError, OSError) as e: raise CuckooGuestError("Unable to read {0}, error: " "{1}".format(options["target"], e)) data = xmlrpclib.Binary(file_data) try: self.server.add_malware(data, options["file_name"]) except Exception as e: raise CuckooGuestError("{0}: unable to upload malware to " "analysis machine: {1}".format( 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("{0}: guest communication timeout, check " "networking or try to increase " "timeout".format(self.id))