def i2m(self, pkt, p): """ Update the context with information from the built packet. If no type was given at the record layer, we try to infer it. """ cur = b"" if isinstance(p, _GenericTLSSessionInheritance): if pkt.type is None: if isinstance(p, TLSChangeCipherSpec): pkt.type = 20 elif isinstance(p, TLSAlert): pkt.type = 21 elif isinstance(p, _TLSHandshake): pkt.type = 22 elif isinstance(p, TLSApplicationData): pkt.type = 23 p.tls_session = pkt.tls_session if not pkt.tls_session.frozen: cur = p.raw_stateful() p.post_build_tls_session_update(cur) else: cur = raw(p) else: pkt.type = 23 cur = raw(p) return cur
def verifyCert(self, cert): """ Verifies either a Cert or an X509_Cert. """ tbsCert = cert.tbsCertificate sigAlg = tbsCert.signature h = hash_by_oid[sigAlg.algorithm.val] sigVal = raw(cert.signatureValue) return self.verify(raw(tbsCert), sigVal, h=h, t='pkcs')
def import_from_asn1pkt(self, cert): error_msg = "Unable to import certificate" self.x509Cert = cert tbsCert = cert.tbsCertificate self.tbsCertificate = tbsCert if tbsCert.version: self.version = tbsCert.version.val + 1 else: self.version = 1 self.serial = tbsCert.serialNumber.val self.sigAlg = tbsCert.signature.algorithm.oidname self.issuer = tbsCert.get_issuer() self.issuer_str = tbsCert.get_issuer_str() self.issuer_hash = hash(self.issuer_str) self.subject = tbsCert.get_subject() self.subject_str = tbsCert.get_subject_str() self.subject_hash = hash(self.subject_str) self.authorityKeyID = None self.notBefore_str = tbsCert.validity.not_before.pretty_time notBefore = tbsCert.validity.not_before.val if notBefore[-1] == "Z": notBefore = notBefore[:-1] try: self.notBefore = time.strptime(notBefore, "%y%m%d%H%M%S") except Exception: raise Exception(error_msg) self.notBefore_str_simple = time.strftime("%x", self.notBefore) self.notAfter_str = tbsCert.validity.not_after.pretty_time notAfter = tbsCert.validity.not_after.val if notAfter[-1] == "Z": notAfter = notAfter[:-1] try: self.notAfter = time.strptime(notAfter, "%y%m%d%H%M%S") except Exception: raise Exception(error_msg) self.notAfter_str_simple = time.strftime("%x", self.notAfter) self.pubKey = PubKey(raw(tbsCert.subjectPublicKeyInfo)) if tbsCert.extensions: for extn in tbsCert.extensions: if extn.extnID.oidname == "basicConstraints": self.cA = False if extn.extnValue.cA: self.cA = not (extn.extnValue.cA.val == 0) elif extn.extnID.oidname == "keyUsage": self.keyUsage = extn.extnValue.get_keyUsage() elif extn.extnID.oidname == "extKeyUsage": self.extKeyUsage = extn.extnValue.get_extendedKeyUsage() elif extn.extnID.oidname == "authorityKeyIdentifier": self.authorityKeyID = extn.extnValue.keyIdentifier.val self.signatureValue = raw(cert.signatureValue) self.signatureLen = len(self.signatureValue)
def post_build(self, pkt, pay): """ need to set the length of the whole PDU manually to avoid any bit fiddling use a dummy class to build the layer content also add padding if frame is < 64 bytes Note: padding only handles Ether/n*Dot1Q/EtherCat (no special mumbo jumbo) :param pkt: raw string containing the current layer :param pay: raw string containing the payload :return: <new current layer> + payload """ class _EtherCatLengthCalc(Packet): """ dummy class used to generate str representation easily """ fields_desc = [ LEBitField('length', None, 11), LEBitField('_reserved', 0, 1), LEBitField('type', 0, 4), ] payload_len = len(pay) # length field is 11 bit if payload_len > 2047: raise ValueError('payload size {} exceeds maximum length {} ' 'of EtherCat message.'.format(payload_len, 2047)) self.length = payload_len vlan_headers_total_size = 0 upper_layer = self.underlayer # add size occupied by VLAN tags while upper_layer and isinstance(upper_layer, Dot1Q): vlan_headers_total_size += 4 upper_layer = upper_layer.underlayer if not isinstance(upper_layer, Ether): raise Exception('missing Ether layer') pad_len = EtherCat.ETHER_FRAME_MIN_LEN - (EtherCat.ETHER_HEADER_LEN + vlan_headers_total_size + EtherCat.ETHERCAT_HEADER_LEN + # noqa: E501 payload_len + EtherCat.ETHER_FSC_LEN) if pad_len > 0: pad = Padding() pad.load = b'\x00' * pad_len return raw(_EtherCatLengthCalc(length=self.length, type=self.type)) + pay + raw(pad) return raw(_EtherCatLengthCalc(length=self.length, type=self.type)) + pay
def _encrypt_esp(self, pkt, seq_num=None, iv=None): if iv is None: iv = self.crypt_algo.generate_iv() else: if len(iv) != self.crypt_algo.iv_size: raise TypeError('iv length must be %s' % self.crypt_algo.iv_size) esp = _ESPPlain(spi=self.spi, seq=seq_num or self.seq_num, iv=iv) if self.tunnel_header: tunnel = self.tunnel_header.copy() if tunnel.version == 4: del tunnel.proto del tunnel.len del tunnel.chksum else: del tunnel.nh del tunnel.plen pkt = tunnel.__class__(raw(tunnel / pkt)) ip_header, nh, payload = split_for_transport(pkt, socket.IPPROTO_ESP) esp.data = payload esp.nh = nh esp = self.crypt_algo.pad(esp) esp = self.crypt_algo.encrypt(self, esp, self.crypt_key) self.auth_algo.sign(esp, self.auth_key) if self.nat_t_header: nat_t_header = self.nat_t_header.copy() nat_t_header.chksum = 0 del nat_t_header.len if ip_header.version == 4: del ip_header.proto else: del ip_header.nh ip_header /= nat_t_header if ip_header.version == 4: ip_header.len = len(ip_header) + len(esp) del ip_header.chksum ip_header = ip_header.__class__(raw(ip_header)) else: ip_header.plen = len(ip_header.payload) + len(esp) # sequence number must always change, unless specified by the user if seq_num is None: self.seq_num += 1 return ip_header / esp
def i2m(self, pkt, p): cur = b"" if isinstance(p, _GenericTLSSessionInheritance): p.tls_session = pkt.tls_session if not pkt.tls_session.frozen: cur = p.raw_stateful() p.post_build_tls_session_update(cur) else: cur = raw(p) else: cur = raw(p) return cur
def _encrypt_ah(self, pkt, seq_num=None): ah = AH(spi=self.spi, seq=seq_num or self.seq_num, icv = b"\x00" * self.auth_algo.icv_size) if self.tunnel_header: tunnel = self.tunnel_header.copy() if tunnel.version == 4: del tunnel.proto del tunnel.len del tunnel.chksum else: del tunnel.nh del tunnel.plen pkt = tunnel.__class__(raw(tunnel / pkt)) ip_header, nh, payload = split_for_transport(pkt, socket.IPPROTO_AH) ah.nh = nh if ip_header.version == 6 and len(ah) % 8 != 0: # For IPv6, the total length of the header must be a multiple of # 8-octet units. ah.padding = b"\x00" * (-len(ah) % 8) elif len(ah) % 4 != 0: # For IPv4, the total length of the header must be a multiple of # 4-octet units. ah.padding = b"\x00" * (-len(ah) % 4) # RFC 4302 - Section 2.2. Payload Length # This 8-bit field specifies the length of AH in 32-bit words (4-byte # units), minus "2". ah.payloadlen = len(ah) // 4 - 2 if ip_header.version == 4: ip_header.len = len(ip_header) + len(ah) + len(payload) del ip_header.chksum ip_header = ip_header.__class__(raw(ip_header)) else: ip_header.plen = len(ip_header.payload) + len(ah) + len(payload) signed_pkt = self.auth_algo.sign(ip_header / ah / payload, self.auth_key) # sequence number must always change, unless specified by the user if seq_num is None: self.seq_num += 1 return signed_pkt
def parse_args(self, server="127.0.0.1", dport=4433, server_name=None, mycert=None, mykey=None, client_hello=None, version=None, data=None, **kargs): super(TLSClientAutomaton, self).parse_args(mycert=mycert, mykey=mykey, **kargs) tmp = socket.getaddrinfo(server, dport) self.remote_name = None try: if ':' in server: inet_pton(socket.AF_INET6, server) else: inet_pton(socket.AF_INET, server) except Exception: self.remote_name = socket.getfqdn(server) if self.remote_name != server: tmp = socket.getaddrinfo(self.remote_name, dport) if server_name: self.remote_name = server_name self.remote_family = tmp[0][0] self.remote_ip = tmp[0][4][0] self.remote_port = dport self.local_ip = None self.local_port = None self.socket = None self.client_hello = client_hello self.advertised_tls_version = None if version: v = _tls_version_options.get(version, None) if not v: self.vprint("Unrecognized TLS version option.") else: self.advertised_tls_version = v self.linebreak = False if isinstance(data, bytes): self.data_to_send = [data] elif isinstance(data, six.string_types): self.data_to_send = [raw(data)] elif isinstance(data, list): self.data_to_send = list(raw(d) for d in reversed(data)) else: self.data_to_send = []
def _decrypt_ah(self, pkt, verify=True): if verify: self.check_spi(pkt) self.auth_algo.verify(pkt, self.auth_key) ah = pkt[AH] payload = ah.payload payload.remove_underlayer(None) # useless argument... if self.tunnel_header: return payload else: ip_header = pkt if ip_header.version == 4: ip_header.proto = ah.nh del ip_header.chksum ip_header.remove_payload() ip_header.len = len(ip_header) + len(payload) # recompute checksum ip_header = ip_header.__class__(raw(ip_header)) else: ah.underlayer.nh = ah.nh ah.underlayer.remove_payload() ip_header.plen = len(ip_header.payload) + len(payload) # reassemble the ip_header with the AH payload return ip_header / payload
def send(self, x): try: sx = raw(x) x.sent_time = time.time() self.outs.sendto(sx, (x.dst, 0)) except socket.error as msg: log_runtime.error(msg)
def send_wpa_enc(self, data, iv, seqnum, dest, mic_key, key_idx=0, additionnal_flag=["from-DS"], encrypt_key=None): """Send an encrypted packet with content @data, using IV @iv, sequence number @seqnum, MIC key @mic_key """ if encrypt_key is None: encrypt_key = self.tk rep = RadioTap() rep /= Dot11( addr1=dest, addr2=self.mac, addr3=self.mac, FCfield="+".join(['wep'] + additionnal_flag), SC=(next(self.seq_num) << 4), subtype=0, type="Data", ) # Assume packet is send by our AP -> use self.mac as source # Encapsule in TKIP with MIC Michael and ICV data_to_enc = build_MIC_ICV(raw(data), mic_key, self.mac, dest) # Header TKIP + payload rep /= Raw(build_TKIP_payload(data_to_enc, iv, self.mac, encrypt_key)) self.send(rep) return rep
def sixlowpan_fragment(packet, datagram_tag=1): """Split a packet into different links to transmit as 6lowpan packets. Usage example: >>> ipv6 = ..... (very big packet) >>> pkts = sixlowpan_fragment(ipv6, datagram_tag=0x17) >>> send = [Dot15d4()/Dot15d4Data()/x for x in pkts] >>> wireshark(send) """ if not packet.haslayer(IPv6): raise Exception("SixLoWPAN only fragments IPv6 packets !") str_packet = raw(packet[IPv6]) if len(str_packet) <= MAX_SIZE: return [packet] def chunks(l, n): return [l[i:i + n] for i in range(0, len(l), n)] new_packet = chunks(str_packet, MAX_SIZE) new_packet[0] = LoWPANFragmentationFirst(datagramTag=datagram_tag, datagramSize=len(str_packet)) / new_packet[0] # noqa: E501 i = 1 while i < len(new_packet): new_packet[i] = LoWPANFragmentationSubsequent(datagramTag=datagram_tag, datagramSize=len(str_packet), datagramOffset=MAX_SIZE // 8 * i) / new_packet[i] # noqa: E501 i += 1 return new_packet
def send(self, x): data = raw(x) if self.cls not in x: raise Scapy_Exception("L3WinSocket can only send IP/IPv6 packets !" " Install Npcap/Winpcap to send more") dst_ip = str(x[self.cls].dst) self.outs.sendto(data, (dst_ip, 0))
def post_build(self, p, pay): if self.properties == []: p += raw(OFPQTNone()) if self.len is None: l = len(p) + len(pay) p = p[:4] + struct.pack("!H", l) + p[6:] return p + pay
def i2m(self, pkt, x): if x is None: s = b"" else: s = raw(x) return BER_tagging_enc(s, implicit_tag=self.implicit_tag, explicit_tag=self.explicit_tag)
def _tls_P_hash(secret, seed, req_len, hm): """ Provides the implementation of P_hash function defined in section 5 of RFC 4346 (and section 5 of RFC 5246). Two parameters have been added (hm and req_len): - secret : the key to be used. If RFC 4868 is to be believed, the length must match hm.key_len. Actually, python hmac takes care of formatting every key. - seed : the seed to be used. - req_len : the length of data to be generated by iterating the specific HMAC function (hm). This prevents multiple calls to the function. - hm : the hmac function class to use for iteration (either Hmac_MD5 or Hmac_SHA1 in TLS <= 1.1 or Hmac_SHA256 or Hmac_SHA384 in TLS 1.2) """ hash_len = hm.hash_alg.hash_len n = (req_len + hash_len - 1) // hash_len res = b"" a = hm(secret).digest(seed) # A(1) while n > 0: res += hm(secret).digest(a + raw(seed)) a = hm(secret).digest(a) n -= 1 return res[:req_len]
def self_build(self, field_pos_list=None): """ Implements the swap-bytes functionality when building this is based on a copy of the Packet.self_build default method. The goal is to affect only the CAN layer data and keep under layers (e.g LinuxCooked) unchanged """ if self.raw_packet_cache is not None: for fname, fval in six.iteritems(self.raw_packet_cache_fields): if self.getfieldval(fname) != fval: self.raw_packet_cache = None self.raw_packet_cache_fields = None break if self.raw_packet_cache is not None: if conf.contribs['CAN']['swap-bytes']: return CAN.inv_endianness(self.raw_packet_cache) return self.raw_packet_cache p = b"" for f in self.fields_desc: val = self.getfieldval(f.name) if isinstance(val, RawVal): sval = raw(val) p += sval if field_pos_list is not None: field_pos_list.append((f.name, sval.encode('string_escape'), len(p), len(sval))) else: p = f.addfield(self, p, val) if conf.contribs['CAN']['swap-bytes']: return CAN.inv_endianness(p) return p
def build(self, pkt): val = getattr(pkt, self.name) if isinstance(val, ASN1_Object) and val.tag == ASN1_Class_UNIVERSAL.RAW: # noqa: E501 s = val elif val is None: s = b"" else: s = b"".join(raw(i) for i in val) return self.i2m(pkt, s)
def i2m(self, pkt, x): if x is None: s = b"" else: s = raw(x) if hash(type(x)) in self.pktchoices: imp, exp = self.pktchoices[hash(type(x))] s = BER_tagging_enc(s, implicit_tag=imp, explicit_tag=exp) return BER_tagging_enc(s, explicit_tag=self.explicit_tag)
def __call__(cls, key_path=None): """ key_path may be the path to either: _an RSAPrivateKey_OpenSSL (as generated by openssl); _an ECDSAPrivateKey_OpenSSL (as generated by openssl); _an RSAPrivateKey; _an ECDSAPrivateKey. """ if key_path is None: obj = type.__call__(cls) if cls is PrivKey: cls = PrivKeyECDSA obj.__class__ = cls obj.frmt = "original" obj.fill_and_store() return obj obj = _PKIObjMaker.__call__(cls, key_path, _MAX_KEY_SIZE) multiPEM = False try: privkey = RSAPrivateKey_OpenSSL(obj.der) privkey = privkey.privateKey obj.__class__ = PrivKeyRSA marker = b"PRIVATE KEY" except Exception: try: privkey = ECDSAPrivateKey_OpenSSL(obj.der) privkey = privkey.privateKey obj.__class__ = PrivKeyECDSA marker = b"EC PRIVATE KEY" multiPEM = True except Exception: try: privkey = RSAPrivateKey(obj.der) obj.__class__ = PrivKeyRSA marker = b"RSA PRIVATE KEY" except Exception: try: privkey = ECDSAPrivateKey(obj.der) obj.__class__ = PrivKeyECDSA marker = b"EC PRIVATE KEY" except Exception: raise Exception("Unable to import private key") try: obj.import_from_asn1pkt(privkey) except ImportError: pass if obj.frmt == "DER": if multiPEM: # this does not restore the EC PARAMETERS header obj.pem = der2pem(raw(privkey), marker) else: obj.pem = der2pem(obj.der, marker) return obj
def sign(self, M, t="pkcs", h="sha256", mgf=None, L=None): M = raw(M) mgf = mgf or padding.MGF1 h = _get_hash(h) pad = _get_padding(t, mgf, h, L) try: return self.key.sign(M, pad, h) except UnsupportedAlgorithm: if t != "pkcs" and h != "md5-sha1": raise UnsupportedAlgorithm("RSA signature with %s" % h) return self._legacy_sign_md5_sha1(M)
def send(self, x): try: return SuperSocket.send(self, x) except socket.error as msg: if msg.errno == 22 and len(x) < conf.min_pkt_size: padding = b"\x00" * (conf.min_pkt_size - len(x)) if isinstance(x, Packet): return SuperSocket.send(self, x / Padding(load=padding)) else: return SuperSocket.send(self, raw(x) + padding) raise
def enc(cls, oid): oid = raw(oid) if oid: lst = [int(x) for x in oid.strip(b".").split(b".")] else: lst = list() if len(lst) >= 2: lst[1] += 40 * lst[0] del(lst[0]) s = b"".join(BER_num_enc(k) for k in lst) return chb(hash(cls.tag)) + BER_len_enc(len(s)) + s
def send(self, x): # Makes send detects when it should add Loopback(), Dot11... instead of Ether() # noqa: E501 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) # noqa: E501 sx = raw(cls() / x) if hasattr(x, "sent_time"): x.sent_time = time.time() return self.ins.send(sx)
def enc(cls, s): # /!\ this is DER encoding (bit strings are only zero-bit padded) s = raw(s) if len(s) % 8 == 0: unused_bits = 0 else: unused_bits = 8 - len(s) % 8 s += b"0" * unused_bits s = b"".join(chb(int(b"".join(chb(y) for y in x), 2)) for x in zip(*[iter(s)] * 8)) s = chb(unused_bits) + s return chb(hash(cls.tag)) + BER_len_enc(len(s)) + s
def sixlowpan_defragment(packet_list): results = {} for p in packet_list: cls = None if LoWPANFragmentationFirst in p: cls = LoWPANFragmentationFirst elif LoWPANFragmentationSubsequent in p: cls = LoWPANFragmentationSubsequent if cls: tag = p[cls].datagramTag results[tag] = results.get(tag, b"") + raw(p[cls][LoWPAN_IPHC].payload) # noqa: E501 return {tag: IPv6(x) for tag, x in results.items()}
def decap(self, orig_pkt): """decapsulate a MACsec frame""" if orig_pkt.name != Ether().name or orig_pkt.payload.name != MACsec().name: # noqa: E501 raise TypeError('cannot decapsulate MACsec packet, must be Ethernet/MACsec') # noqa: E501 packet = copy.deepcopy(orig_pkt) prev_layer = packet[MACsec].underlayer prev_layer.type = packet[MACsec].type next_layer = packet[MACsec].payload del prev_layer.payload if prev_layer.name == Ether().name: return Ether(raw(prev_layer / next_layer)) return prev_layer / next_layer
def sixlowpan_defragment(packet_list): results = {} for p in packet_list: cls = None if LoWPANFragmentationFirst in p: cls = LoWPANFragmentationFirst elif LoWPANFragmentationSubsequent in p: cls = LoWPANFragmentationSubsequent if cls: tag = p[cls].datagramTag results[tag] = results.get(tag, b"") + raw( p[cls][LoWPAN_IPHC].payload) return {tag: IPv6(x) for tag, x in results.items()}
def nmap_udppacket_sig(snd, rcv): res = {} if rcv is None: res["Resp"] = "N" else: res["DF"] = "Y" if rcv.flags.DF else "N" res["TOS"] = "%X" % rcv.tos res["IPLEN"] = "%X" % rcv.len res["RIPTL"] = "%X" % rcv.payload.payload.len res["RID"] = "E" if snd.id == rcv[IPerror].id else "F" res["RIPCK"] = "E" if snd.chksum == rcv[IPerror].chksum else ( "0" if rcv[IPerror].chksum == 0 else "F" ) res["UCK"] = "E" if snd.payload.chksum == rcv[UDPerror].chksum else ( "0" if rcv[UDPerror].chksum == 0 else "F" ) res["ULEN"] = "%X" % rcv[UDPerror].len res["DAT"] = "E" if ( isinstance(rcv[UDPerror].payload, NoPayload) or raw(rcv[UDPerror].payload) == raw(snd[UDP].payload) ) else "F" return res
def _process_packet(self, pkt): """Process each packet: matches the TCP seq/ack numbers to follow the TCP streams, and orders the fragments. """ from scapy.layers.inet import IP, TCP if TCP not in pkt: return pkt pay = pkt[TCP].payload if isinstance(pay, (NoPayload, conf.padding_layer)): return pkt new_data = raw(pay) # Match packets by a uniqute TCP identifier seq = pkt[TCP].seq ident = pkt.sprintf(self.fmt) data, metadata = self.tcp_frags[ident] # Let's guess which class is going to be used if "pay_class" not in metadata: pay_class = pay.__class__ if not hasattr(pay_class, "tcp_reassemble"): # Cannot tcp-reassemble return pkt metadata["pay_class"] = pay_class else: pay_class = metadata["pay_class"] # Get a relative sequence number for a storage purpose relative_seq = metadata.get("relative_seq", None) if not relative_seq: relative_seq = metadata["relative_seq"] = seq - 1 seq = seq - relative_seq # Add the data to the buffer # Note that this take care of retransmission packets. data.append(new_data, seq) # Check TCP FIN or TCP RESET if pkt[TCP].flags.F or pkt[TCP].flags.R or pkt[TCP].flags.P: metadata["tcp_end"] = True # XXX TODO: check that no empty space is missing in the buffer. # XXX Currently, if a TCP fragment was missing, we won't notice it. packet = None if data.full(): # Reassemble using all previous packets packet = pay_class.tcp_reassemble(bytes(data), metadata) # Stack the result on top of the previous frames if packet: data.clear() del self.tcp_frags[ident] pay.underlayer.remove_payload() if IP in pkt: pkt[IP].len = None pkt[IP].chksum = None return pkt / packet
def decap(self, orig_pkt): """decapsulate a MACsec frame""" if not isinstance(orig_pkt, Ether) or \ not isinstance(orig_pkt.payload, MACsec): raise TypeError( 'cannot decapsulate MACsec packet, must be Ethernet/MACsec') packet = copy.deepcopy(orig_pkt) prev_layer = packet[MACsec].underlayer prev_layer.type = packet[MACsec].type next_layer = packet[MACsec].payload del prev_layer.payload if prev_layer.name == Ether().name: return Ether(raw(prev_layer / next_layer)) return prev_layer / next_layer
def send(self, x): # Makes send detects when it should add Loopback(), Dot11... instead of Ether() # noqa: E501 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) # noqa: E501 sx = raw(cls() / x) if hasattr(x, "sent_time"): x.sent_time = time.time() return self.ins.send(sx)
def i2m(self, pkt, i): if i is None: return b"" if isinstance(pkt, _GenericTLSSessionInheritance): if not pkt.tls_session.frozen: s = b"" for ext in i: if isinstance(ext, _GenericTLSSessionInheritance): ext.tls_session = pkt.tls_session s += ext.raw_stateful() else: s += raw(ext) return s return b"".join(map(raw, i))
def prepare_packed_data(radius_packet, packed_req_authenticator): """ Pack RADIUS data prior computing the authentication MAC """ packed_hdr = struct.pack("!B", radius_packet.code) packed_hdr += struct.pack("!B", radius_packet.id) packed_hdr += struct.pack("!H", radius_packet.len) packed_attrs = b'' for attr in radius_packet.attributes: packed_attrs += raw(attr) return packed_hdr + packed_req_authenticator + packed_attrs
def is_request(self, pkt): if not isinstance(pkt, Dot11): return 0 if not pkt.FCfield & 1: return 0 if not pkt.haslayer(TCP): return 0 tcp = pkt.getlayer(TCP) pay = raw(tcp.payload) if not self.ptrn.match(pay): return 0 if self.iptrn.match(pay) is True: return 0 return True
def split_pkt(pkt, assoclen, icvlen=0): """ split the packet into associated data, plaintext or ciphertext, and optional ICV """ data = raw(pkt) assoc = data[:assoclen] if icvlen: icv = data[-icvlen:] enc = data[assoclen:-icvlen] else: icv = b'' enc = data[assoclen:] return assoc, enc, icv
def test_0603_bofpacket_addpayload_automatic(self): """Test that we can dynamically bind payloads. ScapyBasicOtterPacket 1 and 3 are not bound in Scapy implementation. """ bof_pkt = BOFPacket(scapy_pkt=ScapyBasicOtterPacket1()) bof_pkt.append(ScapyBasicOtterPacket3(), autobind=True) self.assertEqual(bof_pkt.scapy_pkt.payload.get_field("basic_otter_3_1").name, "basic_otter_3_1") self.assertEqual(bof_pkt.scapy_pkt.getlayer("ScapyBasicOtterPacket3").get_field("basic_otter_3_1").name, "basic_otter_3_1") self.assertEqual(bytes(bof_pkt), bytes(ScapyBasicOtterPacket1()) + bytes(ScapyBasicOtterPacket3())) # effectively tests for "logical" payload binding (in addition to the correct frame bytes) self.assertEqual(bof_pkt.scapy_pkt.__class__(raw(bof_pkt.scapy_pkt)).payload.name, "basic_otter_packet_3")
def i2m(self, pkt, x): if isinstance(x, str): return x s = b"" for o in x: if isinstance(o, tuple) and len(o) >= 2: name = o[0] lval = o[1:] if isinstance(name, int): onum, oval = name, b"".join(lval) elif name in DHCPRevOptions: onum, f = DHCPRevOptions[name] if f is not None: lval = (f.addfield(pkt, b"", f.any2i(pkt, val)) for val in lval) # noqa: E501 else: lval = (raw(x) for x in lval) oval = b"".join(lval) else: warning("Unknown field option %s", name) continue s += chb(onum) s += chb(len(oval)) s += oval elif (isinstance(o, str) and o in DHCPRevOptions and DHCPRevOptions[o][1] is None): s += chb(DHCPRevOptions[o][0]) elif isinstance(o, int): s += chb(o) + b"\0" elif isinstance(o, (str, bytes)): s += raw(o) else: warning("Malformed option %s", o) return s
def split_for_transport(orig_pkt, transport_proto): """ Split an IP(v6) packet in the correct location to insert an ESP or AH header. @param orig_pkt: the packet to split. Must be an IP or IPv6 packet @param transport_proto: the IPsec protocol number that will be inserted at the split position. @return: a tuple (header, nh, payload) where nh is the protocol number of payload. """ # force resolution of default fields to avoid padding errors header = orig_pkt.__class__(raw(orig_pkt)) next_hdr = header.payload nh = None if header.version == 4: nh = header.proto header.proto = transport_proto header.remove_payload() del header.chksum del header.len return header, nh, next_hdr else: found_rt_hdr = False prev = header # Since the RFC 4302 is vague about where the ESP/AH headers should be # inserted in IPv6, I chose to follow the linux implementation. while isinstance( next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)): if isinstance(next_hdr, IPv6ExtHdrHopByHop): pass if isinstance(next_hdr, IPv6ExtHdrRouting): found_rt_hdr = True elif isinstance(next_hdr, IPv6ExtHdrDestOpt) and found_rt_hdr: break prev = next_hdr next_hdr = next_hdr.payload nh = prev.nh prev.nh = transport_proto prev.remove_payload() del header.plen return header, nh, next_hdr
def sign(self, pkt, key): """ Sign an IPsec (ESP or AH) packet with this algo. @param pkt: a packet that contains a valid encrypted ESP or AH layer @param key: the authentication key, a byte string @return: the signed packet """ if not self.mac: return pkt mac = self.new_mac(key) if pkt.haslayer(ESP): mac.update(raw(pkt[ESP])) pkt[ESP].data += mac.finalize()[:self.icv_size] elif pkt.haslayer(AH): clone = zero_mutable_fields(pkt.copy(), sending=True) mac.update(raw(clone)) pkt[AH].icv = mac.finalize()[:self.icv_size] return pkt
def decap(self, orig_pkt): """decapsulate a MACsec frame""" if orig_pkt.name != Ether().name or orig_pkt.payload.name != MACsec( ).name: # noqa: E501 raise TypeError( 'cannot decapsulate MACsec packet, must be Ethernet/MACsec' ) # noqa: E501 packet = copy.deepcopy(orig_pkt) prev_layer = packet[MACsec].underlayer prev_layer.type = packet[MACsec].type next_layer = packet[MACsec].payload del prev_layer.payload if prev_layer.name == Ether().name: return Ether(raw(prev_layer / next_layer)) return prev_layer / next_layer
def send(self, x): # type: (Packet) -> int try: x.sent_time = time.time() except AttributeError: pass # need to change the byte order of the first four bytes, # required by the underlying Linux SocketCAN frame format bs = raw(x) if not conf.contribs['CAN']['swap-bytes']: bs = bs + b'\x00' * (CAN_MTU - len(bs)) bs = struct.pack("<I12s", *struct.unpack(">I12s", bs)) return super(NativeCANSocket, self).send(bs) # type: ignore
def test_0605_bofpacket_addpayload_automatic_guess(self): """Test dynamic payload binding when specific conditions are used via guess_payload in Scapy implementation""" bof_pkt = BOFPacket(scapy_pkt=ScapyOtterGuessPayloadPacket1()) bof_pkt.append(ScapyBasicOtterPacket3(), autobind=True) self.assertEqual(bof_pkt.scapy_pkt.payload.get_field("basic_otter_3_1").name, "basic_otter_3_1") self.assertEqual( bof_pkt.scapy_pkt.getlayer("ScapyBasicOtterPacket3").get_field("basic_otter_3_1").name, "basic_otter_3_1") self.assertEqual(bytes(bof_pkt), bytes(ScapyOtterGuessPayloadPacket1()) + bytes(ScapyBasicOtterPacket3())) # effectively tests for "logical" payload binding (in addition to the correct frame bytes) self.assertEqual(bof_pkt.scapy_pkt.__class__(raw(bof_pkt.scapy_pkt)).payload.name, "basic_otter_packet_3")
def verify(self, M, S, t="pkcs", h="sha256", mgf=None, L=None): M = raw(M) mgf = mgf or padding.MGF1 h = _get_hash(h) pad = _get_padding(t, mgf, h, L) try: try: self.pubkey.verify(S, M, pad, h) except UnsupportedAlgorithm: if t != "pkcs" and h != "md5-sha1": raise UnsupportedAlgorithm("RSA verification with %s" % h) self._legacy_verify_md5_sha1(M, S) return True except InvalidSignature: return False
def send_assoc_response(self, pkt): # Get RSN info temp_pkt = pkt[Dot11Elt::{"ID": 48}].copy() temp_pkt.remove_payload() self.RSN = raw(temp_pkt) # Avoid 802.11w, etc. (deactivate RSN capabilities) self.RSN = self.RSN[:-2] + "\x00\x00" rep = RadioTap() rep /= Dot11(addr1=self.client, addr2=self.mac, addr3=self.mac) rep /= Dot11AssoResp() rep /= Dot11EltRates(rates=[130, 132, 139, 150, 12, 18, 24, 36]) self.send(rep)
def send(self, x): iff = x.route()[0] if iff is None: iff = conf.iface sdto = (iff, self.type) self.outs.bind(sdto) sn = self.outs.getsockname() ll = lambda x: x if type(x) in conf.l3types: sdto = (iff, conf.l3types[type(x)]) if sn[3] in conf.l2types: ll = lambda x: conf.l2types[sn[3]]() / x sx = raw(ll(x)) x.sent_time = time.time() try: self.outs.sendto(sx, sdto) except socket.error as msg: if msg.errno == 22 and len(sx) < conf.min_pkt_size: self.outs.send(sx + b"\x00" * (conf.min_pkt_size - len(sx))) elif conf.auto_fragment and msg.errno == 90: for p in x.fragment(): self.outs.sendto(raw(ll(p)), sdto) else: raise
def send_assoc_response(self, pkt): # Get RSN info temp_pkt = pkt[Dot11Elt::{"ID": 48}].copy() temp_pkt.remove_payload() self.RSN = raw(temp_pkt) # Avoid 802.11w, etc. (deactivate RSN capabilities) self.RSN = self.RSN[:-2] + "\x00\x00" rep = RadioTap() rep /= Dot11(addr1=self.client, addr2=self.mac, addr3=self.mac) rep /= Dot11AssoResp() rep /= Dot11Elt(ID="Rates", info='\x82\x84\x8b\x96\x0c\x12\x18$') self.send(rep)
def __init__(self, name, # type: str default, # type: Optional[ASN1_Packet] cls, # type: Type[ASN1_Packet] context=None, # type: Optional[Any] implicit_tag=None, # type: Optional[int] explicit_tag=None, # type: Optional[int] ): # type: (...) -> None self.cls = cls super(ASN1F_BIT_STRING_ENCAPS, self).__init__( name, default and raw(default), context=context, implicit_tag=implicit_tag, explicit_tag=explicit_tag )
def send(self, x): # type: (Packet) -> int try: sx = raw(x) if self.outs: x.sent_time = time.time() return self.outs.sendto(sx, (x.dst, 0)) except AttributeError: raise ValueError( "Missing 'dst' attribute in the first layer to be " "sent using a native L3 socket ! (make sure you passed the " "IP layer)") except socket.error as msg: log_runtime.error(msg) return 0
def _legacy_pkcs1_v1_5_encode_md5_sha1(M, emLen): """ Legacy method for PKCS1 v1.5 encoding with MD5-SHA1 hash. """ M = raw(M) md5_hash = hashes.Hash(_get_hash("md5"), backend=default_backend()) md5_hash.update(M) sha1_hash = hashes.Hash(_get_hash("sha1"), backend=default_backend()) sha1_hash.update(M) H = md5_hash.finalize() + sha1_hash.finalize() if emLen < 36 + 11: warning("pkcs_emsa_pkcs1_v1_5_encode: " "intended encoded message length too short") return None PS = b'\xff' * (emLen - 36 - 3) return b'\x00' + b'\x01' + PS + b'\x00' + H
def assert_redirect_to_real_server_ipv6(test, real_server_ip, packet_in, result): test.assertEqual(BPF.XDP_TX, result.retval) # client -> virtual server # become # client -> given real server expected = packet_in.copy() expected[Ether].dst = packet_in[Ether].src expected[Ether].src = packet_in[Ether].dst expected[IPv6].dst = real_server_ip expected[IPv6].hlim = packet_in[IPv6].hlim - 1 # force checksum calculation del expected[UDP].chksum expected = Ether(raw(expected)) test.assertEqual(expected, result.packet)
def send(self, data, address: tuple = None) -> int: """Converts BOF and Scapy frames to bytes to send. Relies on ``TCP`` class to send data. :param data: Data to send as ``ModbusPacket``, Scapy ``Packet``, string or bytes. Will be converted to bytes anyway. :param address: Address to send ``data`` to, with format ``(ip, port)``. If address is not specified, uses the address given to `` connect``. :returns: The number of bytes sent, as an integer. """ if isinstance(data, ModbusPacket): data = bytes(data) elif isinstance(data, Packet): data = raw(data) return super().send(data, address)
def test_0604_bofpacket_addpayload_automatic_layer(self): """Test that we can bind payloads with another layer than the 1st one. (This was a bug because we were not binding with the last) Here, Packet 2 is bound to 1, but Packet 2 is not bound to 3 by default. """ bof_pkt1 = BOFPacket(scapy_pkt=ScapyBasicOtterPacket1() / ScapyBasicOtterPacket2()) bof_pkt1.append(ScapyBasicOtterPacket3(), autobind=True) self.assertEqual(bof_pkt1.scapy_pkt.payload.payload.get_field("basic_otter_3_1").name, "basic_otter_3_1") self.assertEqual(bof_pkt1.scapy_pkt.getlayer("ScapyBasicOtterPacket3").get_field("basic_otter_3_1").name, "basic_otter_3_1") self.assertEqual(bytes(bof_pkt1), bytes(ScapyBasicOtterPacket1()) + bytes(ScapyBasicOtterPacket2()) + bytes(ScapyBasicOtterPacket3())) # effectively tests for "logical" payload binding (in addition to the correct frame bytes) self.assertEqual(bof_pkt1.scapy_pkt.__class__(raw(bof_pkt1.scapy_pkt)).payload.payload.name, "basic_otter_packet_3")
def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None): encrypted = pkt[ESP] if verify: self.check_spi(pkt) self.auth_algo.verify(encrypted, self.auth_key) esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key, self.crypt_algo.icv_size or self.auth_algo.icv_size, esn_en=esn_en or self.esn_en, esn=esn or self.esn) if self.tunnel_header: # drop the tunnel header and return the payload untouched pkt.remove_payload() if pkt.version == 4: pkt.proto = esp.nh else: pkt.nh = esp.nh cls = pkt.guess_payload_class(esp.data) return cls(esp.data) else: ip_header = pkt if ip_header.version == 4: ip_header.proto = esp.nh del ip_header.chksum ip_header.remove_payload() ip_header.len = len(ip_header) + len(esp.data) # recompute checksum ip_header = ip_header.__class__(raw(ip_header)) else: encrypted.underlayer.nh = esp.nh encrypted.underlayer.remove_payload() ip_header.plen = len(ip_header.payload) + len(esp.data) cls = ip_header.guess_payload_class(esp.data) # reassemble the ip_header with the ESP payload return ip_header / cls(esp.data)
def addfield(self, pkt, s, val): """Add an internal value to a string""" if self.length_of(pkt) == 8: return s + struct.pack(self.fmt[0] + "B", val) if self.length_of(pkt) == 16: return s + struct.pack(self.fmt[0] + "H", val) if self.length_of(pkt) == 32: return s + struct.pack(self.fmt[0] + "2H", val) # TODO: fix! if self.length_of(pkt) == 48: return s + struct.pack(self.fmt[0] + "3H", val) # TODO: fix! elif self.length_of(pkt) == 64: return s + struct.pack(self.fmt[0] + "Q", val) elif self.length_of(pkt) == 128: # TODO: FIX THE PACKING!! return s + struct.pack(self.fmt[0] + "16s", raw(val)) else: return s
def post_dissect(self, data): if not self.underlayer or not hasattr(self.underlayer, "_ipv6"): return data if self.guess_payload_class(data) != IPv6: return data # Underlayer is LoWPAN_IPHC packet = self.underlayer._ipv6 try: ipv6_hdr = next( x for x in self.exts if isinstance(x, LoWPAN_NHC_IPv6Ext) ) except StopIteration: ipv6_hdr = None if ipv6_hdr: # XXX todo: implement: append the IPv6 extension # packet = packet / ipv6extension pass try: udp_hdr = next( x for x in self.exts if isinstance(x, LoWPAN_NHC_UDP) ) except StopIteration: udp_hdr = None if udp_hdr: packet.nh = 0x11 # UDP udp = UDP() # https://tools.ietf.org/html/rfc6282#section-4.3.3 if udp_hdr.C == 0: udp.chksum = udp_hdr.udpChecksum if udp_hdr.P == 0: udp.sport = udp_hdr.udpSourcePort udp.dport = udp_hdr.udpDestPort elif udp_hdr.P == 1: udp.sport = udp_hdr.udpSourcePort udp.dport = 0xF000 + udp_hdr.udpDestPort elif udp_hdr.P == 2: udp.sport = 0xF000 + udp_hdr.udpSourcePort udp.dport = udp_hdr.udpDestPort elif udp_hdr.P == 3: udp.sport = 0xF0B0 + udp_hdr.udpSourcePort udp.dport = 0xF0B0 + udp_hdr.udpDestPort packet.lastlayer().add_payload(udp / data) else: packet.lastlayer().add_payload(data) data = raw(packet) return Packet.post_dissect(self, data)
def _legacy_sign_md5_sha1(self, M): M = raw(M) k = self._modulusLen // 8 EM = _legacy_pkcs1_v1_5_encode_md5_sha1(M, k) if EM is None: warning("Key._rsassa_pkcs1_v1_5_sign(): unable to encode") return None m = pkcs_os2ip(EM) n = self._modulus if isinstance(m, int) and six.PY2: m = long(m) # noqa: F821 if (six.PY2 and not isinstance(m, long)) or m > n - 1: # noqa: F821 warning("Key._rsaep() expects a long between 0 and n-1") return None privExp = self.key.private_numbers().d s = pow(m, privExp, n) return pkcs_i2osp(s, k)
def make_reply(self, p): ip = p.getlayer(IP) tcp = p.getlayer(TCP) pay = raw(tcp.payload) del(p.payload.payload.payload) p.FCfield = "from-DS" p.addr1, p.addr2 = p.addr2, p.addr1 p /= IP(src=ip.dst, dst=ip.src) p /= TCP(sport=tcp.dport, dport=tcp.sport, seq=tcp.ack, ack=tcp.seq + len(pay), flags="PA") q = p.copy() p /= self.replace q.ID += 1 q.getlayer(TCP).flags = "RA" q.getlayer(TCP).seq += len(self.replace) return [p, q]