1
2
3
4
5
6 import os
7 import getpass
8 import logging
9 import subprocess
10
11 from lib.cuckoo.common.abstracts import Auxiliary
12 from lib.cuckoo.common.constants import CUCKOO_ROOT, CUCKOO_GUEST_PORT
13 from lib.cuckoo.common.exceptions import CuckooOperationalError
14
15 log = logging.getLogger(__name__)
16
21
23 if not self.machine.interface:
24 log.error("Network interface not defined, network capture aborted")
25 return
26
27
28 if "nictrace" in self.machine.options:
29 return
30
31 tcpdump = self.options.get("tcpdump", "/usr/sbin/tcpdump")
32 bpf = self.options.get("bpf", "")
33 file_path = os.path.join(CUCKOO_ROOT, "storage", "analyses",
34 "%s" % self.task.id, "dump.pcap")
35
36 if not os.path.exists(tcpdump):
37 log.error("Tcpdump does not exist at path \"%s\", network "
38 "capture aborted", tcpdump)
39 return
40
41
42
43
44
45
46
47
48 pargs = [
49 tcpdump, "-U", "-q", "-s", "0", "-n",
50 "-i", self.machine.interface,
51 ]
52
53
54 try:
55 user = getpass.getuser()
56 pargs.extend(["-Z", user])
57 except:
58 pass
59
60 pargs.extend(["-w", file_path])
61 pargs.extend(["host", self.machine.ip])
62
63 if self.task.options.get("sniffer.debug") != "1":
64
65 pargs.extend([
66 "and", "not", "(",
67 "dst", "host", self.machine.ip, "and",
68 "dst", "port", str(CUCKOO_GUEST_PORT),
69 ")", "and", "not", "(",
70 "src", "host", self.machine.ip, "and",
71 "src", "port", str(CUCKOO_GUEST_PORT),
72 ")",
73 ])
74
75
76 pargs.extend([
77 "and", "not", "(",
78 "dst", "host", self.machine.resultserver_ip, "and",
79 "dst", "port", self.machine.resultserver_port,
80 ")", "and", "not", "(",
81 "src", "host", self.machine.resultserver_ip, "and",
82 "src", "port", self.machine.resultserver_port,
83 ")",
84 ])
85
86 if bpf:
87 pargs.extend(["and", "(", bpf, ")"])
88
89 try:
90 self.proc = subprocess.Popen(
91 pargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True
92 )
93 except (OSError, ValueError):
94 log.exception(
95 "Failed to start sniffer (interface=%s, host=%s, pcap=%s)",
96 self.machine.interface, self.machine.ip, file_path,
97 )
98 return
99
100 log.info(
101 "Started sniffer with PID %d (interface=%s, host=%s, pcap=%s)",
102 self.proc.pid, self.machine.interface, self.machine.ip, file_path,
103 )
104
106 if out:
107 raise CuckooOperationalError(
108 "Potential error while running tcpdump, did not expect "
109 "standard output, got: %r." % out
110 )
111
112 err_whitelist = (
113 "packets captured",
114 "packets received by filter",
115 "packets dropped by kernel",
116 )
117
118 for line in err.split("\n"):
119 if not line or line.startswith("tcpdump: listening on "):
120 continue
121
122 if line.endswith(err_whitelist):
123 continue
124
125 raise CuckooOperationalError(
126 "Potential error while running tcpdump, did not expect "
127 "the following standard error output: %r." % line
128 )
129
131 """Stop sniffing.
132 @return: operation status.
133 """
134
135 if not self.proc:
136 return
137
138
139
140 if self.proc.poll():
141 out, err = self.proc.communicate()
142 raise CuckooOperationalError(
143 "Error running tcpdump to sniff the network traffic during "
144 "the analysis; stdout = %r and stderr = %r. Did you enable "
145 "the extra capabilities to allow running tcpdump as non-root "
146 "user and disable AppArmor properly (only applies to Ubuntu)?"
147 % (out, err)
148 )
149
150 try:
151 self.proc.terminate()
152 except:
153 try:
154 if not self.proc.poll():
155 log.debug("Killing sniffer")
156 self.proc.kill()
157 except OSError as e:
158 log.debug("Error killing sniffer: %s. Continue", e)
159 except Exception as e:
160 log.exception("Unable to stop the sniffer with pid %d: %s",
161 self.proc.pid, e)
162
163
164 out, err = self.proc.communicate()
165 self._check_output(out, err)
166