def check_arp_reply(self, pkt): data = parse_data_pkt(pkt, self.tk) try: data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, pkt.addr3) except (ICVError, MICError): return decoded_pkt = LLC(data_clear) log_runtime.debug(hexdump(decoded_pkt, dump=True)) log_runtime.debug(repr(decoded_pkt)) self.deal_common_pkt(decoded_pkt) if ARP not in decoded_pkt: return # ARP.op 2: is-at if decoded_pkt[ARP].op == 2 and \ decoded_pkt[ARP].psrc == self.arp_target_ip and \ decoded_pkt[ARP].pdst == self.arp_source_ip: # Got the expected ARP if self.krack_state & 4 == 0: # First time, normal behavior log_runtime.info("Got ARP reply, this is normal") self.krack_state |= 4 log_runtime.info("Trying to trigger CVE-2017-13080") raise self.RENEW_GTK() else: # Second time, the packet has been accepted twice! log_runtime.warning("Broadcast packet accepted twice!! " "(CVE-2017-13080)")
def rem(self, session): s = self.find(session) if s: log_runtime.info("TLS: previous session shall not be overwritten") return h = session.hash() self.sessions[h].remove(session)
def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg): """Sniff packets sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets Select interface to sniff by setting conf.iface. Use show_interfaces() to see interface names. count: number of packets to capture. 0 means infinity store: wether to store sniffed packets or discard them prn: function to apply to each packet. If something is returned, it is displayed. Ex: ex: prn = lambda x: x.summary() lfilter: python function applied to each packet to determine if further action may be done ex: lfilter = lambda x: x.haslayer(Padding) offline: pcap file to read packets from, instead of sniffing them timeout: stop sniffing after a given time (default: None) L2socket: use the provided L2socket """ c = 0 if offline is None: log_runtime.info('Sniffing on %s' % conf.iface) if L2socket is None: L2socket = conf.L2listen s = L2socket(type=ETH_P_ALL, *arg, **karg) else: s = PcapReader(offline) lst = [] if timeout is not None: stoptime = time.time()+timeout remain = None while 1: try: if timeout is not None: remain = stoptime-time.time() if remain <= 0: break try: p = s.recv(MTU) except PcapTimeoutElapsed: continue if p is None: break if lfilter and not lfilter(p): continue if store: lst.append(p) c += 1 if prn: r = prn(p) if r is not None: print(r) if count > 0 and c >= count: break except KeyboardInterrupt: break s.close() return plist.PacketList(lst,"Sniffed")
def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None, replay_args=None, # noqa: E501 parse_results=False): """Send packets at layer 2 using tcpreplay for performance pps: packets per second mpbs: MBits per second realtime: use packet's timestamp, bending time with real-time value loop: number of times to process the packet list file_cache: cache packets in RAM instead of reading from disk at each iteration # noqa: E501 iface: output interface replay_args: List of additional tcpreplay args (List[str]) parse_results: Return a dictionary of information outputted by tcpreplay (default=False) # noqa: E501 :returns stdout, stderr, command used""" if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % iface] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--preload-pcap") # Check for any additional args we didn't cover. if replay_args is not None: argv.extend(replay_args) f = get_temp_file() argv.append(f) wrpcap(f, x) results = None with ContextManagerSubprocess("sendpfast()", conf.prog.tcpreplay): try: cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception: os.unlink(f) raise else: stdout, stderr = cmd.communicate() if stderr: log_runtime.warning(stderr.decode()) if parse_results: results = _parse_tcpreplay_result(stdout, stderr, argv) elif conf.verb > 2: log_runtime.info(stdout.decode()) os.unlink(f) return results
def post_dissection(self, r): if not self.tls_session.frozen: for kse in self.client_shares: if kse.pubkey: pubshares = self.tls_session.tls13_client_pubshares if _tls_named_curves[kse.group] in pubshares: pkt_info = r.firstlayer().summary() log_runtime.info("TLS: group %s used twice in the same ClientHello [%s]", kse.group, pkt_info) break pubshares[_tls_named_curves[kse.group]] = kse.pubkey return super(TLS_Ext_KeyShare_CH, self).post_dissection(r)
def post_build(self, pkt, pay): if not self.tls_session.frozen: privshares = self.tls_session.tls13_client_privshares for kse in self.client_shares: if kse.privkey: if _tls_named_curves[kse.group] in privshares: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: group %s used twice in the same ClientHello [%s]", kse.group, pkt_info) break privshares[_tls_named_groups[kse.group]] = kse.privkey return super(TLS_Ext_KeyShare_CH, self).post_build(pkt, pay)
def find(self, session): h = session.hash() if h in self.sessions: for k in self.sessions[h]: if k.eq(session): if conf.tls_verbose: log_runtime.info("TLS: found session matching %s", k) return k if conf.tls_verbose: log_runtime.info("TLS: did not find session matching %s", session) return None
def add(self, session): s = self.find(session) if s: log_runtime.info("TLS: previous session shall not be overwritten") return h = session.hash() if h in self.sessions: self.sessions[h].append(session) else: self.sessions[h] = [session]
def post_dissection(self, r): if not self.tls_session.frozen: for kse in self.client_shares: if kse.pubkey: pubshares = self.tls_session.tls13_client_pubshares if _tls_named_curves[kse.group] in pubshares: pkt_info = r.firstlayer().summary() log_runtime.info("TLS: group %s used twice in the same ClientHello [%s]", kse.group, pkt_info) break pubshares[_tls_named_curves[kse.group]] = kse.pubkey return super(TLS_Ext_KeyShare_CH, self).post_dissection(r)
def find(self, session): h = session.hash() if h in self.sessions: for k in self.sessions[h]: if k.eq(session): if conf.tls_verbose: log_runtime.info("TLS: found session matching %s", k) return k if conf.tls_verbose: log_runtime.info("TLS: did not find session matching %s", session) return None
def post_build(self, pkt, pay): if not self.tls_session.frozen: privshares = self.tls_session.tls13_client_privshares for kse in self.client_shares: if kse.privkey: if _tls_named_curves[kse.group] in privshares: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: group %s used twice in the same ClientHello [%s]", kse.group, pkt_info) break privshares[_tls_named_groups[kse.group]] = kse.privkey return super(TLS_Ext_KeyShare_CH, self).post_build(pkt, pay)
def add(self, session): s = self.find(session) if s: log_runtime.info("TLS: previous session shall not be overwritten") return h = session.hash() if h in self.sessions: self.sessions[h].append(session) else: self.sessions[h] = [session]
def m2i(self, pkt, s): ret_s = list() tmp_s = s # RDATA contains a list of strings, each are prepended with # a byte containing the size of the following string. while tmp_s: tmp_len = orb(tmp_s[0]) + 1 if tmp_len > len(tmp_s): log_runtime.info( "DNS RR TXT prematured end of character-string " "(size=%i, remaining bytes=%i)", tmp_len, len(tmp_s)) ret_s.append(tmp_s[1:tmp_len]) tmp_s = tmp_s[tmp_len:] return ret_s
def pre_dissect(self, s): if len(s) < 2: raise Exception("Invalid record: header is too short.") msglen = struct.unpack("!H", s[:2])[0] if msglen & 0x8000: hdrlen = 2 msglen_clean = msglen & 0x7fff else: hdrlen = 3 msglen_clean = msglen & 0x3fff hdr = s[:hdrlen] efrag = s[hdrlen:hdrlen + msglen_clean] self.protected_record = s[:hdrlen + msglen_clean] r = s[hdrlen + msglen_clean:] mac = pad = "" cipher_type = self.tls_session.rcs.cipher.type # Decrypt (with implicit IV if block cipher) mfrag = self._tls_decrypt(efrag) # Extract MAC maclen = self.tls_session.rcs.mac_len if maclen == 0: mac, pfrag = "", mfrag else: mac, pfrag = mfrag[:maclen], mfrag[maclen:] # Extract padding padlen = 0 if hdrlen == 3: padlen = struct.unpack("B", s[2])[0] if padlen == 0: cfrag, pad = pfrag, "" else: cfrag, pad = pfrag[:-padlen], pfrag[-padlen:] # Verify integrity is_mac_ok = self._sslv2_mac_verify(cfrag + pad, mac) if not is_mac_ok: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) reconstructed_body = mac + cfrag + pad return hdr + reconstructed_body + r
def krack_dispatch(self): now = time.time() # Handshake 3/4 replay if self.double_3handshake and (self.krack_state & 1 == 0) and \ (now - self.time_handshake_end) > self.wait_3handshake: log_runtime.info("Trying to trigger CVE-2017-13077") raise self.ANALYZE_DATA().action_parameters(send_3handshake=True) # GTK rekeying if (self.krack_state & 2 == 0) and \ (now - self.time_handshake_end) > self.wait_gtk: raise self.ANALYZE_DATA().action_parameters(send_gtk=True) # Fallback in data analysis raise self.ANALYZE_DATA().action_parameters()
def krack_dispatch(self): now = time.time() # Handshake 3/4 replay if self.double_3handshake and (self.krack_state & 1 == 0) and \ (now - self.time_handshake_end) > self.wait_3handshake: log_runtime.info("Trying to trigger CVE-2017-13077") raise self.ANALYZE_DATA().action_parameters(send_3handshake=True) # GTK rekeying if (self.krack_state & 2 == 0) and \ (now - self.time_handshake_end) > self.wait_gtk: raise self.ANALYZE_DATA().action_parameters(send_gtk=True) # Fallback in data analysis raise self.ANALYZE_DATA().action_parameters()
def pre_dissect(self, s): if len(s) < 2: raise Exception("Invalid record: header is too short.") msglen = struct.unpack("!H", s[:2])[0] if msglen & 0x8000: hdrlen = 2 msglen_clean = msglen & 0x7fff else: hdrlen = 3 msglen_clean = msglen & 0x3fff hdr = s[:hdrlen] efrag = s[hdrlen:hdrlen+msglen_clean] self.protected_record = s[:hdrlen+msglen_clean] r = s[hdrlen+msglen_clean:] mac = pad = b"" cipher_type = self.tls_session.rcs.cipher.type # Decrypt (with implicit IV if block cipher) mfrag = self._tls_decrypt(efrag) # Extract MAC maclen = self.tls_session.rcs.mac_len if maclen == 0: mac, pfrag = b"", mfrag else: mac, pfrag = mfrag[:maclen], mfrag[maclen:] # Extract padding padlen = 0 if hdrlen == 3: padlen = orb(s[2]) if padlen == 0: cfrag, pad = pfrag, b"" else: cfrag, pad = pfrag[:-padlen], pfrag[-padlen:] # Verify integrity is_mac_ok = self._sslv2_mac_verify(cfrag + pad, mac) if not is_mac_ok: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) reconstructed_body = mac + cfrag + pad return hdr + reconstructed_body + r
def extract_iv(self, pkt): # Get IV TSC, _, _ = parse_TKIP_hdr(pkt) iv = TSC[0] | (TSC[1] << 8) | (TSC[2] << 16) | (TSC[3] << 24) | \ (TSC[4] << 32) | (TSC[5] << 40) log_runtime.info("Got a packet with IV: %s", hex(iv)) if self.last_iv is None: self.last_iv = iv else: if iv <= self.last_iv: log_runtime.warning("IV re-use!! Client seems to be " "vulnerable to handshake 3/4 replay " "(CVE-2017-13077)" ) data_clear = None # Normal decoding data = parse_data_pkt(pkt, self.tk) try: data_clear = check_MIC_ICV(data, self.mic_sta_to_ap, pkt.addr2, pkt.addr3) except (ICVError, MICError): pass # Decoding with a 0's TK if data_clear is None: data = parse_data_pkt(pkt, "\x00" * len(self.tk)) try: mic_key = "\x00" * len(self.mic_sta_to_ap) data_clear = check_MIC_ICV(data, mic_key, pkt.addr2, pkt.addr3) log_runtime.warning("Client has installed an all zero " "encryption key (TK)!!") except (ICVError, MICError): pass if data_clear is None: log_runtime.warning("Unable to decode the packet, something went " "wrong") log_runtime.debug(hexdump(pkt, dump=True)) self.deal_common_pkt(pkt) return log_runtime.debug(hexdump(data_clear, dump=True)) pkt = LLC(data_clear) log_runtime.debug(repr(pkt)) self.deal_common_pkt(pkt)
def post_dissection_tls_session_update(self, msg_str): self.tls_session_update(msg_str) s = self.tls_session test = (len(s.client_certs) > 0 and s.sslv2_key_material is not None and s.sslv2_challenge_clientcert is not None and len(s.server_certs) > 0) if test: m = (s.sslv2_key_material + s.sslv2_challenge_clientcert + s.server_certs[0].der) sig_test = self.responsedata._verify_sig(m, s.client_certs[0]) if not sig_test: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: invalid client CertificateVerify signature [%s]", pkt_info) # noqa: E501
def post_dissection_tls_session_update(self, msg_str): self.tls_session_update(msg_str) s = self.tls_session test = (len(s.client_certs) > 0 and s.sslv2_key_material is not None and s.sslv2_challenge_clientcert is not None and len(s.server_certs) > 0) if test: m = (s.sslv2_key_material + s.sslv2_challenge_clientcert + s.server_certs[0].der) sig_test = self.responsedata._verify_sig(m, s.client_certs[0]) if not sig_test: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: invalid client CertificateVerify signature [%s]", pkt_info)
def _tls_auth_decrypt(self, s): """ Provided with the record header and AEAD-ciphered data, return the sliced and clear tuple (TLSInnerPlaintext, tag). Note that we still return the slicing of the original input in case of decryption failure. Also, if the integrity check fails, a warning will be issued, but we still return the sliced (unauthenticated) plaintext. """ rcs = self.tls_session.rcs read_seq_num = struct.pack("!Q", rcs.seq_num) rcs.seq_num += 1 try: return rcs.cipher.auth_decrypt(b"", s, read_seq_num) except CipherError as e: return e.args except AEADTagError as e: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) return e.args
def _tls_auth_decrypt(self, s): """ Provided with the record header and AEAD-ciphered data, return the sliced and clear tuple (TLSInnerPlaintext, tag). Note that we still return the slicing of the original input in case of decryption failure. Also, if the integrity check fails, a warning will be issued, but we still return the sliced (unauthenticated) plaintext. """ rcs = self.tls_session.rcs read_seq_num = struct.pack("!Q", rcs.seq_num) rcs.seq_num += 1 try: return rcs.cipher.auth_decrypt(b"", s, read_seq_num) except CipherError as e: return e.args except AEADTagError as e: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) return e.args
def post_dissection(self, pkt): s = self.tls_session if not s.frozen: handshake_msg = "".join(s.handshake_messages) if s.tls_version < 0x0304 and s.master_secret is not None: ms = s.master_secret con_end = s.connection_end verify_data = s.rcs.prf.compute_verify_data( con_end, "read", handshake_msg, ms) if self.vdata != verify_data: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: invalid Finished received [%s]", pkt_info) elif s.tls_version >= 0x0304: con_end = s.connection_end verify_data = s.compute_tls13_verify_data(con_end, "read") if self.vdata != verify_data: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: invalid Finished received [%s]", pkt_info)
def post_dissection(self, pkt): """ While previously dissecting Server*DHParams, the session server_kx_pubkey should have been updated. XXX Add a 'fixed_dh' OR condition to the 'anonymous' test. """ s = self.tls_session if s.prcs and s.prcs.key_exchange.no_ske: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: useless ServerKeyExchange [%s]", pkt_info) if (s.prcs and not s.prcs.key_exchange.anonymous and s.client_random and s.server_random and s.server_certs and len(s.server_certs) > 0): m = s.client_random + s.server_random + str(self.params) sig_test = self.sig._verify_sig(m, s.server_certs[0]) if not sig_test: pkt_info = pkt.firstlayer().summary() log_runtime.info( "TLS: invalid ServerKeyExchange signature [%s]", pkt_info)
def _sndrcv_snd(pks, timeout, inter, verbose, tobesent, stopevent): """Function used in the sending thread of sndrcv()""" try: i = 0 if verbose: print("Begin emission:") for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print("Finished to send %i packets." % i) except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.info("--- Error sending packets", exc_info=True) if timeout is not None: stopevent.wait(timeout) stopevent.set()
def _sndrcv_snd(pks, timeout, inter, verbose, tobesent, stopevent): """Function used in the sending thread of sndrcv()""" try: i = 0 if verbose: print("Begin emission:") for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print("Finished to send %i packets." % i) except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.info("--- Error sending packets", exc_info=True) if timeout is not None: stopevent.wait(timeout) stopevent.set()
def pre_dissect(self, s): """ Check that a valid DNS over TCP message can be decoded """ if isinstance(self.underlayer, TCP): # Compute the length of the DNS packet if len(s) >= 2: dns_len = struct.unpack("!H", s[:2])[0] else: message = "Malformed DNS message: too small!" log_runtime.info(message) raise Scapy_Exception(message) # Check if the length is valid if dns_len < 14 or len(s) < dns_len: message = "Malformed DNS message: invalid length!" log_runtime.info(message) raise Scapy_Exception(message) return s
def pretty_list(rtlst, header, sortBy=0): """Pretty list to fit the terminal, and add header""" _space = " " # Windows has a fat terminal border _spacelen = len(_space) * (len(header) - 1) + (10 if WINDOWS else 0) _croped = False # Sort correctly rtlst.sort(key=lambda x: x[sortBy]) # Append tag rtlst = header + rtlst # Detect column's width colwidth = [max([len(y) for y in x]) for x in zip(*rtlst)] # Make text fit in box (if required) width = get_terminal_width() if conf.auto_crop_tables and width: width = width - _spacelen while sum(colwidth) > width: _croped = True # Needs to be cropped # Get the longest row i = colwidth.index(max(colwidth)) # Get all elements of this row row = [len(x[i]) for x in rtlst] # Get biggest element of this row: biggest of the array j = row.index(max(row)) # Re-build column tuple with the edited element t = list(rtlst[j]) t[i] = t[i][:-2] + "_" rtlst[j] = tuple(t) # Update max size row[j] = len(t[i]) colwidth[i] = max(row) if _croped: log_runtime.info( "Table cropped to fit the terminal (conf.auto_crop_tables==True)") # Generate padding scheme fmt = _space.join(["%%-%ds" % x for x in colwidth]) # Compile rt = "\n".join(((fmt % x).strip() for x in rtlst)) return rt
def post_dissection(self, r): if not self.tls_session.frozen and self.server_share.pubkey: # if there is a pubkey, we assume the crypto library is ok pubshare = self.tls_session.tls13_server_pubshare if len(pubshare) > 0: pkt_info = r.firstlayer().summary() log_runtime.info("TLS: overwriting previous server key share [%s]", pkt_info) group_name = _tls_named_groups[self.server_share.group] pubshare[group_name] = self.server_share.pubkey if group_name in self.tls_session.tls13_client_privshares: pubkey = self.server_share.pubkey privkey = self.tls_session.tls13_client_privshares[group_name] if group_name in six.itervalues(_tls_named_ffdh_groups): pms = privkey.exchange(pubkey) elif group_name in six.itervalues(_tls_named_curves): if group_name == "x25519": pms = privkey.exchange(pubkey) else: pms = privkey.exchange(ec.ECDH(), pubkey) self.tls_session.tls13_dhe_secret = pms return super(TLS_Ext_KeyShare_SH, self).post_dissection(r)
def getfield(self, pkt, s): if isinstance(s, tuple): s, p = s else: p = 0 ret = None c = getattr(pkt, self.countfld) if c > len(s): log_runtime.info("DNS wrong value: DNS.%s=%i", self.countfld, c) return s, b"" while c: c -= 1 name, p, _, _ = dns_get_str(s, p, _fullpacket=True) rr, p = self.decodeRR(name, s, p) if ret is None: ret = rr else: ret.add_payload(rr) if self.passon: return (s, p), ret else: return s[p:], ret
def __init__(self, type=ETH_P_IP, filter=None, iface=None, promisc=None, nofilter=0): # noqa: E501 self.outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) # noqa: E501 self.outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1) self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) # noqa: E501 self.iface = iface if iface is not None: self.ins.bind((self.iface, type)) if not six.PY2: try: # Receive Auxiliary Data (VLAN tags) self.ins.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1) self.ins.setsockopt( socket.SOL_SOCKET, SO_TIMESTAMPNS, 1 ) self.auxdata_available = True except OSError: # Note: Auxiliary Data is only supported since # Linux 2.6.21 msg = "Your Linux Kernel does not support Auxiliary Data!" log_runtime.info(msg)
def send_arp_req(self): if self.krack_state & 4 == 0: # Set the address for future uses self.arp_target_ip = self.dhcp_server.leases.get(self.client, self.arp_target_ip) assert self.arp_target_ip is not None # Send the first ARP requests, for control test log_runtime.info("Send ARP who-was from '%s' to '%s'", self.arp_source_ip, self.arp_target_ip) arp_pkt = self.send_wpa_to_group( LLC()/SNAP()/ARP(op="who-has", psrc=self.arp_source_ip, pdst=self.arp_target_ip, hwsrc=self.mac), dest='ff:ff:ff:ff:ff:ff', ) self.arp_sent.append(arp_pkt) else: if self.arp_to_send < len(self.arp_sent): # Re-send the ARP requests already sent self.send(self.arp_sent[self.arp_to_send]) self.arp_to_send += 1 else: # Re-send GTK self.arp_to_send = 0 self.arp_retry += 1 log_runtime.info("Trying to trigger CVE-2017-13080 %d/%d", self.arp_retry, self.ARP_MAX_RETRY) if self.arp_retry > self.ARP_MAX_RETRY: # We retries 100 times to send GTK, then already sent ARPs log_runtime.warning("Client is likely not vulnerable to " "CVE-2017-13080") raise self.EXIT() raise self.RENEW_GTK()
def bitmap2RRlist(bitmap): """ Decode the 'Type Bit Maps' field of the NSEC Resource Record into an integer list. """ # RFC 4034, 4.1.2. The Type Bit Maps Field RRlist = [] while bitmap: if len(bitmap) < 2: log_runtime.info("bitmap too short (%i)", len(bitmap)) return window_block = orb(bitmap[0]) # window number offset = 256 * window_block # offset of the Resource Record bitmap_len = orb(bitmap[1]) # length of the bitmap in bytes if bitmap_len <= 0 or bitmap_len > 32: log_runtime.info("bitmap length is no valid (%i)", bitmap_len) return tmp_bitmap = bitmap[2:2 + bitmap_len] # Let's compare each bit of tmp_bitmap and compute the real RR value for b in range(len(tmp_bitmap)): v = 128 for i in range(8): if orb(tmp_bitmap[b]) & v: # each of the RR is encoded as a bit RRlist += [offset + b * 8 + i] v = v >> 1 # Next block if any bitmap = bitmap[2 + bitmap_len:] return RRlist
def deal_common_pkt(self, pkt): # Send to DHCP server # LLC / SNAP to Ether if SNAP in pkt: ether_pkt = Ether(src=self.client,dst=self.mac) / pkt[SNAP].payload self.dhcp_server.reply(ether_pkt) # If an ARP request is made, extract client IP and answer if ARP in pkt and \ pkt[ARP].op == 1 and pkt[ARP].pdst == self.dhcp_server.gw: if self.arp_target_ip is None: self.arp_target_ip = pkt[ARP].psrc log_runtime.info("Detected IP: %s", self.arp_target_ip) # Reply ARP_ans = LLC()/SNAP()/ARP( op="is-at", psrc=self.arp_source_ip, pdst=self.arp_target_ip, hwsrc=self.mac, hwdst=self.client, ) self.send_wpa_to_client(ARP_ans)
def _tls_auth_decrypt(self, hdr, s): """ Provided with the record header and AEAD-ciphered data, return the sliced and clear tuple (nonce, TLSCompressed.fragment, mac). Note that we still return the slicing of the original input in case of decryption failure. Also, if the integrity check fails, a warning will be issued, but we still return the sliced (unauthenticated) plaintext. """ try: read_seq_num = struct.pack("!Q", self.tls_session.rcs.seq_num) self.tls_session.rcs.seq_num += 1 # self.type and self.version have not been parsed yet, # this is why we need to look into the provided hdr. add_data = read_seq_num + chb(hdr[0]) + hdr[1:3] # Last two bytes of add_data are appended by the return function return self.tls_session.rcs.cipher.auth_decrypt(add_data, s, read_seq_num) except CipherError as e: return e.args except AEADTagError as e: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) # noqa: E501 return e.args
def _tls_auth_decrypt(self, hdr, s): """ Provided with the record header and AEAD-ciphered data, return the sliced and clear tuple (nonce, TLSCompressed.fragment, mac). Note that we still return the slicing of the original input in case of decryption failure. Also, if the integrity check fails, a warning will be issued, but we still return the sliced (unauthenticated) plaintext. """ try: read_seq_num = struct.pack("!Q", self.tls_session.rcs.seq_num) self.tls_session.rcs.seq_num += 1 # self.type and self.version have not been parsed yet, # this is why we need to look into the provided hdr. add_data = read_seq_num + chb(hdr[0]) + hdr[1:3] # Last two bytes of add_data are appended by the return function return self.tls_session.rcs.cipher.auth_decrypt(add_data, s, read_seq_num) except CipherError as e: return e.args except AEADTagError as e: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) # noqa: E501 return e.args
def post_dissection(self, pkt): s = self.tls_session if s.sslv2_challenge is not None: if self.challenge != s.sslv2_challenge: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: invalid ServerVerify received [%s]", pkt_info) # noqa: E501
def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0, monitor=None): self.iface = network_name(iface or conf.iface) self.type = type self.promisc = conf.sniff_promisc if promisc is None else promisc if monitor is not None: log_runtime.info( "The 'monitor' argument has no effect on native linux sockets." ) self.ins = socket.socket( socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: try: attach_filter(self.ins, filter, iface) except ImportError as ex: log_runtime.error("Cannot set filter: %s", ex) if self.promisc: set_promisc(self.ins, self.iface) self.ins.bind((self.iface, type)) _flush_fd(self.ins) self.ins.setsockopt( socket.SOL_SOCKET, socket.SO_RCVBUF, conf.bufsize ) if not six.PY2: # Receive Auxiliary Data (VLAN tags) try: self.ins.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1) self.ins.setsockopt( socket.SOL_SOCKET, SO_TIMESTAMPNS, 1 ) self.auxdata_available = True except OSError: # Note: Auxiliary Data is only supported since # Linux 2.6.21 msg = "Your Linux Kernel does not support Auxiliary Data!" log_runtime.info(msg) if isinstance(self, L2ListenSocket): self.outs = None else: self.outs = self.ins self.outs.setsockopt( socket.SOL_SOCKET, socket.SO_SNDBUF, conf.bufsize ) sa_ll = self.ins.getsockname() if sa_ll[3] in conf.l2types: self.LL = conf.l2types[sa_ll[3]] self.lvl = 2 elif sa_ll[1] in conf.l3types: self.LL = conf.l3types[sa_ll[1]] self.lvl = 3 else: self.LL = conf.default_l2 self.lvl = 2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], self.LL.name) # noqa: E501
def pre_dissect(self, s): """ Decrypt, verify and decompress the message, i.e. apply the previous methods according to the reading cipher type. If the decryption was successful, 'len' will be the length of the TLSPlaintext.fragment. Else, it should be the length of the _TLSEncryptedContent. """ if len(s) < 5: raise Exception("Invalid record: header is too short.") msglen = struct.unpack('!H', s[3:5])[0] hdr, efrag, r = s[:5], s[5:5 + msglen], s[msglen + 5:] iv = mac = pad = b"" self.padlen = None decryption_success = False cipher_type = self.tls_session.rcs.cipher.type if cipher_type == 'block': version = struct.unpack("!H", s[1:3])[0] # Decrypt try: if version >= 0x0302: # Explicit IV for TLS 1.1 and 1.2 block_size = self.tls_session.rcs.cipher.block_size iv, efrag = efrag[:block_size], efrag[block_size:] self.tls_session.rcs.cipher.iv = iv pfrag = self._tls_decrypt(efrag) else: # Implicit IV for SSLv3 and TLS 1.0 pfrag = self._tls_decrypt(efrag) except CipherError as e: # This will end up dissected as _TLSEncryptedContent. cfrag = e.args[0] else: decryption_success = True # Excerpt below better corresponds to TLS 1.1 IV definition, # but the result is the same as with TLS 1.2 anyway. # This leading *IV* has been decrypted by _tls_decrypt with a # random IV, hence it does not correspond to anything. # What actually matters is that we got the first encrypted block # noqa: E501 # in order to decrypt the second block (first data block). # if version >= 0x0302: # block_size = self.tls_session.rcs.cipher.block_size # iv, pfrag = pfrag[:block_size], pfrag[block_size:] # l = struct.unpack('!H', hdr[3:5])[0] # hdr = hdr[:3] + struct.pack('!H', l-block_size) # Extract padding ('pad' actually includes the trailing padlen) padlen = orb(pfrag[-1]) + 1 mfrag, pad = pfrag[:-padlen], pfrag[-padlen:] self.padlen = padlen # Extract MAC tmp_len = self.tls_session.rcs.mac_len if tmp_len != 0: cfrag, mac = mfrag[:-tmp_len], mfrag[-tmp_len:] else: cfrag, mac = mfrag, b"" # Verify integrity chdr = hdr[:3] + struct.pack('!H', len(cfrag)) is_mac_ok = self._tls_hmac_verify(chdr, cfrag, mac) if not is_mac_ok: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) # noqa: E501 elif cipher_type == 'stream': # Decrypt try: pfrag = self._tls_decrypt(efrag) except CipherError as e: # This will end up dissected as _TLSEncryptedContent. cfrag = e.args[0] else: decryption_success = True mfrag = pfrag # Extract MAC tmp_len = self.tls_session.rcs.mac_len if tmp_len != 0: cfrag, mac = mfrag[:-tmp_len], mfrag[-tmp_len:] else: cfrag, mac = mfrag, b"" # Verify integrity chdr = hdr[:3] + struct.pack('!H', len(cfrag)) is_mac_ok = self._tls_hmac_verify(chdr, cfrag, mac) if not is_mac_ok: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) # noqa: E501 elif cipher_type == 'aead': # Authenticated encryption # crypto/cipher_aead.py prints a warning for integrity failure if (conf.crypto_valid_advanced and isinstance(self.tls_session.rcs.cipher, Cipher_CHACHA20_POLY1305)): # noqa: E501 iv = b"" cfrag, mac = self._tls_auth_decrypt(hdr, efrag) else: iv, cfrag, mac = self._tls_auth_decrypt(hdr, efrag) decryption_success = True # see XXX above frag = self._tls_decompress(cfrag) if (decryption_success and not isinstance(self.tls_session.rcs.cipher, Cipher_NULL)): self.deciphered_len = len(frag) else: self.deciphered_len = None reconstructed_body = iv + frag + mac + pad return hdr + reconstructed_body + r
def post_dissection(self, pkt): s = self.tls_session if s.sslv2_connection_id is not None: if self.connection_id != s.sslv2_connection_id: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: invalid client Finished received [%s]", pkt_info) # noqa: E501
def dns_get_str(s, pointer=0, pkt=None, _fullpacket=False): """This function decompresses a string s, starting from the given pointer. :param s: the string to decompress :param pointer: first pointer on the string (default: 0) :param pkt: (optional) an InheritOriginDNSStrPacket packet :returns: (decoded_string, end_index, left_string) """ # The _fullpacket parameter is reserved for scapy. It indicates # that the string provided is the full dns packet, and thus # will be the same than pkt._orig_str. The "Cannot decompress" # error will not be prompted if True. max_length = len(s) # The result = the extracted name name = b"" # Will contain the index after the pointer, to be returned after_pointer = None processed_pointers = [] # Used to check for decompression loops # Analyse given pkt if pkt and hasattr(pkt, "_orig_s") and pkt._orig_s: s_full = pkt._orig_s else: s_full = None bytes_left = None while True: if abs(pointer) >= max_length: log_runtime.info("DNS RR prematured end (ofs=%i, len=%i)", pointer, len(s)) break cur = orb(s[pointer]) # get pointer value pointer += 1 # make pointer go forward if cur & 0xc0: # Label pointer if after_pointer is None: # after_pointer points to where the remaining bytes start, # as pointer will follow the jump token after_pointer = pointer + 1 if pointer >= max_length: log_runtime.info("DNS incomplete jump token at (ofs=%i)", pointer) break # Follow the pointer pointer = ((cur & ~0xc0) << 8) + orb(s[pointer]) - 12 if pointer in processed_pointers: warning("DNS decompression loop detected") break if not _fullpacket: # Do we have access to the whole packet ? if s_full: # Yes -> use it to continue bytes_left = s[after_pointer:] s = s_full max_length = len(s) _fullpacket = True else: # No -> abort raise Scapy_Exception("DNS message can't be compressed " + "at this point!") processed_pointers.append(pointer) continue elif cur > 0: # Label # cur = length of the string name += s[pointer:pointer + cur] + b"." pointer += cur else: break if after_pointer is not None: # Return the real end index (not the one we followed) pointer = after_pointer if bytes_left is None: bytes_left = s[pointer:] # name, end_index, remaining return name, pointer, bytes_left, len(processed_pointers) != 0
def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) if verbose is None: verbose = conf.verb debug.recv = plist.PacketList([],"Unanswered") debug.sent = plist.PacketList([],"Sent") debug.match = plist.SndRcvList([]) nbrecv=0 ans = [] # do it here to fix random fields, so that parent and child have the same all_stimuli = tobesent = [p for p in pkt] notans = len(tobesent) hsent={} for i in tobesent: h = i.hashret() if h in hsent: hsent[h].append(i) else: hsent[h] = [i] if retry < 0: retry = -retry autostop=retry else: autostop=0 while retry >= 0: found=0 if timeout < 0: timeout = None rdpipe,wrpipe = os.pipe() rdpipe=os.fdopen(rdpipe) wrpipe=os.fdopen(wrpipe,"w") pid=1 try: pid = os.fork() if pid == 0: try: sys.stdin.close() rdpipe.close() try: i = 0 if verbose: print("Begin emission:") for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print("Finished to send %i packets." % i) except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.exception("--- Error in child %i" % os.getpid()) log_runtime.info("--- Error in child %i" % os.getpid()) finally: try: os.setpgrp() # Chance process group to avoid ctrl-C sent_times = [p.sent_time for p in all_stimuli if p.sent_time] six.moves.cPickle.dump( (conf.netcache,sent_times), wrpipe ) wrpipe.close() except: pass elif pid < 0: log_runtime.error("fork error") else: wrpipe.close() stoptime = 0 remaintime = None inmask = [rdpipe,pks] try: try: while True: if stoptime: remaintime = stoptime-time.time() if remaintime <= 0: break r = None if conf.use_bpf: from scapy.arch.bpf.supersocket import bpf_select inp = bpf_select(inmask) if pks in inp: r = pks.recv() elif not isinstance(pks, StreamSocket) and (FREEBSD or DARWIN or OPENBSD): inp, out, err = select(inmask,[],[], 0.05) if len(inp) == 0 or pks in inp: r = pks.nonblock_recv() else: inp = [] try: inp, out, err = select(inmask,[],[], remaintime) except (IOError, select_error) as exc: # select.error has no .errno attribute if exc.args[0] != errno.EINTR: raise if len(inp) == 0: break if pks in inp: r = pks.recv(MTU) if rdpipe in inp: if timeout: stoptime = time.time()+timeout del(inmask[inmask.index(rdpipe)]) if r is None: continue ok = 0 h = r.hashret() if h in hsent: hlst = hsent[h] for i, sentpkt in enumerate(hlst): if r.answers(sentpkt): ans.append((sentpkt, r)) if verbose > 1: os.write(1, "*") ok = 1 if not multi: del hlst[i] notans -= 1 else: if not hasattr(sentpkt, '_answered'): notans -= 1 sentpkt._answered = 1 break if notans == 0 and not multi: break if not ok: if verbose > 1: os.write(1, ".") nbrecv += 1 if conf.debug_match: debug.recv.append(r) except KeyboardInterrupt: if chainCC: raise finally: try: nc,sent_times = six.moves.cPickle.load(rdpipe) except EOFError: warning("Child died unexpectedly. Packets may have not been sent %i"%os.getpid()) else: conf.netcache.update(nc) for p,t in zip(all_stimuli, sent_times): p.sent_time = t os.waitpid(pid,0) finally: if pid == 0: os._exit(0) remain = list(itertools.chain(*six.itervalues(hsent))) if multi: remain = [p for p in remain if not hasattr(p, '_answered')] if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent=plist.PacketList(remain[:],"Sent") debug.match=plist.SndRcvList(ans[:]) #clean the ans list to delete the field _answered if (multi): for s,r in ans: if hasattr(s, '_answered'): del(s._answered) if verbose: print("\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans)) return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered")
def read_routes(): # type: () -> List[Tuple[int, int, str, str, str, int]] """Return a list of IPv4 routes than can be used by Scapy. This function parses netstat. """ if SOLARIS: f = os.popen("netstat -rvn -f inet") elif FREEBSD: f = os.popen("netstat -rnW -f inet") # -W to show long interface names else: f = os.popen("netstat -rn -f inet") ok = 0 mtu_present = False prio_present = False refs_present = False use_present = False routes = [] # type: List[Tuple[int, int, str, str, str, int]] pending_if = [] # type: List[Tuple[int, int, str]] for line in f.readlines(): if not line: break line = line.strip().lower() if line.find("----") >= 0: # a separation line continue if not ok: if line.find("destination") >= 0: ok = 1 mtu_present = "mtu" in line prio_present = "prio" in line refs_present = "ref" in line # There is no s on Solaris use_present = "use" in line or "nhop" in line continue if not line: break rt = line.split() if SOLARIS: dest_, netmask_, gw, netif = rt[:4] flg = rt[4 + mtu_present + refs_present] else: dest_, gw, flg = rt[:3] locked = OPENBSD and rt[6] == "l" offset = mtu_present + prio_present + refs_present + locked offset += use_present netif = rt[3 + offset] if flg.find("lc") >= 0: continue elif dest_ == "default": dest = 0 netmask = 0 elif SOLARIS: dest = scapy.utils.atol(dest_) netmask = scapy.utils.atol(netmask_) else: if "/" in dest_: dest_, netmask_ = dest_.split("/") netmask = scapy.utils.itom(int(netmask_)) else: netmask = scapy.utils.itom((dest_.count(".") + 1) * 8) dest_ += ".0" * (3 - dest_.count(".")) dest = scapy.utils.atol(dest_) # XXX: TODO: add metrics for unix.py (use -e option on netstat) metric = 1 if "g" not in flg: gw = '0.0.0.0' if netif is not None: from scapy.arch import get_if_addr try: ifaddr = get_if_addr(netif) routes.append((dest, netmask, gw, netif, ifaddr, metric)) except OSError as exc: if 'Device not configured' in str(exc): # This means the interface name is probably truncated by # netstat -nr. We attempt to guess it's name and if not we # ignore it. guessed_netif = _guess_iface_name(netif) if guessed_netif is not None: ifaddr = get_if_addr(guessed_netif) routes.append((dest, netmask, gw, guessed_netif, ifaddr, metric)) # noqa: E501 else: log_runtime.info( "Could not guess partial interface name: %s", netif) else: raise else: pending_if.append((dest, netmask, gw)) f.close() # On Solaris, netstat does not provide output interfaces for some routes # We need to parse completely the routing table to route their gw and # know their output interface for dest, netmask, gw in pending_if: gw_l = scapy.utils.atol(gw) max_rtmask, gw_if, gw_if_addr = 0, None, None for rtdst, rtmask, _, rtif, rtaddr, _ in routes[:]: if gw_l & rtmask == rtdst: if rtmask >= max_rtmask: max_rtmask = rtmask gw_if = rtif gw_if_addr = rtaddr # XXX: TODO add metrics metric = 1 if gw_if and gw_if_addr: routes.append((dest, netmask, gw, gw_if, gw_if_addr, metric)) else: warning("Did not find output interface to reach gateway %s", gw) return routes
def post_dissection(self, pkt): s = self.tls_session if s.sslv2_connection_id is not None: if self.connection_id != s.sslv2_connection_id: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: invalid client Finished received [%s]", pkt_info)
def post_dissection(self, pkt): s = self.tls_session if s.sslv2_challenge is not None: if self.challenge != s.sslv2_challenge: pkt_info = pkt.firstlayer().summary() log_runtime.info("TLS: invalid ServerVerify received [%s]", pkt_info)
def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) if verbose is None: verbose = conf.verb debug.recv = plist.PacketList([],"Unanswered") debug.sent = plist.PacketList([],"Sent") debug.match = plist.SndRcvList([]) nbrecv=0 ans = [] # do it here to fix random fields, so that parent and child have the same all_stimuli = tobesent = [p for p in pkt] notans = len(tobesent) hsent={} for i in tobesent: h = i.hashret() if h in hsent: hsent[h].append(i) else: hsent[h] = [i] if retry < 0: retry = -retry autostop=retry else: autostop=0 while retry >= 0: found=0 if timeout < 0: timeout = None pid=1 try: if WINDOWS or pid == 0: try: try: i = 0 if verbose: print "Begin emission:" for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print "Finished to send %i packets." % i except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.exception("--- Error sending packets") log_runtime.info("--- Error sending packets") finally: try: sent_times = [p.sent_time for p in all_stimuli if p.sent_time] except: pass if WINDOWS or pid > 0: # Timeout starts after last packet is sent (as in Unix version) if timeout: stoptime = time.time()+timeout else: stoptime = 0 remaintime = None inmask = [pks.ins.fd] try: try: while 1: if stoptime: remaintime = stoptime-time.time() if remaintime <= 0: break r = pks.recv(MTU) if r is None: continue ok = 0 h = r.hashret() if h in hsent: hlst = hsent[h] for i in range(len(hlst)): if r.answers(hlst[i]): ans.append((hlst[i],r)) if verbose > 1: os.write(1, "*") ok = 1 if not multi: del(hlst[i]) notans -= 1; else: if not hasattr(hlst[i], '_answered'): notans -= 1; hlst[i]._answered = 1; break if notans == 0 and not multi: break if not ok: if verbose > 1: os.write(1, ".") nbrecv += 1 if conf.debug_match: debug.recv.append(r) except KeyboardInterrupt: if chainCC: raise finally: if WINDOWS: for p,t in zip(all_stimuli, sent_times): p.sent_time = t finally: pass remain = reduce(list.__add__, hsent.values(), []) if multi: remain = filter(lambda p: not hasattr(p, '_answered'), remain); if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent=plist.PacketList(remain[:],"Sent") debug.match=plist.SndRcvList(ans[:]) #clean the ans list to delete the field _answered if (multi): for s,r in ans: if hasattr(s, '_answered'): del(s._answered) if verbose: print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans) return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered")
def sendpfast(x, # type: _PacketIterable pps=None, # type: Optional[float] mbps=None, # type: Optional[float] realtime=False, # type: bool loop=0, # type: int file_cache=False, # type: bool iface=None, # type: Optional[_GlobInterfaceType] replay_args=None, # type: Optional[List[str]] parse_results=False, # type: bool ): # type: (...) -> Optional[Dict[str, Any]] """Send packets at layer 2 using tcpreplay for performance :param pps: packets per second :param mpbs: MBits per second :param realtime: use packet's timestamp, bending time with real-time value :param loop: number of times to process the packet list :param file_cache: cache packets in RAM instead of reading from disk at each iteration :param iface: output interface :param replay_args: List of additional tcpreplay args (List[str]) :param parse_results: Return a dictionary of information outputted by tcpreplay (default=False) :returns: stdout, stderr, command used """ if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % network_name(iface)] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--preload-pcap") # Check for any additional args we didn't cover. if replay_args is not None: argv.extend(replay_args) f = get_temp_file() argv.append(f) wrpcap(f, x) results = None with ContextManagerSubprocess(conf.prog.tcpreplay): try: cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception: os.unlink(f) raise else: stdout, stderr = cmd.communicate() if stderr: log_runtime.warning(stderr.decode()) if parse_results: results = _parse_tcpreplay_result(stdout, stderr, argv) elif conf.verb > 2: log_runtime.info(stdout.decode()) os.unlink(f) return results
def sndrcv(pks, pkt, timeout=None, inter=0, verbose=None, chainCC=0, retry=0, multi=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) if verbose is None: verbose = conf.verb debug.recv = plist.PacketList([], "Unanswered") debug.sent = plist.PacketList([], "Sent") debug.match = plist.SndRcvList([]) nbrecv = 0 ans = [] # do it here to fix random fields, so that parent and child have the same all_stimuli = tobesent = [p for p in pkt] notans = len(tobesent) hsent = {} for i in tobesent: h = i.hashret() if h in hsent: hsent[h].append(i) else: hsent[h] = [i] if retry < 0: retry = -retry autostop = retry else: autostop = 0 while retry >= 0: found = 0 if timeout < 0: timeout = None rdpipe, wrpipe = os.pipe() rdpipe = os.fdopen(rdpipe) wrpipe = os.fdopen(wrpipe, "w") pid = 1 try: pid = os.fork() if pid == 0: try: sys.stdin.close() rdpipe.close() try: i = 0 if verbose: print "Begin emission:" for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print "Finished to send %i packets." % i except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.exception("--- Error in child %i" % os.getpid()) log_runtime.info("--- Error in child %i" % os.getpid()) finally: try: os.setpgrp() # Chance process group to avoid ctrl-C sent_times = [ p.sent_time for p in all_stimuli if p.sent_time ] cPickle.dump((conf.netcache, sent_times), wrpipe) wrpipe.close() except: pass elif pid < 0: log_runtime.error("fork error") else: wrpipe.close() stoptime = 0 remaintime = None inmask = [rdpipe, pks] try: try: while 1: if stoptime: remaintime = stoptime - time.time() if remaintime <= 0: break r = None if not isinstance( pks, StreamSocket) and (FREEBSD or DARWIN): inp, out, err = select(inmask, [], [], 0.05) if len(inp) == 0 or pks in inp: r = pks.nonblock_recv() else: inp = [] try: inp, out, err = select( inmask, [], [], remaintime) except IOError, exc: if exc.errno != errno.EINTR: raise if len(inp) == 0: break if pks in inp: r = pks.recv(MTU) if rdpipe in inp: if timeout: stoptime = time.time() + timeout del (inmask[inmask.index(rdpipe)]) if r is None: continue ok = 0 h = r.hashret() if h in hsent: hlst = hsent[h] for i, sentpkt in enumerate(hlst): if r.answers(sentpkt): ans.append((sentpkt, r)) if verbose > 1: os.write(1, "*") ok = 1 if not multi: del hlst[i] notans -= 1 else: if not hasattr( sentpkt, '_answered'): notans -= 1 sentpkt._answered = 1 break if notans == 0 and not multi: break if not ok: if verbose > 1: os.write(1, ".") nbrecv += 1 if conf.debug_match: debug.recv.append(r) except KeyboardInterrupt: if chainCC: raise finally: try: nc, sent_times = cPickle.load(rdpipe) except EOFError: warning( "Child died unexpectedly. Packets may have not been sent %i" % os.getpid()) else: conf.netcache.update(nc) for p, t in zip(all_stimuli, sent_times): p.sent_time = t os.waitpid(pid, 0) finally: if pid == 0: os._exit(0) remain = list(itertools.chain(*hsent.itervalues())) if multi: remain = [p for p in remain if not hasattr(p, '_answered')] if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent = plist.PacketList(remain[:], "Sent") debug.match = plist.SndRcvList(ans[:]) #clean the ans list to delete the field _answered if (multi): for s, r in ans: if hasattr(s, '_answered'): del (s._answered) if verbose: print "\nReceived %i packets, got %i answers, remaining %i packets" % ( nbrecv + len(ans), len(ans), notans) return plist.SndRcvList(ans), plist.PacketList(remain, "Unanswered")
def pre_dissect(self, s): """ Decrypt, verify and decompress the message, i.e. apply the previous methods according to the reading cipher type. If the decryption was successful, 'len' will be the length of the TLSPlaintext.fragment. Else, it should be the length of the _TLSEncryptedContent. """ if len(s) < 5: raise Exception("Invalid record: header is too short.") msglen = struct.unpack('!H', s[3:5])[0] hdr, efrag, r = s[:5], s[5:5 + msglen], s[msglen + 5:] iv = mac = pad = b"" self.padlen = None decryption_success = False cipher_type = self.tls_session.rcs.cipher.type if cipher_type == 'block': version = struct.unpack("!H", s[1:3])[0] # Decrypt try: if version >= 0x0302: # Explicit IV for TLS 1.1 and 1.2 block_size = self.tls_session.rcs.cipher.block_size iv, efrag = efrag[:block_size], efrag[block_size:] self.tls_session.rcs.cipher.iv = iv pfrag = self._tls_decrypt(efrag) else: # Implicit IV for SSLv3 and TLS 1.0 pfrag = self._tls_decrypt(efrag) except CipherError as e: # This will end up dissected as _TLSEncryptedContent. cfrag = e.args[0] else: decryption_success = True # Excerpt below better corresponds to TLS 1.1 IV definition, # but the result is the same as with TLS 1.2 anyway. # This leading *IV* has been decrypted by _tls_decrypt with a # random IV, hence it does not correspond to anything. # What actually matters is that we got the first encrypted block # in order to decrypt the second block (first data block). # if version >= 0x0302: # block_size = self.tls_session.rcs.cipher.block_size # iv, pfrag = pfrag[:block_size], pfrag[block_size:] # l = struct.unpack('!H', hdr[3:5])[0] # hdr = hdr[:3] + struct.pack('!H', l-block_size) # Extract padding ('pad' actually includes the trailing padlen) padlen = orb(pfrag[-1]) + 1 mfrag, pad = pfrag[:-padlen], pfrag[-padlen:] self.padlen = padlen # Extract MAC l = self.tls_session.rcs.mac_len if l != 0: cfrag, mac = mfrag[:-l], mfrag[-l:] else: cfrag, mac = mfrag, b"" # Verify integrity chdr = hdr[:3] + struct.pack('!H', len(cfrag)) is_mac_ok = self._tls_hmac_verify(chdr, cfrag, mac) if not is_mac_ok: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) elif cipher_type == 'stream': # Decrypt try: pfrag = self._tls_decrypt(efrag) except CipherError as e: # This will end up dissected as _TLSEncryptedContent. cfrag = e.args[0] else: decryption_success = True mfrag = pfrag # Extract MAC l = self.tls_session.rcs.mac_len if l != 0: cfrag, mac = mfrag[:-l], mfrag[-l:] else: cfrag, mac = mfrag, b"" # Verify integrity chdr = hdr[:3] + struct.pack('!H', len(cfrag)) is_mac_ok = self._tls_hmac_verify(chdr, cfrag, mac) if not is_mac_ok: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) elif cipher_type == 'aead': # Authenticated encryption # crypto/cipher_aead.py prints a warning for integrity failure if (conf.crypto_valid_advanced and isinstance( self.tls_session.rcs.cipher, Cipher_CHACHA20_POLY1305)): iv = b"" cfrag, mac = self._tls_auth_decrypt(hdr, efrag) else: iv, cfrag, mac = self._tls_auth_decrypt(hdr, efrag) decryption_success = True # see XXX above frag = self._tls_decompress(cfrag) if (decryption_success and not isinstance(self.tls_session.rcs.cipher, Cipher_NULL)): self.deciphered_len = len(frag) else: self.deciphered_len = None reconstructed_body = iv + frag + mac + pad return hdr + reconstructed_body + r