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 MemoryError as e:
167 raise CuckooGuestError("{0}: unable to upload malware to "
168 "analysis machine, not enough "
169 "memory".format(self.id))
170
171
172 pid = self.server.execute()
173 log.debug("%s: analyzer started with PID %d", self.id, pid)
174
175
176 except (socket.timeout, socket.error):
177 raise CuckooGuestError("{0}: guest communication timeout, check "
178 "networking or try to increase "
179 "timeout".format(self.id))
180
182 """Wait for analysis completion.
183 @return: operation status.
184 """
185 log.debug("%s: waiting for completion", self.id)
186
187
188 abort = Event()
189 abort.clear()
190
191 def die():
192 abort.set()
193
194 timer = Timer(self.timeout, die)
195 timer.start()
196 self.server._set_timeout(self.timeout)
197
198 while True:
199 time.sleep(1)
200
201
202
203
204 if abort.is_set():
205 raise CuckooGuestError("The analysis hit the critical timeout,"
206 " terminating")
207
208 try:
209 status = self.server.get_status()
210 except Exception as e:
211 log.debug("%s: error retrieving status: %s", self.id, e)
212 continue
213
214
215 if status == CUCKOO_GUEST_COMPLETED:
216 log.info("%s: analysis completed successfully", self.id)
217 break
218 elif status == CUCKOO_GUEST_FAILED:
219 error = self.server.get_error()
220 if not error:
221 error = "unknown error"
222
223 raise CuckooGuestError("Analysis failed: {0}".format(error))
224 else:
225 log.debug("%s: analysis not completed yet (status=%s)",
226 self.id, status)
227
228 self.server._set_timeout(None)
229