1
2
3
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
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"):
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
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
65
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
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
86
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
95
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
111
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
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
127 if options["category"] == "file":
128 options["file_name"] = sanitize_filename(options["file_name"])
129
130
131
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
138 options["port"] = str(ResultServer().port)
139
140 try:
141
142
143
144 self.wait(CUCKOO_GUEST_INIT)
145
146
147 self.upload_analyzer()
148
149
150
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
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
174 pid = self.server.execute()
175 log.debug("%s: analyzer started with PID %d", self.id, pid)
176
177
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
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
196
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
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