Module agent
[hide private]
[frames] | no frames]

Source Code for Module agent

  1  # Copyright (C) 2010-2014 Cuckoo Sandbox Developers. 
  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 sys 
  7  import time 
  8  import socket 
  9  import string 
 10  import random 
 11  import platform 
 12  import subprocess 
 13  import ConfigParser 
 14  from StringIO import StringIO 
 15  from zipfile import ZipFile 
 16  from SimpleXMLRPCServer import SimpleXMLRPCServer 
 17   
 18  BIND_IP = "0.0.0.0" 
 19  BIND_PORT = 8000 
 20   
 21  STATUS_INIT = 0x0001 
 22  STATUS_RUNNING = 0x0002 
 23  STATUS_COMPLETED = 0x0003 
 24  STATUS_FAILED = 0x0004 
 25  CURRENT_STATUS = STATUS_INIT 
 26   
 27  ERROR_MESSAGE = "" 
 28  ANALYZER_FOLDER = "" 
 29  RESULTS_FOLDER = "" 
 30   
31 -class Agent:
32 """Cuckoo agent, it runs inside guest.""" 33
34 - def __init__(self):
35 self.system = platform.system().lower() 36 self.analyzer_path = "" 37 self.analyzer_pid = 0
38
39 - def _initialize(self):
40 global ERROR_MESSAGE 41 global ANALYZER_FOLDER 42 43 if not ANALYZER_FOLDER: 44 random.seed(time.time()) 45 container = "".join(random.choice(string.ascii_lowercase) for x in range(random.randint(5, 10))) 46 47 if self.system == "windows": 48 system_drive = os.environ["SYSTEMDRIVE"] + os.sep 49 ANALYZER_FOLDER = os.path.join(system_drive, container) 50 elif self.system == "linux" or self.system == "darwin": 51 ANALYZER_FOLDER = os.path.join(os.environ["HOME"], container) 52 else: 53 ERROR_MESSAGE = "Unable to identify operating system" 54 return False 55 56 try: 57 os.makedirs(ANALYZER_FOLDER) 58 except OSError as e: 59 ERROR_MESSAGE = e 60 return False 61 62 return True
63
64 - def get_status(self):
65 """Get current status. 66 @return: status. 67 """ 68 return CURRENT_STATUS
69
70 - def get_error(self):
71 """Get error message. 72 @return: error message. 73 """ 74 return str(ERROR_MESSAGE)
75
76 - def add_malware(self, data, name):
77 """Get analysis data. 78 @param data: analysis data. 79 @param name: file name. 80 @return: operation status. 81 """ 82 global ERROR_MESSAGE 83 data = data.data 84 85 if self.system == "windows": 86 root = os.environ["TEMP"] 87 elif self.system == "linux" or self.system == "darwin": 88 root = "/tmp" 89 else: 90 ERROR_MESSAGE = "Unable to write malware to disk because of " \ 91 "failed identification of the operating system" 92 return False 93 94 file_path = os.path.join(root, name) 95 96 try: 97 with open(file_path, "wb") as malware: 98 malware.write(data) 99 except IOError as e: 100 ERROR_MESSAGE = "Unable to write malware to disk: {0}".format(e) 101 return False 102 103 return True
104
105 - def add_config(self, options):
106 """Creates analysis.conf file from current analysis options. 107 @param options: current configuration options, dict format. 108 @return: operation status. 109 """ 110 global ERROR_MESSAGE 111 112 if type(options) != dict: 113 return False 114 115 config = ConfigParser.RawConfigParser() 116 config.add_section("analysis") 117 118 try: 119 for key, value in options.items(): 120 # Options can be UTF encoded. 121 if isinstance(value, basestring): 122 try: 123 value = value.encode("utf-8") 124 except UnicodeEncodeError: 125 pass 126 127 config.set("analysis", key, value) 128 129 config_path = os.path.join(ANALYZER_FOLDER, "analysis.conf") 130 131 with open(config_path, "wb") as config_file: 132 config.write(config_file) 133 except Exception as e: 134 ERROR_MESSAGE = str(e) 135 return False 136 137 return True
138
139 - def add_analyzer(self, data):
140 """Add analyzer. 141 @param data: analyzer data. 142 @return: operation status. 143 """ 144 data = data.data 145 146 if not self._initialize(): 147 return False 148 149 try: 150 zip_data = StringIO() 151 zip_data.write(data) 152 153 with ZipFile(zip_data, "r") as archive: 154 archive.extractall(ANALYZER_FOLDER) 155 finally: 156 zip_data.close() 157 158 self.analyzer_path = os.path.join(ANALYZER_FOLDER, "analyzer.py") 159 160 return True
161
162 - def execute(self):
163 """Execute analysis. 164 @return: analyzer PID. 165 """ 166 global ERROR_MESSAGE 167 global CURRENT_STATUS 168 169 if not self.analyzer_path or not os.path.exists(self.analyzer_path): 170 return False 171 172 try: 173 proc = subprocess.Popen([sys.executable, self.analyzer_path], 174 cwd=os.path.dirname(self.analyzer_path)) 175 self.analyzer_pid = proc.pid 176 except OSError as e: 177 ERROR_MESSAGE = str(e) 178 return False 179 180 CURRENT_STATUS = STATUS_RUNNING 181 182 return self.analyzer_pid
183
184 - def complete(self, success=True, error="", results=""):
185 """Complete analysis. 186 @param success: success status. 187 @param error: error status. 188 """ 189 global ERROR_MESSAGE 190 global CURRENT_STATUS 191 global RESULTS_FOLDER 192 193 if success: 194 CURRENT_STATUS = STATUS_COMPLETED 195 else: 196 if error: 197 ERROR_MESSAGE = str(error) 198 199 CURRENT_STATUS = STATUS_FAILED 200 201 RESULTS_FOLDER = results 202 203 return True
204 205 if __name__ == "__main__": 206 try: 207 if not BIND_IP: 208 BIND_IP = socket.gethostbyname(socket.gethostname()) 209 210 print("[+] Starting agent on %s:%s ..." % (BIND_IP, BIND_PORT)) 211 212 # Disable DNS lookup, by Scott D.
213 - def FakeGetFQDN(name=""):
214 return name
215 socket.getfqdn = FakeGetFQDN 216 217 server = SimpleXMLRPCServer((BIND_IP, BIND_PORT), allow_none=True) 218 server.register_instance(Agent()) 219 server.serve_forever() 220 except KeyboardInterrupt: 221 server.shutdown() 222