Package lib :: Package cuckoo :: Package core :: Module guest
[hide private]
[frames] | no frames]

Source Code for Module lib.cuckoo.core.guest

  1  # Copyright (C) 2010-2015 Cuckoo Foundation. 
  2  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  3  # See the file 'docs/LICENSE' for copying permission. 
  4   
  5  import os 
  6  import time 
  7  import socket 
  8  import logging 
  9  import xmlrpclib 
 10  from StringIO import StringIO 
 11  from zipfile import ZipFile, ZIP_STORED 
 12   
 13  from lib.cuckoo.common.config import Config 
 14  from lib.cuckoo.common.constants import CUCKOO_ROOT 
 15  from lib.cuckoo.common.constants import CUCKOO_GUEST_PORT, CUCKOO_GUEST_INIT 
 16  from lib.cuckoo.common.constants import CUCKOO_GUEST_COMPLETED 
 17  from lib.cuckoo.common.constants import CUCKOO_GUEST_FAILED 
 18  from lib.cuckoo.common.exceptions import CuckooGuestError 
 19  from lib.cuckoo.common.utils import TimeoutServer, sanitize_filename 
 20  from lib.cuckoo.core.resultserver import ResultServer 
 21   
 22  log = logging.getLogger(__name__) 
 23   
24 -class GuestManager:
25 """Guest Manager. 26 27 This class handles the communications with the agents running in the 28 machines. 29 """ 30
31 - def __init__(self, vm_id, ip, platform="windows"):
32 """@param ip: guest's IP address. 33 @param platform: guest's operating system type. 34 """ 35 self.id = vm_id 36 self.ip = ip 37 self.platform = platform 38 39 self.cfg = Config() 40 self.timeout = self.cfg.timeouts.critical 41 42 url = "http://{0}:{1}".format(ip, CUCKOO_GUEST_PORT) 43 self.server = TimeoutServer(url, allow_none=True, 44 timeout=self.timeout)
45
46 - def wait(self, status):
47 """Waiting for status. 48 @param status: status. 49 @return: always True. 50 """ 51 log.debug("%s: waiting for status 0x%.04x", self.id, status) 52 53 end = time.time() + self.timeout 54 self.server._set_timeout(self.timeout) 55 56 while True: 57 # Check if we've passed the timeout. 58 if time.time() > end: 59 raise CuckooGuestError("{0}: the guest initialization hit the " 60 "critical timeout, analysis " 61 "aborted.".format(self.id)) 62 63 try: 64 # If the server returns the given status, break the loop 65 # and return. 66 if self.server.get_status() == status: 67 log.debug("%s: status ready", self.id) 68 break 69 except: 70 pass 71 72 log.debug("%s: not ready yet", self.id) 73 time.sleep(1) 74 75 self.server._set_timeout(None) 76 return True
77
78 - def upload_analyzer(self):
79 """Upload analyzer to guest. 80 @return: operation status. 81 """ 82 zip_data = StringIO() 83 zip_file = ZipFile(zip_data, "w", ZIP_STORED) 84 85 # Select the proper analyzer's folder according to the operating 86 # system associated with the current machine. 87 root = os.path.join(CUCKOO_ROOT, "analyzer", self.platform) 88 root_len = len(os.path.abspath(root)) 89 90 if not os.path.exists(root): 91 log.error("No valid analyzer found at path: %s", root) 92 return False 93 94 # Walk through everything inside the analyzer's folder and write 95 # them to the zip archive. 96 for root, dirs, files in os.walk(root): 97 archive_root = os.path.abspath(root)[root_len:] 98 for name in files: 99 path = os.path.join(root, name) 100 archive_name = os.path.join(archive_root, name) 101 zip_file.write(path, archive_name) 102 103 zip_file.close() 104 data = xmlrpclib.Binary(zip_data.getvalue()) 105 zip_data.close() 106 107 log.debug("Uploading analyzer to guest (id=%s, ip=%s)", 108 self.id, self.ip) 109 110 # Send the zip containing the analyzer to the agent running inside 111 # the guest. 112 try: 113 self.server.add_analyzer(data) 114 except socket.timeout: 115 raise CuckooGuestError("{0}: guest communication timeout: unable " 116 "to upload agent, check networking or try " 117 "to increase timeout".format(self.id))
118
119 - def start_analysis(self, options):
120 """Start analysis. 121 @param options: options. 122 @return: operation status. 123 """ 124 log.info("Starting analysis on guest (id=%s, ip=%s)", self.id, self.ip) 125 126 # TODO: deal with unicode URLs. 127 if options["category"] == "file": 128 options["file_name"] = sanitize_filename(options["file_name"]) 129 130 # If the analysis timeout is higher than the critical timeout, 131 # automatically increase the critical timeout by one minute. 132 if options["timeout"] > self.timeout: 133 log.debug("Automatically increased critical timeout to %s", 134 self.timeout) 135 self.timeout = options["timeout"] + 60 136 137 # Get and set dynamically generated resultserver port. 138 options["port"] = str(ResultServer().port) 139 140 try: 141 # Wait for the agent to respond. This is done to check the 142 # availability of the agent and verify that it's ready to receive 143 # data. 144 self.wait(CUCKOO_GUEST_INIT) 145 146 # Invoke the upload of the analyzer to the guest. 147 self.upload_analyzer() 148 149 # Give the analysis options to the guest, so it can generate the 150 # analysis.conf inside the guest. 151 try: 152 self.server.add_config(options) 153 except: 154 raise CuckooGuestError("{0}: unable to upload config to " 155 "analysis machine".format(self.id)) 156 157 # If the target of the analysis is a file, upload it to the guest. 158 if options["category"] == "file": 159 try: 160 file_data = open(options["target"], "rb").read() 161 except (IOError, OSError) as e: 162 raise CuckooGuestError("Unable to read {0}, error: " 163 "{1}".format(options["target"], e)) 164 165 data = xmlrpclib.Binary(file_data) 166 167 try: 168 self.server.add_malware(data, options["file_name"]) 169 except Exception as e: 170 raise CuckooGuestError("{0}: unable to upload malware to " 171 "analysis machine: {1}".format(self.id, e)) 172 173 # Launch the analyzer. 174 pid = self.server.execute() 175 log.debug("%s: analyzer started with PID %d", self.id, pid) 176 # If something goes wrong when establishing the connection, raise an 177 # exception and abort the analysis. 178 except (socket.timeout, socket.error): 179 raise CuckooGuestError("{0}: guest communication timeout, check " 180 "networking or try to increase " 181 "timeout".format(self.id))
182
183 - def wait_for_completion(self):
184 """Wait for analysis completion. 185 @return: operation status. 186 """ 187 log.debug("%s: waiting for completion", self.id) 188 189 end = time.time() + self.timeout 190 self.server._set_timeout(self.timeout) 191 192 while True: 193 time.sleep(1) 194 195 # If the analysis hits the critical timeout, just return straight 196 # away and try to recover the analysis results from the guest. 197 if time.time() > end: 198 raise CuckooGuestError("The analysis hit the critical timeout, terminating.") 199 200 try: 201 status = self.server.get_status() 202 except Exception as e: 203 log.debug("%s: error retrieving status: %s", self.id, e) 204 continue 205 206 # React according to the returned status. 207 if status == CUCKOO_GUEST_COMPLETED: 208 log.info("%s: analysis completed successfully", self.id) 209 break 210 elif status == CUCKOO_GUEST_FAILED: 211 error = self.server.get_error() 212 if not error: 213 error = "unknown error" 214 215 raise CuckooGuestError("Analysis failed: {0}".format(error)) 216 else: 217 log.debug("%s: analysis not completed yet (status=%s)", 218 self.id, status) 219 220 self.server._set_timeout(None)
221