def __init__(self, name, default, length_from, get_class, evaluators=None): """ @param length_from: function to obtain the field length @type length_from: C{callable} @param get_class: function to obtain the class @type get_class: C{callable} @param evaluators: evaluators @type evaluators: C{list} of C{callable} """ StrLenField.__init__(self, name, default, length_from=length_from) self.evaluators = evaluators or [] self._get_class = get_class
def i2m(self, pkt, x): cls = self.subtypes_dict.get(pkt.subtype, StrLenField) try: return (cls.i2m.__func__ if six.PY2 else cls.i2m)(self, pkt, x) except Exception: log_runtime.exception("Failed to build " + self.name + " ! ") return StrLenField.i2m(self, pkt, x)
def m2i(self, pkt, x): cls = self.subtypes_dict.get(pkt.subtype, StrLenField) try: return (cls.m2i.__func__ if six.PY2 else cls.m2i)(self, pkt, x) except Exception: log_runtime.exception("Failed to dissect " + self.name + " ! ") return StrLenField.m2i(self, pkt, x)
class TacacsPacketArguments(Packet): ''' Class defined to handle the arguments listed at the end of tacacs+ Authorization and Accounting packets. ''' __slots__ = ['_len'] name = 'Arguments in Tacacs+ packet' fields_desc = [StrLenField('data', '', length_from=lambda pkt: pkt._len)] def pre_dissect(self, s): cur = self.underlayer i = 0 # Searching the position in layer in order to get its length while isinstance(cur, TacacsPacketArguments): cur = cur.underlayer i += 1 self._len = cur.arg_len_list[i] return s def guess_payload_class(self, pay): cur = self.underlayer i = 0 # Guessing if Argument packet. Nothing in encapsulated via tacacs+ while isinstance(cur, TacacsPacketArguments): cur = cur.underlayer i += 1 if i+1 < cur.arg_cnt: return TacacsPacketArguments return conf.padding_layer
class LLTDAttribute(Packet): name = "LLTD Attribute" show_indent = False show_summary = False # section 2.2.1.1 fields_desc = [ ByteEnumField( "type", 0, { 0: "End Of Property", 1: "Host ID", 2: "Characteristics", 3: "Physical Medium", 7: "IPv4 Address", 9: "802.11 Max Rate", 10: "Performance Counter Frequency", 12: "Link Speed", 14: "Icon Image", 15: "Machine Name", 18: "Device UUID", 20: "QoS Characteristics", 21: "802.11 Physical Medium", 24: "Detailed Icon Image", }), FieldLenField("len", None, length_of="value", fmt="B"), StrLenField("value", "", length_from=lambda pkt: pkt.len), ] @classmethod def dispatch_hook(cls, _pkt=None, *_, **kargs): if _pkt: cmd = struct.unpack("B", _pkt[0])[0] elif "type" in kargs: cmd = kargs["type"] if isinstance(cmd, basestring): cmd = cls.fields_desc[0].s2i[cmd] return SPECIFIC_CLASSES.get(cmd, cls)
class SCTPChunkData(_SCTPChunkGuessPayload, Packet): # TODO : add a padding function in post build if this layer is used to generate SCTP chunk data # noqa: E501 fields_desc = [ ByteEnumField("type", 0, sctpchunktypes), BitField("reserved", None, 4), BitField("delay_sack", 0, 1), BitField("unordered", 0, 1), BitField("beginning", 0, 1), BitField("ending", 0, 1), FieldLenField("len", None, length_of="data", adjust=lambda pkt, x: x + 16), # noqa: E501 XIntField("tsn", None), XShortField("stream_id", None), XShortField("stream_seq", None), IntEnumField("proto_id", None, SCTP_PAYLOAD_PROTOCOL_INDENTIFIERS), # noqa: E501 PadField( StrLenField("data", None, length_from=lambda pkt: pkt.len - 16), # noqa: E501 4, padwith=b"\x00"), ]
class PPP_LCP_Option(Packet): name = "PPP LCP Option" fields_desc = [ ByteEnumField("type", None, _PPP_lcp_optiontypes), FieldLenField("len", None, fmt="B", length_of="data", adjust=lambda _, val: val + 2), StrLenField("data", None, length_from=lambda pkt: pkt.len - 2), ] def extract_padding(self, pay): return b"", pay registered_options = {} @classmethod def register_variant(cls): cls.registered_options[cls.type.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: o = orb(_pkt[0]) return cls.registered_options.get(o, cls) return cls
class ZCLPricePublishPrice(Packet): name = "Price Cluster: Publish Price Command (Server: Generated)" fields_desc = [ XLEIntField("provider_id", 0x00000000), # Unsigned 32-bit Integer (4 octets) # noqa: E501 # Rate Label is a UTF-8 encoded Octet String (0-12 octets). The first Octet indicates the length. # noqa: E501 StrLenField("rate_label", "", length_from=lambda pkt:int(pkt.rate_label[0])), # TODO verify # noqa: E501 XLEIntField("issuer_event_id", 0x00000000), # Unsigned 32-bit Integer (4 octets) # noqa: E501 XLEIntField("current_time", 0x00000000), # UTCTime (4 octets) ByteField("unit_of_measure", 0), # 8 bits enumeration (1 octet) XLEShortField("currency", 0x0000), # Unsigned 16-bit Integer (2 octets) # noqa: E501 ByteField("price_trailing_digit", 0), # 8-bit BitMap (1 octet) ByteField("number_of_price_tiers", 0), # 8-bit BitMap (1 octet) XLEIntField("start_time", 0x00000000), # UTCTime (4 octets) XLEShortField("duration_in_minutes", 0x0000), # Unsigned 16-bit Integer (2 octets) # noqa: E501 XLEIntField("price", 0x00000000), # Unsigned 32-bit Integer (4 octets) ByteField("price_ratio", 0), # Unsigned 8-bit Integer (1 octet) XLEIntField("generation_price", 0x00000000), # Unsigned 32-bit Integer (4 octets) # noqa: E501 ByteField("generation_price_ratio", 0), # Unsigned 8-bit Integer (1 octet) # noqa: E501 XLEIntField("alternate_cost_delivered", 0x00000000), # Unsigned 32-bit Integer (4 octets) # noqa: E501 ByteField("alternate_cost_unit", 0), # 8-bit enumeration (1 octet) ByteField("alternate_cost_trailing_digit", 0), # 8-bit BitMap (1 octet) # noqa: E501 ByteField("number_of_block_thresholds", 0), # 8-bit BitMap (1 octet) ByteField("price_control", 0), # 8-bit BitMap (1 octet) ]
class RTRRouterKey(Packet): ''' Router Key packet from version 1 standard section 5.10 https://tools.ietf.org/html/rfc8210#section-5.10 ''' name = 'Router Key' fields_desc = [ ByteEnumField('rtr_version', 1, RTR_VERSION), ByteEnumField('pdu_type', 9, PDU_TYPE), ByteField('flags', 0), ByteField('zeros', 0), IntField('length', None), StrFixedLenField('subject_key_identifier', '', 20), IntField('asn', 0), StrLenField('subject_PKI', '', length_from=lambda x: x.length - 32) ] def post_build(self, pkt, pay): temp_len = len(pkt) + 2 if not self.length: pkt = pkt[:2] + struct.pack('!I', temp_len) + pkt[6:] return pkt + pay
class DNSRR(InheritOriginDNSStrPacket): name = "DNS Resource Record" show_indent = 0 fields_desc = [ DNSStrField("rrname", ""), ShortEnumField("type", 1, dnstypes), ShortEnumField("rclass", 1, dnsclasses), IntField("ttl", 0), FieldLenField("rdlen", None, length_of="rdata", fmt="H"), MultipleTypeField( [ # A (IPField("rdata", "0.0.0.0"), lambda pkt: pkt.type == 1), # AAAA (IP6Field("rdata", "::"), lambda pkt: pkt.type == 28), # NS, MD, MF, CNAME, PTR (DNSStrField("rdata", "", length_from=lambda pkt: pkt.rdlen), lambda pkt: pkt.type in [2, 3, 4, 5, 12]), # TEXT (DNSTextField("rdata", [], length_from=lambda pkt: pkt.rdlen), lambda pkt: pkt.type == 16), ], StrLenField("rdata", "", length_from=lambda pkt: pkt.rdlen)) ]
class KeyShareEntry(Packet): """ When building from scratch, we create a DH private key, and when dissecting, we create a DH public key. Default group is secp256r1. """ __slots__ = ["privkey", "pubkey"] name = "Key Share Entry" fields_desc = [ ShortEnumField("group", None, _tls_named_groups), FieldLenField("kxlen", None, length_of="key_exchange"), StrLenField("key_exchange", "", length_from=lambda pkt: pkt.kxlen) ] def __init__(self, *args, **kargs): self.privkey = None self.pubkey = None super(KeyShareEntry, self).__init__(*args, **kargs) def do_build(self): """ We need this hack, else 'self' would be replaced by __iter__.next(). """ tmp = self.explicit self.explicit = True b = super(KeyShareEntry, self).do_build() self.explicit = tmp return b @crypto_validator def create_privkey(self): """ This is called by post_build() for key creation. """ if self.group in _tls_named_ffdh_groups: params = _ffdh_groups[_tls_named_ffdh_groups[self.group]][0] privkey = params.generate_private_key() self.privkey = privkey pubkey = privkey.public_key() self.key_exchange = pubkey.public_numbers().y elif self.group in _tls_named_curves: if _tls_named_curves[self.group] == "x25519": if conf.crypto_valid_advanced: privkey = x25519.X25519PrivateKey.generate() self.privkey = privkey pubkey = privkey.public_key() self.key_exchange = pubkey.public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw) elif _tls_named_curves[self.group] != "x448": curve = ec._CURVE_TYPES[_tls_named_curves[self.group]]() privkey = ec.generate_private_key(curve, default_backend()) self.privkey = privkey pubkey = privkey.public_key() try: # cryptography >= 2.5 self.key_exchange = pubkey.public_bytes( serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint) except TypeError: # older versions self.key_exchange = pubkey.public_numbers().encode_point() def post_build(self, pkt, pay): if self.group is None: self.group = 23 # secp256r1 if not self.key_exchange: try: self.create_privkey() except ImportError: pass if self.kxlen is None: self.kxlen = len(self.key_exchange) group = struct.pack("!H", self.group) kxlen = struct.pack("!H", self.kxlen) return group + kxlen + self.key_exchange + pay @crypto_validator def register_pubkey(self): if self.group in _tls_named_ffdh_groups: params = _ffdh_groups[_tls_named_ffdh_groups[self.group]][0] pn = params.parameter_numbers() public_numbers = dh.DHPublicNumbers(self.key_exchange, pn) self.pubkey = public_numbers.public_key(default_backend()) elif self.group in _tls_named_curves: if _tls_named_curves[self.group] == "x25519": if conf.crypto_valid_advanced: import_point = x25519.X25519PublicKey.from_public_bytes self.pubkey = import_point(self.key_exchange) elif _tls_named_curves[self.group] != "x448": curve = ec._CURVE_TYPES[_tls_named_curves[self.group]]() try: # cryptography >= 2.5 import_point = ec.EllipticCurvePublicKey.from_encoded_point # noqa: E501 self.pubkey = import_point(curve, self.key_exchange) except AttributeError: import_point = ec.EllipticCurvePublicNumbers.from_encoded_point # noqa: E501 pub_num = import_point( curve, self.key_exchange).public_numbers() # noqa: E501 self.pubkey = pub_num.public_key(default_backend()) def post_dissection(self, r): try: self.register_pubkey() except ImportError: pass def extract_padding(self, s): return "", s
class ClientECDiffieHellmanPublic(_GenericTLSSessionInheritance): """ Note that the 'len' field is 1 byte longer than with the previous class. """ name = "Client ECDH Public Value" fields_desc = [FieldLenField("ecdh_Yclen", None, length_of="ecdh_Yc", fmt="B"), StrLenField("ecdh_Yc", "", length_from=lambda pkt: pkt.ecdh_Yclen)] @crypto_validator def fill_missing(self): s = self.tls_session s.client_kx_privkey = _tls_named_groups_generate( s.client_kx_ecdh_params ) # ecdh_Yc follows ECPoint.point format as defined in # https://tools.ietf.org/html/rfc8422#section-5.4 pubkey = s.client_kx_privkey.public_key() if isinstance(pubkey, (x25519.X25519PublicKey, x448.X448PublicKey)): self.ecdh_Yc = pubkey.public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw ) if s.client_kx_privkey and s.server_kx_pubkey: pms = s.client_kx_privkey.exchange(s.server_kx_pubkey) else: # uncompressed format of an elliptic curve point x = pubkey.public_numbers().x y = pubkey.public_numbers().y self.ecdh_Yc = (b"\x04" + pkcs_i2osp(x, pubkey.key_size // 8) + pkcs_i2osp(y, pubkey.key_size // 8)) if s.client_kx_privkey and s.server_kx_pubkey: pms = s.client_kx_privkey.exchange(ec.ECDH(), s.server_kx_pubkey) if s.client_kx_privkey and s.server_kx_pubkey: s.pre_master_secret = pms if not s.extms or s.session_hash: s.compute_ms_and_derive_keys() def post_build(self, pkt, pay): if not self.ecdh_Yc: try: self.fill_missing() except ImportError: pass if self.ecdh_Yclen is None: self.ecdh_Yclen = len(self.ecdh_Yc) return pkcs_i2osp(self.ecdh_Yclen, 1) + self.ecdh_Yc + pay def post_dissection(self, m): s = self.tls_session # if there are kx params and keys, we assume the crypto library is ok if s.client_kx_ecdh_params: s.client_kx_pubkey = _tls_named_groups_import( s.client_kx_ecdh_params, self.ecdh_Yc ) if s.server_kx_privkey and s.client_kx_pubkey: ZZ = s.server_kx_privkey.exchange(ec.ECDH(), s.client_kx_pubkey) s.pre_master_secret = ZZ if not s.extms or s.session_hash: s.compute_ms_and_derive_keys()
class ClientDiffieHellmanPublic(_GenericTLSSessionInheritance): """ If the user provides a value for dh_Yc attribute, we assume he will set the pms and ms accordingly and trigger the key derivation on his own. XXX As specified in 7.4.7.2. of RFC 4346, we should distinguish the needs for implicit or explicit value depending on availability of DH parameters in *client* certificate. For now we can only do ephemeral/explicit DH. """ name = "Client DH Public Value" fields_desc = [FieldLenField("dh_Yclen", None, length_of="dh_Yc"), StrLenField("dh_Yc", "", length_from=lambda pkt: pkt.dh_Yclen)] @crypto_validator def fill_missing(self): s = self.tls_session s.client_kx_privkey = s.client_kx_ffdh_params.generate_private_key() pubkey = s.client_kx_privkey.public_key() y = pubkey.public_numbers().y self.dh_Yc = pkcs_i2osp(y, pubkey.key_size // 8) if s.client_kx_privkey and s.server_kx_pubkey: pms = s.client_kx_privkey.exchange(s.server_kx_pubkey) s.pre_master_secret = pms if not s.extms or s.session_hash: # If extms is set (extended master secret), the key will # need the session hash to be computed. This is provided # by the TLSClientKeyExchange. Same in all occurrences s.compute_ms_and_derive_keys() def post_build(self, pkt, pay): if not self.dh_Yc: try: self.fill_missing() except ImportError: pass if self.dh_Yclen is None: self.dh_Yclen = len(self.dh_Yc) return pkcs_i2osp(self.dh_Yclen, 2) + self.dh_Yc + pay def post_dissection(self, m): """ First we update the client DHParams. Then, we try to update the server DHParams generated during Server*DHParams building, with the shared secret. Finally, we derive the session keys and update the context. """ s = self.tls_session # if there are kx params and keys, we assume the crypto library is ok if s.client_kx_ffdh_params: y = pkcs_os2ip(self.dh_Yc) param_numbers = s.client_kx_ffdh_params.parameter_numbers() public_numbers = dh.DHPublicNumbers(y, param_numbers) s.client_kx_pubkey = public_numbers.public_key(default_backend()) if s.server_kx_privkey and s.client_kx_pubkey: ZZ = s.server_kx_privkey.exchange(s.client_kx_pubkey) s.pre_master_secret = ZZ if not s.extms or s.session_hash: s.compute_ms_and_derive_keys() def guess_payload_class(self, p): return Padding
class PPP_LCP_Quality_Protocol_Option(PPP_LCP_Option): fields_desc = [ByteEnumField("type", 4, _PPP_lcp_optiontypes), FieldLenField("len", None, fmt="B", length_of="data", adjust=lambda p, x:x+4), ShortEnumField("quality_protocol", 0xc025, _PPP_LCP_quality_protocols), StrLenField("data", "", length_from=lambda p:p.len-4)]
class SAPDiagDyntAtomItem(PacketNoPadded): name = "SAP Diag Dynt Atom item" fields_desc = [ ShortField("atom_length", 0), ByteField("dlg_flag_1", 0), ByteField("dlg_flag_2", 0), ByteEnumKeysField("etype", 0, diag_atom_etypes), ByteField("area", 0), ByteField("block", 0), ByteField("group", 0), ShortField("row", 0), ShortField("col", 0), # Attr flags BitField("attr_DIAG_BSD_COMBOSTYLE", 0, 1), # 80 BitField("attr_DIAG_BSD_YES3D", 0, 1), # 40 BitField("attr_DIAG_BSD_PROPFONT", 0, 1), # 20 BitField("attr_DIAG_BSD_MATCHCODE", 0, 1), # 10 BitField("attr_DIAG_BSD_JUSTRIGHT", 0, 1), # 08 BitField("attr_DIAG_BSD_INTENSIFY", 0, 1), # 04 BitField("attr_DIAG_BSD_INVISIBLE", 0, 1), # 02 BitField("attr_DIAG_BSD_PROTECTED", 0, 1), # 01 # DIAG_DGOTYP_FNAME ConditionalField( StrLenField("name_text", "", length_from=lambda pkt: pkt.atom_length - 13), lambda pkt: pkt.etype == 114), # DIAG_DGOTYP_PUSHBUTTON_2 */ ConditionalField(ByteField("pushbutton_v_length", 0), lambda pkt: pkt.etype in [115]), ConditionalField(ByteField("pushbutton_v_height", 0), lambda pkt: pkt.etype in [115]), ConditionalField(ShortField("pushbutton_function_code_offset", 0), lambda pkt: pkt.etype in [115]), ConditionalField(ShortField("pushbutton_text_offset", 0), lambda pkt: pkt.etype in [115]), ConditionalField(StrField("pushbutton_text", ""), lambda pkt: pkt.etype in [115]), ConditionalField(StrField("pushbutton_function_code", ""), lambda pkt: pkt.etype in [115]), # DIAG_DGOTYP_TABSTRIP_BUTTON ConditionalField(ByteField("tabstripbutton_v_length", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ByteField("tabstripbutton_v_height", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ByteField("tabstripbutton_page_id", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ShortField("tabstripbutton_function_code_offset", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ShortField("tabstripbutton_text_offset", 0), lambda pkt: pkt.etype in [116]), ConditionalField(ShortField("tabstripbutton_id_offset", 0), lambda pkt: pkt.etype in [116]), ConditionalField(StrNullField("tabstripbutton_text", ""), lambda pkt: pkt.etype in [116]), ConditionalField(StrNullField("tabstripbutton_function_code", ""), lambda pkt: pkt.etype in [116]), ConditionalField(StrNullField("tabstripbutton_id", ""), lambda pkt: pkt.etype in [116]), # DIAG_DGOTYP_XMLPROP ConditionalField( StrLenField("xmlprop_text", "", length_from=lambda pkt: pkt.atom_length - 13), lambda pkt: pkt.etype == 120), # DIAG_DGOTYP_EFIELD_1 or DIAG_DGOTYP_OFIELD_1 or DIAG_DGOTYP_KEYWORD_1 ConditionalField(ByteField("field1_flag1", 0), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField( FieldLenField("field1_dlen", None, fmt="B", length_of="field1_text"), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField(ByteField("field1_mlen", 0), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField(ShortField("field1_maxnrchars", 0), lambda pkt: pkt.etype in [121, 122, 123]), ConditionalField( StrLenField("field1_text", "", length_from=lambda pkt: pkt.field1_dlen), lambda pkt: pkt.etype in [121, 122, 123]), # DIAG_DGOTYP_FRAME_1 ConditionalField(ShortField("frame_drows", 0), lambda pkt: pkt.etype in [127]), ConditionalField(ShortField("frame_dcols", 0), lambda pkt: pkt.etype in [127]), ConditionalField( StrLenField("frame_text", "", length_from=lambda pkt: pkt.atom_length - 17), lambda pkt: pkt.etype in [127]), # DIAG_DGOTYP_RADIOBUTTON_3 ConditionalField(ByteField("radiobutton_button", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_visible_label_length", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_event_id_off", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ByteField("radiobutton_event_id_len", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_text_off", 0), lambda pkt: pkt.etype in [129]), ConditionalField(ShortField("radiobutton_text_length", 0), lambda pkt: pkt.etype in [129]), ConditionalField( StrLenField("radiobutton_text", "", length_from=lambda pkt: pkt.radiobutton_event_id_len + pkt.radiobutton_text_length), lambda pkt: pkt.etype in [129]), # DIAG_DGOTYP_EFIELD_2 or DIAG_DGOTYP_OFIELD_2 or DIAG_DGOTYP_KEYWORD_2 ConditionalField(ShortField("field2_flag1", 0), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField( FieldLenField("field2_dlen", None, fmt="B", length_of="field2_text"), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField(ByteField("field2_mlen", 0), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField(ShortField("field2_maxnrchars", 0), lambda pkt: pkt.etype in [130, 131, 132]), ConditionalField( StrLenField("field2_text", "", length_from=lambda pkt: pkt.field2_dlen), lambda pkt: pkt.etype in [130, 131, 132]), # Remaining types ConditionalField( StrLenField("value", "", length_from=lambda pkt: pkt.atom_length - 13), lambda pkt: pkt.etype not in [114, 115, 116, 120, 121, 122, 123, 127, 129, 130, 131, 132]), ] def post_build(self, p, pay): if pay is None: pay = '' # Update the atom_length field (first 2 bytes) with the packet length p = pack("!H", len(p)) + p[2:] return p + pay
class CDPMsgPortID(CDPMsgGeneric): name = "Port ID" fields_desc = [XShortEnumField("type", 0x0003, _cdp_tlv_types), FieldLenField("len", None, "iface", "!H", adjust=lambda pkt, x: x + 4), StrLenField("iface", "Port 1", length_from=lambda x:x.len - 4)] # noqa: E501
def m2i(self, pkt, m): cls = self.get_class(pkt) if cls is not None: return cls(m) else: return StrLenField.m2i(self, pkt, m)
class UTF8EncodedString(Packet): fields_desc = [ FieldLenField("length", None, length_of="value"), StrLenField("value", "", length_from=lambda pkt: pkt.length) ]
def i2m(self, pkt, i): cls = self.get_class(pkt) if cls is not None: return str(i) else: return StrLenField.i2m(self, pkt, i)
class CAN(Packet): """A minimal implementation of the CANopen protocol, based on Wireshark dissectors. See https://wiki.wireshark.org/CANopen """ fields_desc = [ FlagsField('flags', 0, 3, ['error', 'remote_transmission_request', 'extended' ]), # noqa: E501 XBitField('identifier', 0, 29), FieldLenField('length', None, length_of='data', fmt='B'), ThreeBytesField('reserved', 0), StrLenField('data', '', length_from=lambda pkt: pkt.length), ] @staticmethod def inv_endianness(pkt): """ Invert the order of the first four bytes of a CAN packet This method is meant to be used specifically to convert a CAN packet between the pcap format and the socketCAN format :param pkt: str of the CAN packet :return: packet str with the first four bytes swapped """ len_partial = len(pkt) - 4 # len of the packet, CAN ID excluded return struct.pack('<I{}s'.format(len_partial), *struct.unpack('>I{}s'.format(len_partial), pkt)) # noqa: E501 def pre_dissect(self, s): """ Implements the swap-bytes functionality when dissecting """ if conf.contribs['CAN']['swap-bytes']: return CAN.inv_endianness(s) return s 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))) # noqa: E501 else: p = f.addfield(self, p, val) if conf.contribs['CAN']['swap-bytes']: return CAN.inv_endianness(p) return p def extract_padding(self, p): return b'', p
class LLTDAttributeDeviceUUID(LLTDAttribute): name = "LLTD Attribute - Device UUID" fields_desc = [ FieldLenField("len", None, length_of="uuid", fmt="B"), StrLenField("uuid", b"\x00" * 16, length_from=lambda pkt: pkt.len), ]
class PSKBinderEntry(Packet): name = "PSK Binder Entry" fields_desc = [ FieldLenField("binder_len", None, fmt="B", length_of="binder"), StrLenField("binder", "", length_from=lambda pkt: pkt.binder_len) ]
class RadioTap(Packet): name = "RadioTap dummy" fields_desc = [ ByteField('version', 0), ByteField('pad', 0), LEShortField('len', None), FlagsField('present', None, -32, _rt_present), # noqa: E501 # Extended presence mask ConditionalField( PacketListField("Ext", [], next_cls_cb=_next_radiotap_extpm), lambda pkt: pkt.present and pkt.present.Ext), # noqa: E501 # RadioTap fields - each starts with a _RadiotapReversePadField # to handle padding # TSFT ConditionalField( _RadiotapReversePadField(LELongField("mac_timestamp", 0)), lambda pkt: pkt.present and pkt.present.TSFT), # Flags ConditionalField( _RadiotapReversePadField(FlagsField("Flags", None, -8, _rt_flags)), lambda pkt: pkt.present and pkt.present.Flags), # Rate ConditionalField(_RadiotapReversePadField(ByteField("Rate", 0)), lambda pkt: pkt.present and pkt.present.Rate), # Channel ConditionalField(_RadiotapReversePadField(LEShortField("Channel", 0)), lambda pkt: pkt.present and pkt.present.Channel), ConditionalField( FlagsField("ChannelFlags", None, -16, _rt_channelflags), lambda pkt: pkt.present and pkt.present.Channel), # dBm_AntSignal ConditionalField( _RadiotapReversePadField(_dbmField("dBm_AntSignal", -256)), lambda pkt: pkt.present and pkt.present.dBm_AntSignal), # dBm_AntNoise ConditionalField( _RadiotapReversePadField(_dbmField("dBm_AntNoise", -256)), lambda pkt: pkt.present and pkt.present.dBm_AntNoise), # Lock_Quality ConditionalField( _RadiotapReversePadField(LEShortField("Lock_Quality", 0), ), lambda pkt: pkt.present and pkt.present.Lock_Quality), # Antenna ConditionalField(_RadiotapReversePadField(ByteField("Antenna", 0)), lambda pkt: pkt.present and pkt.present.Antenna), # RX Flags ConditionalField( _RadiotapReversePadField( FlagsField("RXFlags", None, -16, _rt_rxflags)), lambda pkt: pkt.present and pkt.present.RXFlags), # TX Flags ConditionalField( _RadiotapReversePadField( FlagsField("TXFlags", None, -16, _rt_txflags)), lambda pkt: pkt.present and pkt.present.TXFlags), # ChannelPlus ConditionalField( _RadiotapReversePadField( FlagsField("ChannelFlags2", None, -32, _rt_channelflags2)), lambda pkt: pkt.present and pkt.present.ChannelPlus), ConditionalField(LEShortField("ChannelFrequency", 0), lambda pkt: pkt.present and pkt.present.ChannelPlus), ConditionalField(ByteField("ChannelNumber", 0), lambda pkt: pkt.present and pkt.present.ChannelPlus), # MCS ConditionalField( _RadiotapReversePadField( FlagsField("knownMCS", None, -8, _rt_knownmcs)), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitField("Ness_LSB", 0, 1), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitField("STBC_streams", 0, 2), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitEnumField("FEC_type", 0, 1, { 0: "BCC", 1: "LDPC" }), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField( BitEnumField("HT_format", 0, 1, { 0: "mixed", 1: "greenfield" }), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField( BitEnumField("guard_interval", 0, 1, { 0: "Long_GI", 1: "Short_GI" }), # noqa: E501 lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(BitEnumField("MCS_bandwidth", 0, 2, _rt_bandwidth), lambda pkt: pkt.present and pkt.present.MCS), ConditionalField(ByteField("MCS_index", 0), lambda pkt: pkt.present and pkt.present.MCS), # A_MPDU ConditionalField(_RadiotapReversePadField(LEIntField("A_MPDU_ref", 0)), lambda pkt: pkt.present and pkt.present.A_MPDU), ConditionalField( FlagsField("A_MPDU_flags", None, -32, _rt_a_mpdu_flags), lambda pkt: pkt.present and pkt.present.A_MPDU), # VHT ConditionalField( _RadiotapReversePadField( FlagsField("KnownVHT", None, -16, _rt_knownvht)), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(FlagsField("PresentVHT", None, -8, _rt_presentvht), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(ByteEnumField("VHT_bandwidth", 0, _rt_vhtbandwidth), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(StrFixedLenField("mcs_nss", 0, length=5), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(ByteField("GroupID", 0), lambda pkt: pkt.present and pkt.present.VHT), ConditionalField(ShortField("PartialAID", 0), lambda pkt: pkt.present and pkt.present.VHT), # timestamp ConditionalField(_RadiotapReversePadField(LELongField("timestamp", 0)), lambda pkt: pkt.present and pkt.present.timestamp), ConditionalField(LEShortField("ts_accuracy", 0), lambda pkt: pkt.present and pkt.present.timestamp), ConditionalField(ByteField("ts_position", 0), lambda pkt: pkt.present and pkt.present.timestamp), ConditionalField(ByteField("ts_flags", 0), lambda pkt: pkt.present and pkt.present.timestamp), # HE - XXX not complete ConditionalField(_RadiotapReversePadField(ShortField("he_data1", 0)), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data2", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data3", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data4", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data5", 0), lambda pkt: pkt.present and pkt.present.HE), ConditionalField(ShortField("he_data6", 0), lambda pkt: pkt.present and pkt.present.HE), # HE_MU ConditionalField( _RadiotapReversePadField(LEShortField("hemu_flags1", 0)), lambda pkt: pkt.present and pkt.present.HE_MU), ConditionalField(LEShortField("hemu_flags2", 0), lambda pkt: pkt.present and pkt.present.HE_MU), ConditionalField( FieldListField("RU_channel1", [], ByteField, count_from=lambda x: 4), lambda pkt: pkt.present and pkt.present.HE_MU), ConditionalField( FieldListField("RU_channel2", [], ByteField, count_from=lambda x: 4), lambda pkt: pkt.present and pkt.present.HE_MU), # HE_MU_other_user ConditionalField( _RadiotapReversePadField(LEShortField("hemuou_per_user_1", 0x7fff)), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), ConditionalField( LEShortField("hemuou_per_user_2", 0x003f), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), ConditionalField( ByteField("hemuou_per_user_position", 0), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), ConditionalField( FlagsField("hemuou_per_user_known", 0, -16, _rt_hemuother_per_user_known), lambda pkt: pkt.present and pkt.present.HE_MU_other_user), # L_SIG ConditionalField( _RadiotapReversePadField( FlagsField("lsig_data1", 0, -16, ["rate", "length"])), lambda pkt: pkt.present and pkt.present.L_SIG), ConditionalField(BitField("lsig_length", 0, 12), lambda pkt: pkt.present and pkt.present.L_SIG), ConditionalField(BitField("lsig_rate", 0, 4), lambda pkt: pkt.present and pkt.present.L_SIG), # Remaining StrLenField( 'notdecoded', "", length_from=lambda pkt: max(pkt.len - pkt._tmp_dissect_pos, 0)) ] def guess_payload_class(self, payload): if self.present and self.present.Flags and self.Flags.FCS: return Dot11FCS return Dot11 def post_build(self, p, pay): if self.len is None: p = p[:2] + struct.pack("!H", len(p))[::-1] + p[4:] return p + pay
class IE_ProtocolConfigurationOptions(IE_Base): name = "Protocol Configuration Options" fields_desc = [ByteEnumField("ietype", 132, IEType), ShortField("length", 4), StrLenField("Protocol_Configuration", "", length_from=lambda x: x.length)]
class PPP_LCP_Callback_Option(PPP_LCP_Option): fields_desc = [ByteEnumField("type", 13, _PPP_lcp_optiontypes), FieldLenField("len", None, fmt="B", length_of="message", adjust=lambda p, x:x+3), ByteEnumField("operation", 0, _PPP_lcp_callback_operations), StrLenField("message", "", length_from=lambda p:p.len-3)]
class MQTTConnect(Packet): name = "MQTT connect" fields_desc = [ FieldLenField("length", None, length_of="protoname"), StrLenField("protoname", "", length_from=lambda pkt: pkt.length), ByteEnumField("protolevel", 5, PROTOCOL_LEVEL), BitEnumField("usernameflag", 0, 1, { 0: 'Disabled', 1: 'Enabled' }), BitEnumField("passwordflag", 0, 1, { 0: 'Disabled', 1: 'Enabled' }), BitEnumField("willretainflag", 0, 1, { 0: 'Disabled', 1: 'Enabled' }), BitEnumField("willQOSflag", 0, 2, QOS_LEVEL), BitEnumField("willflag", 0, 1, { 0: 'Disabled', 1: 'Enabled' }), BitEnumField("cleansess", 0, 1, { 0: 'Disabled', 1: 'Enabled' }), BitEnumField("reserved", 0, 1, { 0: 'Disabled', 1: 'Enabled' }), ShortField("klive", 0), #CONNECT PROPERTIES FieldLenField("proplen", None, fmt='B', length_of="properties"), ConditionalField( PacketListField("properties", [], pkt_cls=MQTTProperty, length_from=lambda pkt: pkt.proplen), lambda pkt: pkt.proplen != 0), FieldLenField("clientIdlen", None, length_of="clientId"), StrLenField("clientId", "", length_from=lambda pkt: pkt.clientIdlen), # Payload with optional fields depending on the flags # WILL PROPERTIES ConditionalField( FieldLenField("willproplen", None, fmt='B', length_of="willproperties"), lambda pkt: pkt.willflag == 1), ConditionalField( PacketListField("willproperties", [], pkt_cls=MQTTWillProperty, length_from=lambda pkt: pkt.willproplen), lambda pkt: pkt.willflag == 1), ConditionalField(FieldLenField("wtoplen", None, length_of="willtopic"), lambda pkt: pkt.willflag == 1), ConditionalField( StrLenField("willtopic", "", length_from=lambda pkt: pkt.wtoplen), lambda pkt: pkt.willflag == 1), ConditionalField(FieldLenField("wmsglen", None, length_of="willmsg"), lambda pkt: pkt.willflag == 1), ConditionalField( StrLenField("willmsg", "", length_from=lambda pkt: pkt.wmsglen), lambda pkt: pkt.willflag == 1), ConditionalField(FieldLenField("userlen", None, length_of="username"), lambda pkt: pkt.usernameflag == 1), ConditionalField( StrLenField("username", "", length_from=lambda pkt: pkt.userlen), lambda pkt: pkt.usernameflag == 1), ConditionalField(FieldLenField("passlen", None, length_of="password"), lambda pkt: pkt.passwordflag == 1), ConditionalField( StrLenField("password", "", length_from=lambda pkt: pkt.passlen), lambda pkt: pkt.passwordflag == 1), ]
class Dot11Elt(Packet): name = "802.11 Information Element" fields_desc = [ ByteEnumField("ID", 0, _dot11_info_elts_ids), FieldLenField("len", None, "info", "B"), StrLenField("info", "", length_from=lambda x: x.len, max_length=255) ] def mysummary(self): if self.ID == 0: ssid = repr(self.info) if ssid[:2] in ['b"', "b'"]: ssid = ssid[1:] return "SSID=%s" % ssid, [Dot11] else: return "" registered_ies = {} @classmethod def register_variant(cls): cls.registered_ies[cls.ID.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: _id = orb(_pkt[0]) if _id == 221: oui_a = orb(_pkt[2]) oui_b = orb(_pkt[3]) oui_c = orb(_pkt[4]) if oui_a == 0x00 and oui_b == 0x50 and oui_c == 0xf2: # MS OUI type_ = orb(_pkt[5]) if type_ == 0x01: # MS WPA IE return Dot11EltMicrosoftWPA else: return Dot11EltVendorSpecific else: return Dot11EltVendorSpecific else: return cls.registered_ies.get(_id, cls) return cls def haslayer(self, cls): if cls == "Dot11Elt": if isinstance(self, Dot11Elt): return True elif issubtype(cls, Dot11Elt): if isinstance(self, cls): return True return super(Dot11Elt, self).haslayer(cls) def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt): return super(Dot11Elt, self).getlayer(cls, nb=nb, _track=_track, _subclass=True, **flt) def post_build(self, p, pay): if self.len is None: p = p[:1] + chb(len(p) - 2) + p[2:] return p + pay
class Dot11Elt(Packet): __slots__ = ["info"] name = "802.11 Information Element" fields_desc = [ ByteEnumField("ID", 0, _dot11_info_elts_ids), FieldLenField("len", None, "info", "B"), StrLenField("info", "", length_from=lambda x: x.len, max_length=255) ] show_indent = 0 def mysummary(self): if self.ID == 0: ssid = repr(self.info) if ssid[:2] in ['b"', "b'"]: ssid = ssid[1:] return "SSID", [Dot11] else: return "" registered_ies = {} @classmethod def register_variant(cls): cls.registered_ies[cls.ID.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: _id = orb(_pkt[0]) if _id == 221: oui_a = orb(_pkt[2]) oui_b = orb(_pkt[3]) oui_c = orb(_pkt[4]) if oui_a == 0x00 and oui_b == 0x50 and oui_c == 0xf2: # MS OUI type_ = orb(_pkt[5]) if type_ == 0x01: # MS WPA IE return Dot11EltMicrosoftWPA else: return Dot11EltVendorSpecific else: return Dot11EltVendorSpecific else: return cls.registered_ies.get(_id, cls) return cls def haslayer(self, cls): if cls == "Dot11Elt": if isinstance(self, Dot11Elt): return True elif issubtype(cls, Dot11Elt): if isinstance(self, cls): return True return super(Dot11Elt, self).haslayer(cls) def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt): return super(Dot11Elt, self).getlayer(cls, nb=nb, _track=_track, _subclass=True, **flt) def pre_dissect(self, s): # Backward compatibility: add info to all elements # This allows to introduce new Dot11Elt classes without breaking # previous code if len(s) >= 3: length = orb(s[1]) if length > 0 and length <= 255: self.info = s[2:2 + length] return s def post_build(self, p, pay): if self.len is None: p = p[:1] + chb(len(p) - 2) + p[2:] return p + pay
class ServerDHParams(_GenericTLSSessionInheritance): """ ServerDHParams for FFDH-based key exchanges, as defined in RFC 5246/7.4.3. Either with .fill_missing() or .post_dissection(), the server_kx_privkey or server_kx_pubkey of the TLS context are updated according to the parsed/assembled values. It is the user's responsibility to store and restore the original values if he wants to keep them. For instance, this could be done between the writing of a ServerKeyExchange and the receiving of a ClientKeyExchange (which includes secret generation). """ name = "Server FFDH parameters" fields_desc = [FieldLenField("dh_plen", None, length_of="dh_p"), StrLenField("dh_p", "", length_from=lambda pkt: pkt.dh_plen), FieldLenField("dh_glen", None, length_of="dh_g"), StrLenField("dh_g", "", length_from=lambda pkt: pkt.dh_glen), FieldLenField("dh_Yslen", None, length_of="dh_Ys"), StrLenField("dh_Ys", "", length_from=lambda pkt: pkt.dh_Yslen)] @crypto_validator def fill_missing(self): """ We do not want TLSServerKeyExchange.build() to overload and recompute things every time it is called. This method can be called specifically to have things filled in a smart fashion. Note that we do not expect default_params.g to be more than 0xff. """ s = self.tls_session default_params = _ffdh_groups['modp2048'][0].parameter_numbers() default_mLen = _ffdh_groups['modp2048'][1] if not self.dh_p: self.dh_p = pkcs_i2osp(default_params.p, default_mLen // 8) if self.dh_plen is None: self.dh_plen = len(self.dh_p) if not self.dh_g: self.dh_g = pkcs_i2osp(default_params.g, 1) if self.dh_glen is None: self.dh_glen = 1 p = pkcs_os2ip(self.dh_p) g = pkcs_os2ip(self.dh_g) real_params = dh.DHParameterNumbers(p, g).parameters(default_backend()) if not self.dh_Ys: s.server_kx_privkey = real_params.generate_private_key() pubkey = s.server_kx_privkey.public_key() y = pubkey.public_numbers().y self.dh_Ys = pkcs_i2osp(y, pubkey.key_size // 8) # else, we assume that the user wrote the server_kx_privkey by himself if self.dh_Yslen is None: self.dh_Yslen = len(self.dh_Ys) if not s.client_kx_ffdh_params: s.client_kx_ffdh_params = real_params @crypto_validator def register_pubkey(self): """ XXX Check that the pubkey received is in the group. """ p = pkcs_os2ip(self.dh_p) g = pkcs_os2ip(self.dh_g) pn = dh.DHParameterNumbers(p, g) y = pkcs_os2ip(self.dh_Ys) public_numbers = dh.DHPublicNumbers(y, pn) s = self.tls_session s.server_kx_pubkey = public_numbers.public_key(default_backend()) if not s.client_kx_ffdh_params: s.client_kx_ffdh_params = pn.parameters(default_backend()) def post_dissection(self, r): try: self.register_pubkey() except ImportError: pass def guess_payload_class(self, p): """ The signature after the params gets saved as Padding. This way, the .getfield() which _TLSServerParamsField inherits from PacketField will return the signature remain as expected. """ return Padding
class RadiusAttribute(Packet): """ Implements a RADIUS attribute (RFC 2865). Every specific RADIUS attribute class should inherit from this one. """ name = "Radius Attribute" fields_desc = [ ByteEnumField("type", 1, _radius_attribute_types), FieldLenField("len", None, "value", "B", adjust=lambda pkt, x: len(pkt.value) + 2), StrLenField("value", "", length_from=lambda pkt: pkt.len - 2) ] registered_attributes = {} @classmethod def register_variant(cls): """ Registers the RADIUS attributes defined in this module. """ if hasattr(cls, "val"): cls.registered_attributes[cls.val] = cls else: cls.registered_attributes[cls.type.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): """ Returns the right RadiusAttribute class for the given data. """ if _pkt: attr_type = orb(_pkt[0]) return cls.registered_attributes.get(attr_type, cls) return cls def haslayer(self, cls): if cls == "RadiusAttribute": if isinstance(self, RadiusAttribute): return True elif issubtype(cls, RadiusAttribute): if isinstance(self, cls): return True return super(RadiusAttribute, self).haslayer(cls) def getlayer(self, cls, nb=1, _track=None, _subclass=True, **flt): return super(RadiusAttribute, self).getlayer(cls, nb=nb, _track=_track, _subclass=True, **flt) def post_build(self, p, pay): length = self.len if length is None: length = len(p) p = p[:1] + struct.pack("!B", length) + p[2:] return p def guess_payload_class(self, _): return Padding
class ECCurvePkt(Packet): name = "Elliptic Curve" fields_desc = [FieldLenField("alen", None, length_of="a", fmt="B"), StrLenField("a", "", length_from=lambda pkt: pkt.alen), FieldLenField("blen", None, length_of="b", fmt="B"), StrLenField("b", "", length_from=lambda pkt: pkt.blen)]
class ServerECDHNamedCurveParams(_GenericTLSSessionInheritance): name = "Server ECDH parameters - Named Curve" fields_desc = [ByteEnumField("curve_type", 3, _tls_ec_curve_types), ShortEnumField("named_curve", None, _tls_named_curves), FieldLenField("pointlen", None, length_of="point", fmt="B"), StrLenField("point", None, length_from=lambda pkt: pkt.pointlen)] @crypto_validator def fill_missing(self): """ We do not want TLSServerKeyExchange.build() to overload and recompute things every time it is called. This method can be called specifically to have things filled in a smart fashion. XXX We should account for the point_format (before 'point' filling). """ s = self.tls_session if self.curve_type is None: self.curve_type = _tls_ec_curve_types["named_curve"] if self.named_curve is None: self.named_curve = 23 curve_group = self.named_curve if curve_group not in _tls_named_curves: # this fallback is arguable curve_group = 23 # default to secp256r1 s.server_kx_privkey = _tls_named_groups_generate(curve_group) if self.point is None: self.point = _tls_named_groups_pubbytes( s.server_kx_privkey ) # else, we assume that the user wrote the server_kx_privkey by himself if self.pointlen is None: self.pointlen = len(self.point) if not s.client_kx_ecdh_params: s.client_kx_ecdh_params = curve_group @crypto_validator def register_pubkey(self): """ XXX Support compressed point format. XXX Check that the pubkey received is on the curve. """ # point_format = 0 # if self.point[0] in [b'\x02', b'\x03']: # point_format = 1 s = self.tls_session s.server_kx_pubkey = _tls_named_groups_import( self.named_curve, self.point ) if not s.client_kx_ecdh_params: s.client_kx_ecdh_params = self.named_curve def post_dissection(self, r): try: self.register_pubkey() except ImportError: pass def guess_payload_class(self, p): return Padding
class PPP_ECP_Option_OUI(PPP_ECP_Option): fields_desc = [ByteEnumField("type", 0, _PPP_ecpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p, x:x+6), StrFixedLenField("oui", "", 3), ByteField("subtype", 0), StrLenField("data", "", length_from=lambda p:p.len-6)]