Package modules :: Package auxiliary :: Module sniffer
[hide private]
[frames] | no frames]

Source Code for Module modules.auxiliary.sniffer

  1  # Copyright (C) 2010-2013 Claudio Guarnieri. 
  2  # Copyright (C) 2014-2016 Cuckoo Foundation. 
  3  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  4  # See the file 'docs/LICENSE' for copying permission. 
  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   
17 -class Sniffer(Auxiliary):
18 - def __init__(self):
19 Auxiliary.__init__(self) 20 self.proc = None
21
22 - def start(self):
23 if not self.machine.interface: 24 log.error("Network interface not defined, network capture aborted") 25 return 26 27 # Handle special pcap dumping options. 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 # TODO: this isn't working. need to fix. 42 # mode = os.stat(tcpdump)[stat.ST_MODE] 43 # if (mode & stat.S_ISUID) == 0: 44 # log.error("Tcpdump is not accessible from this user, " 45 # "network capture aborted") 46 # return 47 48 pargs = [ 49 tcpdump, "-U", "-q", "-s", "0", "-n", 50 "-i", self.machine.interface, 51 ] 52 53 # Trying to save pcap with the same user which cuckoo is running. 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 # Do not capture Agent traffic. 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 # Do not capture ResultServer traffic. 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
105 - def _check_output(self, out, err):
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
130 - def stop(self):
131 """Stop sniffing. 132 @return: operation status. 133 """ 134 # The tcpdump process was never started in the first place. 135 if not self.proc: 136 return 137 138 # The tcpdump process has already quit, generally speaking this 139 # indicates an error such as "permission denied". 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 # Ensure expected output was received from tcpdump. 164 out, err = self.proc.communicate() 165 self._check_output(out, err)
166