1
2
3
4
5 import os
6 import time
7 import socket
8 import logging
9 import xmlrpclib
10 from threading import Timer, Event
11 from StringIO import StringIO
12 from zipfile import ZipFile, ZIP_STORED
13
14 from lib.cuckoo.common.config import Config
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
21 log = logging.getLogger(__name__)
22
24 """Guest Mananager.
25
26 This class handles the communications with the agents running in the
27 machines.
28 """
29
30 - def __init__(self, vm_id, ip, platform="windows"):
44
45 - def wait(self, status):
46 """Waiting for status.
47 @param status: status.
48 @return: always True.
49 """
50 log.debug("%s: waiting for status 0x%.04x", self.id, status)
51
52
53
54 abort = Event()
55 abort.clear()
56
57 def die():
58 abort.set()
59
60
61 timer = Timer(self.timeout, die)
62 timer.start()
63 self.server._set_timeout(self.timeout)
64
65 while True:
66
67 if abort.is_set():
68 raise CuckooGuestError("{0}: the guest initialization hit the "
69 "critical timeout, analysis "
70 "aborted".format(self.id))
71
72 try:
73
74
75 if self.server.get_status() == status:
76 log.debug("%s: status ready", self.id)
77 break
78 except:
79 pass
80
81 log.debug("%s: not ready yet", self.id)
82 time.sleep(1)
83
84 self.server._set_timeout(None)
85 return True
86
88 """Upload analyzer to guest.
89 @return: operation status.
90 """
91 zip_data = StringIO()
92 zip_file = ZipFile(zip_data, "w", ZIP_STORED)
93
94
95
96 root = os.path.join("analyzer", self.platform)
97 root_len = len(os.path.abspath(root))
98
99 if not os.path.exists(root):
100 log.error("No valid analyzer found at path: %s", root)
101 return False
102
103
104
105 for root, dirs, files in os.walk(root):
106 archive_root = os.path.abspath(root)[root_len:]
107 for name in files:
108 path = os.path.join(root, name)
109 archive_name = os.path.join(archive_root, name)
110 zip_file.write(path, archive_name)
111
112 zip_file.close()
113 data = xmlrpclib.Binary(zip_data.getvalue())
114 zip_data.close()
115
116 log.debug("Uploading analyzer to guest (id=%s, ip=%s)",
117 self.id, self.ip)
118
119
120
121 try:
122 self.server.add_analyzer(data)
123 except socket.timeout:
124 raise CuckooGuestError("{0}: guest communication timeout: unable "
125 "to upload agent, check networking or try "
126 "to increase timeout".format(self.id))
127
129 """Start analysis.
130 @param options: options.
131 @return: operation status.
132 """
133 log.info("Starting analysis on guest (id=%s, ip=%s)", self.id, self.ip)
134
135
136 if options["category"] == "file":
137 options["file_name"] = sanitize_filename(options["file_name"])
138
139 try:
140
141
142
143 self.wait(CUCKOO_GUEST_INIT)
144
145 self.upload_analyzer()
146
147
148 try:
149 self.server.add_config(options)
150 except:
151 raise CuckooGuestError("{0}: unable to upload config to "
152 "analysis machine".format(self.id))
153
154
155 if options["category"] == "file":
156 try:
157 file_data = open(options["target"], "rb").read()
158 except (IOError, OSError) as e:
159 raise CuckooGuestError("Unable to read {0}, error: "
160 "{1}".format(options["target"], e))
161
162 data = xmlrpclib.Binary(file_data)
163
164 try:
165 self.server.add_malware(data, options["file_name"])
166 except Exception as e:
167 raise CuckooGuestError("{0}: unable to upload malware to "
168 "analysis machine: {1}".format(self.id, e))
169
170
171 pid = self.server.execute()
172 log.debug("%s: analyzer started with PID %d", self.id, pid)
173
174
175 except (socket.timeout, socket.error):
176 raise CuckooGuestError("{0}: guest communication timeout, check "
177 "networking or try to increase "
178 "timeout".format(self.id))
179
181 """Wait for analysis completion.
182 @return: operation status.
183 """
184 log.debug("%s: waiting for completion", self.id)
185
186
187 abort = Event()
188 abort.clear()
189
190 def die():
191 abort.set()
192
193 timer = Timer(self.timeout, die)
194 timer.start()
195 self.server._set_timeout(self.timeout)
196
197 while True:
198 time.sleep(1)
199
200
201
202
203 if abort.is_set():
204 raise CuckooGuestError("The analysis hit the critical timeout,"
205 " terminating")
206
207 try:
208 status = self.server.get_status()
209 except Exception as e:
210 log.debug("%s: error retrieving status: %s", self.id, e)
211 continue
212
213
214 if status == CUCKOO_GUEST_COMPLETED:
215 log.info("%s: analysis completed successfully", self.id)
216 break
217 elif status == CUCKOO_GUEST_FAILED:
218 error = self.server.get_error()
219 if not error:
220 error = "unknown error"
221
222 raise CuckooGuestError("Analysis failed: {0}".format(error))
223 else:
224 log.debug("%s: analysis not completed yet (status=%s)",
225 self.id, status)
226
227 self.server._set_timeout(None)
228