def _PPIGuessPayloadClass(p, **kargs): """ This function tells the PacketListField how it should extract the TLVs from the payload. We pass cls only the length string pfh_len says it needs. If a payload is returned, that means part of the string was unused. This converts to a Raw layer, and the remainder of p is added as Raw's payload. If there is no payload, the remainder of p is added as out's payload. """ if len(p) >= 4: t, pfh_len = struct.unpack("<HH", p[:4]) # Find out if the value t is in the dict _ppi_types. # If not, return the default TLV class cls = getPPIType(t, "default") pfh_len += 4 out = cls(p[:pfh_len], **kargs) if (out.payload): out.payload = conf.raw_layer(out.payload.load) out.payload.underlayer = out if (len(p) > pfh_len): out.payload.payload = conf.padding_layer(p[pfh_len:]) out.payload.payload.underlayer = out.payload elif (len(p) > pfh_len): out.payload = conf.padding_layer(p[pfh_len:]) out.payload.underlayer = out else: out = conf.raw_layer(p, **kargs) return out
def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[2] == socket.PACKET_OUTGOING: return None if sa_ll[3] in conf.l2types: cls = conf.l2types[sa_ll[3]] lvl = 2 elif sa_ll[1] in conf.l3types: cls = conf.l3types[sa_ll[1]] lvl = 3 else: cls = conf.default_l2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], cls.name) # noqa: E501 lvl = 3 try: pkt = cls(pkt) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) if lvl == 2: pkt = pkt.payload if pkt is not None: from scapy.arch import get_last_packet_timestamp pkt.time = get_last_packet_timestamp(self.ins) return pkt
def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[2] == socket.PACKET_OUTGOING: return None if sa_ll[3] in conf.l2types: cls = conf.l2types[sa_ll[3]] lvl = 2 elif sa_ll[1] in conf.l3types: cls = conf.l3types[sa_ll[1]] lvl = 3 else: cls = conf.default_l2 warning(" Impossivel saber o tipo (interface=%s protocol=%#x familia=%i). Usando %s" % (sa_ll[0],sa_ll[1],sa_ll[3],cls.name)) lvl = 2 try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) if lvl == 2: pkt = pkt.payload if pkt is not None: pkt.time = get_last_packet_timestamp(self.ins) return pkt
def recv(self, x=MTU): ll = self.ins.datalink() if ll in conf.l2types: cls = conf.l2types[ll] else: cls = conf.default_l2 warning( "Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name) ) pkt = self.ins.next() if pkt is not None: ts, pkt = pkt if pkt is None: return try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = ts return pkt
def getfield(self, pkt, s): c = l = None if self.length_from is not None: l = self.length_from(pkt) elif self.count_from is not None: c = self.count_from(pkt) lst = [] ret = "" remain = s if l is not None: remain,ret = s[:l],s[l:] while remain: if c is not None: if c <= 0: break c -= 1 try: p = self.m2i(pkt,remain) except Exception: if conf.debug_dissector: raise p = conf.raw_layer(load=remain) remain = "" else: if conf.padding_layer in p: pad = p[conf.padding_layer] remain = pad.load del(pad.underlayer.payload) else: remain = "" lst.append(p) return remain+ret,lst
def getfield(self, pkt, s): l = self.length_from(pkt) try: i = self.m2i(pkt, s[:l]) except Exception: if conf.debug_dissector: raise i = conf.raw_layer(load=s[:l]) return s[l:],i
def m2i(self, pkt, m): ret = None eap_packet_len = struct.unpack("!H", m[2:4])[0] if eap_packet_len < 254: # If the EAP packet has not been fragmented, build a Scapy EAP # packet from the data. ret = EAP(m) else: ret = conf.raw_layer(m) return ret
def do_dissect_payload(self, s): if s: try: p = SSLv2(s, _internal=1, _underlayer=self, tls_session = self.tls_session) except KeyboardInterrupt: raise except: p = conf.raw_layer(s, _internal=1, _underlayer=self) self.add_payload(p)
def __div__(self, other): if isinstance(other, Packet): cloneA = self.copy() cloneB = other.copy() cloneA.add_payload(cloneB) return cloneA elif type(other) is str: return self/conf.raw_layer(load=other) else: return other.__rdiv__(self)
def recv(self, x=MTU): cls, val, ts = self.recv_raw(x) if not val or not cls: return try: pkt = cls(val) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: raise pkt = conf.raw_layer(val) pkt.time = ts return pkt
def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[2] == socket.PACKET_OUTGOING: return None try: q = self.LL(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise q = conf.raw_layer(pkt) q.time = get_last_packet_timestamp(self.ins) return q
def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, *args, **kargs): # noqa: E501 if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop = -1 if return_packets: sent_packets = PacketList() try: while loop: dt0 = None for p in x: if realtime: ct = time.time() if dt0: st = dt0 + float(p.time) - ct if st > 0: time.sleep(st) else: dt0 = ct - float(p.time) s.send(p) if return_packets: sent_packets.append(p) n += 1 if verbose: os.write(1, b".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass if verbose: print("\nSent %i packets." % n) if return_packets: return sent_packets
class ISAKMP_payload_Proposal(ISAKMP_class): name = "IKE proposal" # ISAKMP_payload_type = 0 fields_desc = [ ByteEnumField("next_payload", None, ISAKMP_payload_type), ByteField("res", 0), FieldLenField("length", None, "trans", "H", adjust=lambda pkt, x:x + 8), # noqa: E501 ByteField("proposal", 1), ByteEnumField("proto", 1, {1: "ISAKMP"}), FieldLenField("SPIsize", None, "SPI", "B"), ByteField("trans_nb", None), StrLenField("SPI", "", length_from=lambda x: x.SPIsize), PacketLenField("trans", conf.raw_layer(), ISAKMP_payload_Transform, length_from=lambda x: x.length - 8), # noqa: E501 ]
def do_dissect_payload(self, s): """ Try to dissect the following data as a TLS message. Note that overloading .guess_payload_class() would not be enough, as the TLS session to be used would get lost. """ if s: try: p = TLS(s, _internal=1, _underlayer=self, tls_session = self.tls_session) except KeyboardInterrupt: raise except: p = conf.raw_layer(s, _internal=1, _underlayer=self) self.add_payload(p)
def do_dissect_payload(self, s): """ Try to dissect the following data as a TLS message. Note that overloading .guess_payload_class() would not be enough, as the TLS session to be used would get lost. """ if s: try: p = TLS(s, _internal=1, _underlayer=self, tls_session=self.tls_session) except KeyboardInterrupt: raise except Exception: p = conf.raw_layer(s, _internal=1, _underlayer=self) self.add_payload(p)
def read_packet(self, size=MTU): rp = RawPcapNgReader.read_packet(self, size=size) if rp is None: return None s, (linktype, sec, usec, wirelen) = rp try: p = conf.l2types[linktype](s) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise p = conf.raw_layer(s) p.time = sec + 0.000001 * usec return p
def read_packet(self, size=MTU): rp = RawPcapNgReader.read_packet(self, size=size) if rp is None: return None s, (linktype, sec, usec, wirelen) = rp try: p = conf.l2types[linktype](s) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise p = conf.raw_layer(s) p.time = sec+0.000001*usec return p
def read_packet(self, size=MTU): rp = RawPcapNgReader.read_packet(self, size=size) if rp is None: return None s, (linktype, tsresol, tshigh, tslow, wirelen) = rp try: p = conf.l2types[linktype](s) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise p = conf.raw_layer(s) if tshigh is not None: p.time = float((tshigh << 32) + tslow) / tsresol return p
def read_packet(self, size=MTU): rp = RawPcapReader.read_packet(self, size=size) if rp is None: return None s,(sec,usec,wirelen) = rp try: p = self.LLcls(s) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise p = conf.raw_layer(s) p.time = sec + (0.000000001 if self.nano else 0.000001) * usec return p
def recv(self, x=MTU): cls, val, ts = self.recv_raw(x) if not val or not cls: return try: pkt = cls(val) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: from scapy.sendrecv import debug debug.crashed_on = (cls, val) raise pkt = conf.raw_layer(val) pkt.time = ts return pkt
def do_dissect_payload(self, s): if s: cls = self.guess_payload_class(s) try: p = cls(s, _internal=1, _underlayer=self) except KeyboardInterrupt: raise except: if conf.debug_dissector: if isinstance(cls,type) and issubclass(cls,Packet): log_runtime.error("%s dissector failed" % cls.name) else: log_runtime.error("%s.guess_payload_class() returned [%s]" % (self.__class__.__name__,repr(cls))) if cls is not None: raise p = conf.raw_layer(s, _internal=1, _underlayer=self) self.add_payload(p)
def add_payload(self, payload): if payload is None: return elif not isinstance(self.payload, NoPayload): self.payload.add_payload(payload) else: if isinstance(payload, Packet): self.payload = payload payload.add_underlayer(self) for t in self.aliastypes: if payload.overload_fields.has_key(t): self.overloaded_fields = payload.overload_fields[t] break elif type(payload) is str: self.payload = conf.raw_layer(load=payload) else: raise TypeError("payload must be either 'Packet' or 'str', not [%s]" % repr(payload))
def read_packet(self, size=MTU): rp = super(PcapReader, self).read_packet(size=size) if rp is None: return None s, pkt_info = rp try: p = self.LLcls(s) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise p = conf.raw_layer(s) p.time = pkt_info.sec + (0.000000001 if self.nano else 0.000001) * pkt_info.usec p.wirelen = pkt_info.wirelen return p
class IEC104_I_Message_SeqIOA(IEC104_I_Message): """ all information objects share a base information object address field sq = 1, see EN 60870-5-101:2003, sec. 7.2.2.1 (p. 33) """ name = 'IEC-104 I APDU (Seq IOA)' fields_desc = [ # APCI XByteField('start', IEC104_I_Message.IEC_104_MAGIC), FieldLenField("apdu_length", None, fmt="!B", length_of='io', adjust=lambda pkt, x: x + 13), IEC104SequenceNumber('tx_seq_num', 0), IEC104SequenceNumber('rx_seq_num', 0), # ASDU ByteEnumField('type_id', 0, IEC104_IO_NAMES), BitEnumField('sq', IEC104_I_Message.SQ_FLAG_SEQUENCE, 1, IEC104_I_Message.SQ_FLAGS), BitFieldLenField('num_io', None, 7, count_of='io'), BitEnumField('test', 0, 1, IEC104_I_Message.TEST_FLAGS), BitEnumField('ack', 0, 1, IEC104_I_Message.ACK_FLAGS), BitEnumField('cot', 0, 6, CAUSE_OF_TRANSMISSIONS), ByteField('origin_address', 0), LEShortField('common_asdu_address', 0), LEThreeBytesField('information_object_address', 0), IEC104ASDUPacketListField('io', conf.raw_layer(), _i_msg_io_dispatcher_sequence, length_from=lambda pkt: pkt.apdu_length - 13) ] def post_dissect(self, s): if self.type_id == IEC104_IO_ID_C_RD_NA_1: # IEC104_IO_ID_C_RD_NA_1 has no payload. we will add the layer # manually to the stack right now. we do this num_io times # as - even if it makes no sense - someone could decide # to add more than one read commands in a sequence... setattr(self, 'io', [IEC104_IO_C_RD_NA_1()] * self.num_io) return s
def iec104_decode(payload): """ can be used to dissect payload of a TCP connection :param payload: the application layer data (IEC104-APDU(s)) :return: iec104 (I/U/S) message instance, conf.raw_layer() if unknown """ if _iec104_is_i_apdu_seq_ioa(payload): return IEC104_I_Message_SeqIOA(payload) elif _iec104_is_i_apdu_single_ioa(payload): return IEC104_I_Message_SingleIOA(payload) elif _iec104_is_s_apdu(payload): return IEC104_S_Message(payload) elif _iec104_is_u_apdu(payload): return IEC104_U_Message(payload) else: return conf.raw_layer(payload)
class ISAKMP_payload_SA(ISAKMP_class): name = "ISAKMP SA" overload_fields = {ISAKMP: {"next_payload": 1}} fields_desc = [ ByteEnumField("next_payload", None, ISAKMP_payload_type), ByteField("res", 0), FieldLenField("length", None, "prop", "H", adjust=lambda pkt, x: x + 12), # noqa: E501 IntEnumField("DOI", 1, {1: "IPSEC"}), IntEnumField("situation", 1, {1: "identity"}), PacketLenField("prop", conf.raw_layer(), ISAKMP_payload_Proposal, length_from=lambda x: x.length - 12), # noqa: E501 ]
def recv(self, x=MTU): # type: (int) -> Optional[Packet] cls, val, ts = self.recv_raw(x) if not val or not cls: return None try: pkt = cls(val) # type: Packet except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: from scapy.sendrecv import debug debug.crashed_on = (cls, val) raise pkt = conf.raw_layer(val) if ts: pkt.time = ts return pkt
def getfield(self, pkt, s): c = l = cls = None if self.length_from is not None: l = self.length_from(pkt) elif self.count_from is not None: c = self.count_from(pkt) if self.next_cls_cb is not None: cls = self.next_cls_cb(pkt, [], None, s) c = 1 lst = [] ret = b"" remain = s if l is not None: remain,ret = s[:l],s[l:] while remain: if c is not None: if c <= 0: break c -= 1 try: if cls is not None: p = cls(remain) else: p = self.m2i(pkt, remain) except Exception: if conf.debug_dissector: raise p = conf.raw_layer(load=remain) remain = b"" else: if conf.padding_layer in p: pad = p[conf.padding_layer] remain = pad.load del(pad.underlayer.payload) if self.next_cls_cb is not None: cls = self.next_cls_cb(pkt, lst, p, remain) if cls is not None: c += 1 else: remain = b"" lst.append(p) return remain+ret,lst
def extract_frames(self, bpf_buffer): """Extract all frames from the buffer and stored them in the received list.""" # noqa: E501 # Ensure that the BPF buffer contains at least the header len_bb = len(bpf_buffer) if len_bb < 20: # Note: 20 == sizeof(struct bfp_hdr) return # Extract useful information from the BPF header if FREEBSD or NETBSD: # struct bpf_xhdr or struct bpf_hdr32 bh_tstamp_offset = 16 else: # struct bpf_hdr bh_tstamp_offset = 8 # Parse the BPF header bh_caplen = struct.unpack( 'I', bpf_buffer[bh_tstamp_offset:bh_tstamp_offset + 4])[0] # noqa: E501 next_offset = bh_tstamp_offset + 4 bh_datalen = struct.unpack('I', bpf_buffer[next_offset:next_offset + 4])[0] # noqa: E501 next_offset += 4 bh_hdrlen = struct.unpack('H', bpf_buffer[next_offset:next_offset + 2])[0] # noqa: E501 if bh_datalen == 0: return # Get and store the Scapy object frame_str = bpf_buffer[bh_hdrlen:bh_hdrlen + bh_caplen] try: pkt = self.guessed_cls(frame_str) except Exception: if conf.debug_dissector: raise pkt = conf.raw_layer(frame_str) self.received_frames.append(pkt) # Extract the next frame end = self.bpf_align(bh_hdrlen, bh_caplen) if (len_bb - end) >= 20: self.extract_frames(bpf_buffer[end:])
def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, realtime=None, return_packets=False, *args, **kargs): if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop = -1 if return_packets: sent_packets = plist.PacketList() try: while loop: dt0 = None for p in x: if realtime: ct = time.time() if dt0: st = dt0+p.time-ct if st > 0: time.sleep(st) else: dt0 = ct-p.time s.send(p) if return_packets: sent_packets.append(p) n += 1 if verbose: os.write(1,".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass s.close() if verbose: print("\nSent %i packets." % n) if return_packets: return sent_packets
def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[3] in conf.l2types : cls = conf.l2types[sa_ll[3]] elif sa_ll[1] in conf.l3types: cls = conf.l3types[sa_ll[1]] else: cls = conf.default_l2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s" % (sa_ll[0],sa_ll[1],sa_ll[3],cls.name)) try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = get_last_packet_timestamp(self.ins) return pkt
def extract_frames(self, bpf_buffer): """Extract all frames from the buffer and stored them in the received list.""" # noqa: E501 # Ensure that the BPF buffer contains at least the header len_bb = len(bpf_buffer) if len_bb < 20: # Note: 20 == sizeof(struct bfp_hdr) return # Extract useful information from the BPF header if FREEBSD or NETBSD: # struct bpf_xhdr or struct bpf_hdr32 bh_tstamp_offset = 16 else: # struct bpf_hdr bh_tstamp_offset = 8 # Parse the BPF header bh_caplen = struct.unpack('I', bpf_buffer[bh_tstamp_offset:bh_tstamp_offset + 4])[0] # noqa: E501 next_offset = bh_tstamp_offset + 4 bh_datalen = struct.unpack('I', bpf_buffer[next_offset:next_offset + 4])[0] # noqa: E501 next_offset += 4 bh_hdrlen = struct.unpack('H', bpf_buffer[next_offset:next_offset + 2])[0] # noqa: E501 if bh_datalen == 0: return # Get and store the Scapy object frame_str = bpf_buffer[bh_hdrlen:bh_hdrlen + bh_caplen] try: pkt = self.guessed_cls(frame_str) except Exception: if conf.debug_dissector: raise pkt = conf.raw_layer(frame_str) self.received_frames.append(pkt) # Extract the next frame end = self.bpf_align(bh_hdrlen, bh_caplen) if (len_bb - end) >= 20: self.extract_frames(bpf_buffer[end:])
class IEC104_I_Message_SingleIOA(IEC104_I_Message): """ every information object contains an individual information object address field sq = 0, see EN 60870-5-101:2003, sec. 7.2.2.1 (p. 33) """ name = 'IEC-104 I APDU (single IOA)' fields_desc = [ # APCI XByteField('start', IEC104_I_Message.IEC_104_MAGIC), FieldLenField("apdu_length", None, fmt="!B", length_of='io', adjust=lambda pkt, x: x + 10), IEC104SequenceNumber('tx_seq_num', 0), IEC104SequenceNumber('rx_seq_num', 0), # ASDU ByteEnumField('type_id', 0, IEC104_IO_NAMES), BitEnumField('sq', IEC104_I_Message.SQ_FLAG_SINGLE, 1, IEC104_I_Message.SQ_FLAGS), BitFieldLenField('num_io', None, 7, count_of='io'), BitEnumField('test', 0, 1, IEC104_I_Message.TEST_FLAGS), BitEnumField('ack', 0, 1, IEC104_I_Message.ACK_FLAGS), BitEnumField('cot', 0, 6, CAUSE_OF_TRANSMISSIONS), ByteField('origin_address', 0), LEShortField('common_asdu_address', 0), IEC104ASDUPacketListField('io', conf.raw_layer(), _i_msg_io_dispatcher_single, length_from=lambda pkt: pkt.apdu_length - 10) ]
def recv(self, x=MTU): ll = self.ins.datalink() if ll in conf.l2types: cls = conf.l2types[ll] else: cls = conf.default_l2 warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s", self.iface, ll, cls.name) pkt = self.ins.next() if scapy.arch.WINDOWS and pkt is None: raise PcapTimeoutElapsed if pkt is not None: ts,pkt = pkt try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = ts return pkt
def getfield(self, pkt, s): c = l = None if self.length_from is not None: l = self.length_from(pkt) elif self.count_from is not None: c = self.count_from(pkt) lst = [] ret = "" remain = s if l is not None: remain, ret = s[:l], s[l:] while remain: if c is not None: if c <= 0: break c -= 1 try: p = self.m2i(pkt, remain) except Exception: if conf.debug_dissector: raise p = conf.raw_layer(load=remain) remain = "" else: if conf.padding_layer in p: pad = p[conf.padding_layer] remain = pad.load del (pad.underlayer.payload) else: remain = "" lst.append(p) # Evaluate the stop condition if self.stop and self.stop(p): break return remain + ret, lst
def recv(self, x=MTU): # type: (int) -> Optional[Packet] data, sa_ll, ts = self._recv_raw(self.ins, x) if sa_ll[2] == socket.PACKET_OUTGOING: return None if sa_ll[3] in conf.l2types: cls = conf.l2types.num2layer[sa_ll[3]] # type: Type[Packet] lvl = 2 elif sa_ll[1] in conf.l3types: cls = conf.l3types.num2layer[sa_ll[1]] lvl = 3 else: cls = conf.default_l2 warning( "Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], cls.name) # noqa: E501 lvl = 3 try: pkt = cls(data) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: raise pkt = conf.raw_layer(data) if lvl == 2: pkt = pkt.payload if pkt is not None: if ts is None: from scapy.arch.linux import get_last_packet_timestamp ts = get_last_packet_timestamp(self.ins) pkt.time = ts return pkt
def recv(self,x=MTU): ll = self.ins.datalink() if ll in conf.l2types: cls = conf.l2types[ll] else: cls = conf.default_l2 warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name)) pkt = next(self.ins) if pkt is not None: ts,pkt = pkt if pkt is None: return try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = ts return pkt.payload
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() # pkt = pkt.__class__(raw(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = [x for x in pb if x[6] == osgenre] if osdetails: pb = [x for x in pb if x[7] == osdetails] elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = [x for x in pb if 'K' in x[5]] else: pb = [x for x in pb if 'K' not in x[5]] if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) # Take the options already set as "hints" to use in the new packet if we # can. MSS, WScale and Timestamp can all be wildcarded in a signature, so # we'll use the already-set values if they're valid integers. orig_opts = dict(pkt.payload.options) int_only = lambda val: val if isinstance(val, six.integer_types) else None mss_hint = int_only(orig_opts.get('MSS')) wscale_hint = int_only(orig_opts.get('WScale')) ts_hint = [int_only(o) for o in orig_opts.get('Timestamp', (None, None))] options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16 - 1) // int(pers[0][1:]) else: maxmss = (2**16 - 1) # disregard hint if out of range if mss_hint and not 0 <= mss_hint <= maxmss: mss_hint = None # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': if mss_hint is not None: options.append(('MSS', mss_hint)) else: options.append(('MSS', random.randint(1, maxmss))) elif opt[1] == '%': coef = int(opt[2:]) if mss_hint is not None and mss_hint % coef == 0: options.append(('MSS', mss_hint)) else: options.append(( 'MSS', coef * random.randint(1, maxmss // coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if wscale_hint and not 0 <= wscale_hint < 2**8: wscale_hint = None if opt[1:] == '*': if wscale_hint is not None: options.append(('WScale', wscale_hint)) else: options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) if wscale_hint is not None and wscale_hint % coef == 0: options.append(('WScale', wscale_hint)) else: options.append(( 'WScale', coef * RandNum(min=1, max=(2**8 - 1) // coef))) # noqa: E501 else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': # Determine first timestamp. if uptime is not None: ts_a = uptime elif ts_hint[0] and 0 < ts_hint[0] < 2**32: # Note: if first ts is 0, p0f registers it as "T0" not "T", # hence we don't want to use the hint if it was 0. ts_a = ts_hint[0] else: ts_a = random.randint(120, 100 * 60 * 60 * 24 * 365) # Determine second timestamp. if 'T' not in pers[5]: ts_b = 0 elif ts_hint[1] and 0 < ts_hint[1] < 2**32: ts_b = ts_hint[1] else: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) ts_b = random.randint(1, 2**32 - 1) options.append(('Timestamp', (ts_a, ts_b))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append((optname, struct.unpack(optstruct, RandString(struct.calcsize(optstruct))._fix()))) # noqa: E501 else: options.append((int(opt[1:]), '')) # FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1, max=(2**16 - 1) // coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': # needs MSS set mss = [x for x in options if x[0] == 'MSS'] if not mss: raise Scapy_Exception("TCP window value requires MSS, and MSS option not set") # noqa: E501 pkt.payload.window = mss[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1] - extrahops # DF flag pkt.flags |= (2 * pers[2]) # FIXME: ss (packet size) not handled (how ? may be with D quirk # if present) # Quirks if pers[5] != '.': for qq in pers[5]: # FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= random.choice([8, 32, 40]) # P/U/PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) # XXX p0fo.fp # noqa: E501 elif qq == 'Q': pkt.payload.seq = pkt.payload.ack # elif qq == '0': pkt.payload.seq = 0 # if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
def post_dissect(self, data): """dissect the IPv6 package compressed into this IPHC packet. The packet payload needs to be decompressed and depending on the arguments, several conversions should be done. """ # uncompress payload packet = IPv6() packet.version = IPHC_DEFAULT_VERSION packet.tc, packet.fl = self._getTrafficClassAndFlowLabel() if not self.nh: packet.nh = self._nhField # HLIM: Hop Limit if self.hlim == 0: packet.hlim = self._hopLimit elif self.hlim == 0x1: packet.hlim = 1 elif self.hlim == 0x2: packet.hlim = 64 else: packet.hlim = 255 # TODO: Payload length can be inferred from lower layers from either the # noqa: E501 # 6LoWPAN Fragmentation header or the IEEE802.15.4 header packet.src = self.decompressSourceAddr(packet) packet.dst = self.decompressDestinyAddr(packet) if self.nh == 1: # The Next Header field is compressed and the next header is # encoded using LOWPAN_NHC packet.nh = 0x11 # UDP udp = UDP() if self.header_compression and \ self.header_compression & 0x4 == 0x0: udp.chksum = self.udpChecksum s, d = nhc_port(self) if s == 16: udp.sport = self.udpSourcePort elif s == 8: udp.sport = 0xF000 + s elif s == 4: udp.sport = 0xF0B0 + s if d == 16: udp.dport = self.udpDestinyPort elif d == 8: udp.dport = 0xF000 + d elif d == 4: udp.dport = 0xF0B0 + d packet.payload = udp / data data = raw(packet) # else self.nh == 0 not necessary elif self._nhField & 0xE0 == 0xE0: # IPv6 Extension Header Decompression # noqa: E501 warning('Unimplemented: IPv6 Extension Header decompression') # noqa: E501 packet.payload = conf.raw_layer(data) data = raw(packet) else: packet.payload = conf.raw_layer(data) data = raw(packet) return Packet.post_dissect(self, data)
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() #pkt = pkt.__class__(str(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") if uptime is None: uptime = random.randint(120,100*60*60*24*365) db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] #pb = filter(lambda x: x[6] == osgenre, pb) pb = [ x for x in pb if x[6] == osgenre ] if osdetails: #pb = filter(lambda x: x[7] == osdetails, pb) pb = [ x for x in pb if x[7] == osdetails ] elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: #pb = filter(lambda x: 'K' in x[5], pb) pb = [ x for x in pb if 'K' in x[5] ] else: #pb = filter(lambda x: 'K' not in x[5], pb) pb = [ x for x in pb if 'K' not in x[5] ] if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) ## TODO: let the options already set if they are valid options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16-1) / int(pers[0][1:]) else: maxmss = (2**16-1) # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': options.append(('MSS', random.randint(1,maxmss))) elif opt[1] == '%': coef = int(opt[2:]) options.append(('MSS', coef*random.randint(1,maxmss/coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if opt[1:] == '*': options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) options.append(('WScale', coef*RandNum(min=1, max=(2**8-1)/coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': if 'T' in pers[5]: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) options.append(('Timestamp', (uptime, random.randint(1,2**32-1)))) else: options.append(('Timestamp', (uptime, 0))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append((optname, struct.unpack(optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) ## FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1,max=(2**16-1)/coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': ## needs MSS set #MSS = filter(lambda x: x[0] == 'MSS', options) MSS = [ x for x in options if x[0] == 'MSS' ] if not MSS: raise Scapy_Exception("TCP window value requires MSS, and MSS option not set") pkt.payload.window = MSS[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1]-extrahops # DF flag pkt.flags |= (2 * pers[2]) ## FIXME: ss (packet size) not handled (how ? may be with D quirk ## if present) # Quirks if pers[5] != '.': for qq in pers[5]: ## FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': #if db == p0fo_kdb: # pkt.payload.flags |= 0x20 # U #else: pkt.payload.flags |= RandChoice(8, 32, 40) #P / U / PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack #elif qq == '0': pkt.payload.seq = 0 #if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
def __gen_send(s, # type: SuperSocket x, # type: _PacketIterable inter=0, # type: int loop=0, # type: int count=None, # type: Optional[int] verbose=None, # type: Optional[int] realtime=False, # type: bool return_packets=False, # type: bool *args, # type: Any **kargs # type: Any ): # type: (...) -> Optional[PacketList] """ An internal function used by send/sendp to actually send the packets, implement the send logic... It will take care of iterating through the different packets """ if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop = -1 sent_packets = PacketList() if return_packets else None p = None try: while loop: dt0 = None for p in x: if realtime: ct = time.time() if dt0: st = dt0 + float(p.time) - ct if st > 0: time.sleep(st) else: dt0 = ct - float(p.time) s.send(p) if sent_packets is not None: sent_packets.append(p) n += 1 if verbose: os.write(1, b".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass finally: try: cast(Packet, x).sent_time = cast(Packet, p).sent_time except AttributeError: pass if verbose: print("\nSent %i packets." % n) return sent_packets
def recv(self, x=MTU): return conf.raw_layer(self.ins.recv(x))
def post_dissect(self, data): """dissect the IPv6 package compressed into this IPHC packet. The packet payload needs to be decompressed and depending on the arguments, several conversions should be done. """ # uncompress payload packet = IPv6() packet.version = IPHC_DEFAULT_VERSION packet.tc, packet.fl = self._getTrafficClassAndFlowLabel() if not self.nh: packet.nh = self._nhField # HLIM: Hop Limit if self.hlim == 0: packet.hlim = self._hopLimit elif self.hlim == 0x1: packet.hlim = 1 elif self.hlim == 0x2: packet.hlim = 64 else: packet.hlim = 255 # TODO: Payload length can be inferred from lower layers from either the # noqa: E501 # 6LoWPAN Fragmentation header or the IEEE802.15.4 header packet.src = self.decompressSourceAddr(packet) packet.dst = self.decompressDestinyAddr(packet) if self.nh == 1: # The Next Header field is compressed and the next header is # encoded using LOWPAN_NHC udp = UDP() if self.header_compression and \ self.header_compression & 0x4 == 0x0: udp.chksum = self.udpChecksum s, d = nhc_port(self) if s == 16: udp.sport = self.udpSourcePort elif s == 8: udp.sport = 0xF000 + s elif s == 4: udp.sport = 0xF0B0 + s if d == 16: udp.dport = self.udpDestinyPort elif d == 8: udp.dport = 0xF000 + d elif d == 4: udp.dport = 0xF0B0 + d packet.payload = udp / data data = raw(packet) # else self.nh == 0 not necessary elif self._nhField & 0xE0 == 0xE0: # IPv6 Extension Header Decompression # noqa: E501 warning('Unimplemented: IPv6 Extension Header decompression') # noqa: E501 packet.payload = conf.raw_layer(data) data = raw(packet) else: packet.payload = conf.raw_layer(data) data = raw(packet) return Packet.post_dissect(self, data)
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. Either osgenre or signature is required to impersonate. If signature is specified (as a raw string), we use the signature. signature format: "ip_ver:ttl:ip_opt_len:mss:window,wscale:opt_layout:quirks:pay_class" If osgenre is specified, we randomly pick a signature with a label that matches osgenre (and osdetails, if specified). Note: osgenre is case sensitive ("linux" -> "Linux" etc.), and osdetails is a substring of a label flavor ("7", "8" and "7 or 8" will all match the label "s:win:Windows:7 or 8") For now, only TCP SYN/SYN+ACK packets are supported.""" pkt = validate_packet(pkt) if not osgenre and not signature: raise ValueError("osgenre or signature is required to impersonate!") tcp = pkt[TCP] tcp_type = tcp.flags & (0x02 | 0x10) # SYN / SYN+ACK if signature: if isinstance(signature, string_types): sig, _ = TCP_Signature.from_raw_sig(signature) else: raise TypeError("Unsupported signature type") else: if not p0fdb.get_base(): sigs = [] else: direction = "request" if tcp_type == 0x02 else "response" sigs = p0fdb.get_sigs_by_os(direction, osgenre, osdetails) # If IPv6 packet, remove IPv4-only signatures and vice versa sigs = [s for s in sigs if s.ip_ver == -1 or s.ip_ver == pkt.version] if not sigs: raise ValueError("No match in the p0f database") sig = random.choice(sigs) if sig.ip_ver != -1 and pkt.version != sig.ip_ver: raise ValueError("Can't convert between IPv4 and IPv6") quirks = sig.quirks if pkt.version == 4: pkt.ttl = sig.ttl - extrahops if sig.ip_opt_len != 0: # FIXME: Non-zero IPv4 options not handled warning("Unhandled IPv4 option field") else: pkt.options = [] if "df" in quirks: pkt.flags |= 0x02 # set DF flag if "id+" in quirks: if pkt.id == 0: pkt.id = random.randint(1, 2**16 - 1) else: pkt.id = 0 else: pkt.flags &= ~(0x02) # DF flag not set if "id-" in quirks: pkt.id = 0 elif pkt.id == 0: pkt.id = random.randint(1, 2**16 - 1) if "ecn" in quirks: pkt.tos |= random.randint(0x01, 0x03) pkt.flags = pkt.flags | 0x04 if "0+" in quirks else pkt.flags & ~(0x04) else: pkt.hlim = sig.ttl - extrahops if "flow" in quirks: pkt.fl = random.randint(1, 2**20 - 1) if "ecn" in quirks: pkt.tc |= random.randint(0x01, 0x03) # Take the options already set as "hints" to use in the new packet if we # can. we'll use the already-set values if they're valid integers. def int_only(val): return val if isinstance(val, integer_types) else None orig_opts = dict(tcp.options) mss_hint = int_only(orig_opts.get("MSS")) ws_hint = int_only(orig_opts.get("WScale")) ts_hint = [int_only(o) for o in orig_opts.get("Timestamp", (None, None))] options = [] for opt in sig.olayout.split(","): if opt == "mss": # MSS might have a maximum size because of WIN_TYPE_MSS if sig.win_type == WIN_TYPE_MSS: maxmss = (2**16 - 1) // sig.win else: maxmss = (2**16 - 1) if sig.mss == -1: # wildcard mss if mss_hint and 0 <= mss_hint <= maxmss: options.append(("MSS", mss_hint)) else: # invalid hint, generate new value options.append(("MSS", random.randint(100, maxmss))) else: options.append(("MSS", sig.mss)) elif opt == "ws": if sig.wscale == -1: # wildcard wscale maxws = 2**8 if "exws" in quirks: # wscale > 14 if ws_hint and 14 < ws_hint < maxws: options.append(("WScale", ws_hint)) else: # invalid hint, generate new value > 14 options.append( ("WScale", random.randint(15, maxws - 1))) # noqa: E501 else: if ws_hint and 0 <= ws_hint < maxws: options.append(("WScale", ws_hint)) else: # invalid hint, generate new value options.append(("WScale", RandByte())) else: options.append(("WScale", sig.wscale)) elif opt == "ts": ts1, ts2 = ts_hint if "ts1-" in quirks: # own timestamp specified as zero ts1 = 0 elif uptime is not None: # if specified uptime, override ts1 = uptime elif ts1 is None or not (0 < ts1 < 2**32): # invalid hint ts1 = random.randint(120, 100 * 60 * 60 * 24 * 365) # non-zero peer timestamp on initial SYN if "ts2+" in quirks and tcp_type == 0x02: if ts2 is None or not (0 < ts2 < 2**32): # invalid hint ts2 = random.randint(1, 2**32 - 1) else: ts2 = 0 options.append(("Timestamp", (ts1, ts2))) elif opt == "nop": options.append(("NOP", None)) elif opt == "sok": options.append(("SAckOK", "")) elif opt[:3] == "eol": options.append(("EOL", None)) # FIXME: opt+ quirk not handled if "opt+" in quirks: warning("Unhandled opt+ quirk") elif opt == "sack": # Randomize SAck value in range of 10 <= val <= 34 sack_len = random.choice([10, 18, 26, 34]) - 2 optstruct = "!%iI" % (sack_len // 4) rand_val = RandString(struct.calcsize(optstruct))._fix() options.append(("SAck", struct.unpack(optstruct, rand_val))) else: warning("Unhandled TCP option %s", opt) tcp.options = options if sig.win_type == WIN_TYPE_NORMAL: tcp.window = sig.win elif sig.win_type == WIN_TYPE_MSS: mss = [x for x in options if x[0] == "MSS"] if not mss: raise ValueError( "TCP window value requires MSS, and MSS option not set" ) # noqa: E501 tcp.window = mss[0][1] * sig.win elif sig.win_type == WIN_TYPE_MOD: tcp.window = sig.win * random.randint(1, (2**16 - 1) // sig.win) elif sig.win_type == WIN_TYPE_MTU: tcp.window = mtu * sig.win elif sig.win_type == WIN_TYPE_ANY: tcp.window = RandShort() else: warning("Unhandled window size specification") if "seq-" in quirks: tcp.seq = 0 elif tcp.seq == 0: tcp.seq = random.randint(1, 2**32 - 1) if "ack+" in quirks: tcp.flags &= ~(0x10) # ACK flag not set if tcp.ack == 0: tcp.ack = random.randint(1, 2**32 - 1) elif "ack-" in quirks: tcp.flags |= 0x10 # ACK flag set tcp.ack = 0 if "uptr+" in quirks: tcp.flags &= ~(0x020) # URG flag not set if tcp.urgptr == 0: tcp.urgptr = random.randint(1, 2**16 - 1) elif "urgf+" in quirks: tcp.flags |= 0x020 # URG flag used tcp.flags = tcp.flags | 0x08 if "pushf+" in quirks else tcp.flags & ~(0x08) if sig.pay_class: # signature has payload if not tcp.payload: pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) else: tcp.payload = NoPayload() return pkt
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() #pkt = pkt.__class__(raw(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = [x for x in pb if x[6] == osgenre] if osdetails: pb = [x for x in pb if x[7] == osdetails] elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = [x for x in pb if 'K' in x[5]] else: pb = [x for x in pb if 'K' not in x[5]] if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) # Take the options already set as "hints" to use in the new packet if we # can. MSS, WScale and Timestamp can all be wildcarded in a signature, so # we'll use the already-set values if they're valid integers. orig_opts = dict(pkt.payload.options) int_only = lambda val: val if isinstance(val, six.integer_types) else None mss_hint = int_only(orig_opts.get('MSS')) wscale_hint = int_only(orig_opts.get('WScale')) ts_hint = [int_only(o) for o in orig_opts.get('Timestamp', (None, None))] options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16-1) // int(pers[0][1:]) else: maxmss = (2**16-1) # disregard hint if out of range if mss_hint and not 0 <= mss_hint <= maxmss: mss_hint = None # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': if mss_hint is not None: options.append(('MSS', mss_hint)) else: options.append(('MSS', random.randint(1, maxmss))) elif opt[1] == '%': coef = int(opt[2:]) if mss_hint is not None and mss_hint % coef == 0: options.append(('MSS', mss_hint)) else: options.append(( 'MSS', coef*random.randint(1, maxmss//coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if wscale_hint and not 0 <= wscale_hint < 2**8: wscale_hint = None if opt[1:] == '*': if wscale_hint is not None: options.append(('WScale', wscale_hint)) else: options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) if wscale_hint is not None and wscale_hint % coef == 0: options.append(('WScale', wscale_hint)) else: options.append(( 'WScale', coef*RandNum(min=1, max=(2**8-1)//coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': # Determine first timestamp. if uptime is not None: ts_a = uptime elif ts_hint[0] and 0 < ts_hint[0] < 2**32: # Note: if first ts is 0, p0f registers it as "T0" not "T", # hence we don't want to use the hint if it was 0. ts_a = ts_hint[0] else: ts_a = random.randint(120, 100*60*60*24*365) # Determine second timestamp. if 'T' not in pers[5]: ts_b = 0 elif ts_hint[1] and 0 < ts_hint[1] < 2**32: ts_b = ts_hint[1] else: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) ts_b = random.randint(1, 2**32-1) options.append(('Timestamp', (ts_a, ts_b))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append((optname, struct.unpack(optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) ## FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1, max=(2**16-1)//coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': ## needs MSS set mss = [x for x in options if x[0] == 'MSS'] if not mss: raise Scapy_Exception("TCP window value requires MSS, and MSS option not set") pkt.payload.window = mss[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1]-extrahops # DF flag pkt.flags |= (2 * pers[2]) ## FIXME: ss (packet size) not handled (how ? may be with D quirk ## if present) # Quirks if pers[5] != '.': for qq in pers[5]: ## FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= random.choice([8, 32, 40]) # P/U/PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint(1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack #elif qq == '0': pkt.payload.seq = 0 #if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
def __rdiv__(self, other): if type(other) is str: return conf.raw_layer(load=other)/self else: raise TypeError