class ISIS_AuthenticationTlv(ISIS_GenericTlv): name = "ISIS Authentication TLV" fields_desc = [ByteEnumField("type", 10, _isis_tlv_names), FieldLenField("len", None, length_of= "password", adjust=lambda pkt,x: x + 1, fmt="B"), ByteEnumField("authtype", 1, {1: "Plain", 17: "HMAC-MD5"}), BoundStrLenField("password", "", maxlen= 254, length_from=lambda pkt: pkt.len - 1)]
class ISIS_ExtendedIpReachabilityTlv(ISIS_GenericTlv): name = "ISIS Extended IP Reachability TLV" fields_desc = [ByteEnumField("type", 135, _isis_tlv_names), FieldLenField("len", None, length_of="pfxs", fmt="B"), PacketListField("pfxs", [], ISIS_ExtendedIpPrefix, length_from= lambda pkt: pkt.len)]
class SAPRouter(Packet): """SAP Router packet This packet is used for general SAP Router packets. There are (at least) five types of SAP Router packets: 1. Route packets. For requesting the routing of a connection to a remote hosts. The packet contains some general information and a connection string with a list of routing hops (:class:`SAPRouterRouteHop`). 2. Administration packets. This packet is used for the SAP Router to send administrative commands. It's suppose to be used only from the hosts running the SAP Router or when an specific route is included in the routing table. Generally administration packets are not accepted from the external binding. 3. Error Information packets. Packets sent when an error occurred. 4. Control Message packets. Used to perform some control activities, like retrieving the current SAPRouter version or to perform the SNC handshake. They have the same structure that error information packets. 5. Route accepted packet. Used to acknowledge a route request ("NI_PONG"). Routed packets and some responses doesn't fill in these five packet types. For identifying those cases, you should check the type using the function :class:`router_is_known_type`. NI Versions found (unconfirmed): - 30: Release 40C - 36: Release <6.20 - 38: Release 7.00/7.10 - 39: Release 7.11 - 40: Release 7.20/7.21 """ # Default router version to use SAPROUTER_DEFAULT_VERSION = 40 # Constants for router types SAPROUTER_ROUTE = "NI_ROUTE" """ :cvar: Constant for route packets :type: C{string} """ SAPROUTER_ADMIN = "ROUTER_ADM" """ :cvar: Constant for administration packets :type: C{string} """ SAPROUTER_ERROR = "NI_RTERR" """ :cvar: Constant for error information packets :type: C{string} """ SAPROUTER_CONTROL = "NI_RTERR" """ :cvar: Constant for control messages packets :type: C{string} """ SAPROUTER_PONG = "NI_PONG" """ :cvar: Constant for route accepted packets :type: C{string} """ router_type_values = [ SAPROUTER_ADMIN, SAPROUTER_ERROR, SAPROUTER_CONTROL, SAPROUTER_ROUTE, SAPROUTER_PONG, ] """ :cvar: List of known packet types :type: ``list`` of C{string} """ name = "SAP Router" fields_desc = [ # General fields present in all SAP Router packets StrNullField("type", SAPROUTER_ROUTE), ConditionalField( ByteField("version", 2), lambda pkt: router_is_known_type(pkt) and not router_is_pong(pkt)), # Route packets ConditionalField( ByteField("route_ni_version", SAPROUTER_DEFAULT_VERSION), router_is_route), ConditionalField(ByteField("route_entries", 0), router_is_route), ConditionalField( ByteEnumKeysField("route_talk_mode", 0, router_ni_talk_mode_values), router_is_route), ConditionalField(ShortField("route_padd", 0), router_is_route), ConditionalField(ByteField("route_rest_nodes", 0), router_is_route), ConditionalField( FieldLenField("route_length", 0, length_of="route_string", fmt="I"), router_is_route), ConditionalField(IntField("route_offset", 0), router_is_route), ConditionalField( PacketListField("route_string", None, SAPRouterRouteHop, length_from=lambda pkt: pkt.route_length), router_is_route), # Admin packets ConditionalField( ByteEnumKeysField("adm_command", 0x02, router_adm_commands), router_is_admin), ConditionalField( ShortField("adm_unused", 0x00), lambda pkt: router_is_admin(pkt) and pkt.adm_command not in [10, 11, 12, 13]), # Info Request fields ConditionalField( StrNullFixedLenField("adm_password", "", 19), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [2]), # Cancel Route fields ConditionalField( FieldLenField("adm_client_count", None, count_of="adm_client_ids", fmt="H"), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [6]), # Trace Connection fields ConditionalField( FieldLenField("adm_client_count", None, count_of="adm_client_ids", fmt="I"), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [12, 13]), # Cancel Route or Trace Connection fields ConditionalField( FieldListField("adm_client_ids", [0x00], IntField("", 0), count_from=lambda pkt: pkt.adm_client_count), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [6, 12, 13]), # Set/Clear Peer Trace fields # TODO: Check whether this field should be a IPv6 address or another proper field ConditionalField( StrFixedLenField("adm_address_mask", "", 32), lambda pkt: router_is_admin(pkt) and pkt.adm_command in [10, 11]), # Error Information/Control Messages fields ConditionalField( ByteEnumKeysField("opcode", 0, router_control_opcodes), lambda pkt: router_is_error(pkt) or router_is_control(pkt)), ConditionalField( ByteField("opcode_padd", 0), lambda pkt: router_is_error(pkt) or router_is_control(pkt)), ConditionalField( SignedIntEnumField("return_code", 0, router_return_codes), lambda pkt: router_is_error(pkt) or router_is_control(pkt)), # Error Information fields ConditionalField( FieldLenField("err_text_length", None, length_of="err_text_value", fmt="!I"), lambda pkt: router_is_error(pkt) and pkt.opcode == 0), ConditionalField( PacketField("err_text_value", SAPRouterError(), SAPRouterError), lambda pkt: router_is_error(pkt) and pkt.opcode == 0 and pkt.err_text_length > 0), ConditionalField(IntField("err_text_unknown", 0), lambda pkt: router_is_error(pkt) and pkt.opcode == 0), # Control Message fields ConditionalField( IntField("control_text_length", 0), lambda pkt: router_is_control(pkt) and pkt.opcode != 0), ConditionalField( StrField("control_text_value", "*ERR"), lambda pkt: router_is_control(pkt) and pkt.opcode != 0), # SNC Frame fields ConditionalField( PacketField("snc_frame", None, SAPSNCFrame), lambda pkt: router_is_control(pkt) and pkt.opcode in [70, 71]) ]
class OBD_S07_DTC(Packet): name = "S7_ResponsePendingDTCs" fields_desc = [ FieldLenField('count', None, count_of='dtcs', fmt='B'), PacketListField('dtcs', [], OBD_DTC, count_from=lambda pkt: pkt.count) ]
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 params = s.client_kx_ffdh_params s.client_kx_privkey = 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 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 s.compute_ms_and_derive_keys() def guess_payload_class(self, p): return Padding
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() 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]]() import_point = ec.EllipticCurvePublicNumbers.from_encoded_point public_numbers = import_point(curve, self.key_exchange) self.pubkey = public_numbers.public_key(default_backend()) def post_dissection(self, r): try: self.register_pubkey() except ImportError: pass def extract_padding(self, s): return "", s
class PPP_LCP_Magic_Number_Option(PPP_LCP_Option): fields_desc = [ByteEnumField("type", 5, _PPP_lcp_optiontypes), FieldLenField("len", 6, fmt="B", adjust=lambda p, x:6), IntField("magic_number", None)]
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 PPP_LCP_ACCM_Option(PPP_LCP_Option): fields_desc = [ByteEnumField("type", 2, _PPP_lcp_optiontypes), FieldLenField("len", 6, fmt="B"), BitField("accm", 0x00000000, 32)]
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 PPP_LCP_MRU_Option(PPP_LCP_Option): fields_desc = [ByteEnumField("type", 1, _PPP_lcp_optiontypes), FieldLenField("len", 4, fmt="B", adjust=lambda p, x:4), ShortField("max_recv_unit", 1500)]
class PPP_ECP(Packet): fields_desc = [ByteEnumField("code", 1, _PPP_conftypes), XByteField("id", 0), FieldLenField("len", None, fmt="H", length_of="options", adjust=lambda p, x:x + 4), PacketListField("options", [], PPP_ECP_Option, length_from=lambda p:p.len - 4,)]
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)]
def i2repr(self, pkt, x): return repr(x) if not x else str(FieldLenField.i2h(self, pkt, x) << 2) + " bytes" # noqa: E501
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 PPP_IPCP_Option_NBNS2(PPP_IPCP_Option): name = "PPP IPCP Option: NBNS2 Address" fields_desc = [ByteEnumField("type", 132, _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p, x:x + 2), IPField("data", "0.0.0.0"), ConditionalField(StrLenField("garbage", "", length_from=lambda pkt:pkt.len - 6), lambda p:p.len != 6)]
class PPP_LCP_Code_Reject(PPP_LCP): fields_desc = [ByteEnumField("code", 7, _PPP_lcptypes), XByteField("id", 0), FieldLenField("len", None, fmt="H", length_of="rejected_packet", adjust=lambda p, x:x + 4), PacketField("rejected_packet", None, PPP_LCP)]
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: curve = ec.SECP256R1() s.server_kx_privkey = ec.generate_private_key( curve, default_backend()) self.named_curve = next( ( cid for cid, name in six.iteritems( _tls_named_curves) # noqa: E501 if name == curve.name), 0) else: curve_name = _tls_named_curves.get(self.named_curve) if curve_name is None: # this fallback is arguable curve = ec.SECP256R1() else: curve_cls = ec._CURVE_TYPES.get(curve_name) if curve_cls is None: # this fallback is arguable curve = ec.SECP256R1() else: curve = curve_cls() s.server_kx_privkey = ec.generate_private_key( curve, default_backend()) if self.point is None: pubkey = s.server_kx_privkey.public_key() try: # cryptography >= 2.5 self.point = pubkey.public_bytes( serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint) except TypeError: # older versions self.key_exchange = pubkey.public_numbers().encode_point() # 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 @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 curve_name = _tls_named_curves[self.named_curve] curve = ec._CURVE_TYPES[curve_name]() s = self.tls_session try: # cryptography >= 2.5 import_point = ec.EllipticCurvePublicKey.from_encoded_point s.server_kx_pubkey = import_point(curve, self.point) except AttributeError: import_point = ec.EllipticCurvePublicNumbers.from_encoded_point pubnum = import_point(curve, self.point) s.server_kx_pubkey = pubnum.public_key(default_backend()) if not s.client_kx_ecdh_params: s.client_kx_ecdh_params = curve def post_dissection(self, r): try: self.register_pubkey() except ImportError: pass def guess_payload_class(self, p): return Padding
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=%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 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 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 TLS_Ext_Padding(TLS_Ext_Unknown): # RFC 7685 name = "TLS Extension - Padding" fields_desc = [ShortEnumField("type", 0x15, _tls_ext), FieldLenField("len", None, length_of="padding"), StrLenField("padding", "", length_from=lambda pkt: pkt.len)]
class SAPCARArchiveFilev200Format(PacketNoPadded): """SAP CAR file information format This is ued to parse files inside a SAP CAR archive. """ name = "SAP CAR Archive File 2.00" version = SAPCAR_VERSION_200 is_filename_null_terminated = False fields_desc = [ StrFixedLenField("type", SAPCAR_TYPE_FILE, 2), LEIntField("perm_mode", 0), LELongField("file_length_low", 0), LEIntField("file_length_high", 0), LELongField("timestamp", 0), LEIntField("code_page", 0), FieldLenField("user_info_length", None, length_of="user_info", fmt="<H"), FieldLenField("filename_length", None, length_of="filename", fmt="<H"), StrNullFixedLenField( "filename", None, length_from=lambda x: x.filename_length, null_terminated=lambda x: x.is_filename_null_terminated), StrFixedLenField("user_info", None, length_from=lambda x: x.user_info_length), ConditionalField( PacketListStopField("blocks", None, SAPCARCompressedBlockFormat, stop=sapcar_is_last_block), lambda x: x.type == SAPCAR_TYPE_FILE and x.file_length > 0), ] @property def file_length(self): """Getter for the file length fields. It converts the two length fields (low and high) as provided in the archive file into a long long integer. """ return (self.file_length_high * SIZE_FOUR_GB) + self.file_length_low @file_length.setter def file_length(self, file_length): """Setter for the file length fields. It splits the long long integer int on the two length fields (low and high) as required by the archive file. """ self.file_length_low = file_length & 0xffffffff self.file_length_high = file_length >> 32 def extract(self, fd): """Extracts the archive file and writes the extracted file to the provided file object. Returns the checksum obtained from the archive. If blocks are uncompressed, the file is directly extracted. If the blocks are compressed, each block is added to a buffer, skipping the length field, and decompression is performed after the block marked as end of data. Expected length and compression header is obtained from the first block and checksum from the end of data block. :param fd: file-like object to write the extracted file to :type fd: file :return: checksum :rtype: int :raise DecompressError: If there's a decompression error :raise SAPCARInvalidFileException: If the file is invalid """ if self.file_length == 0: return 0 compressed = "" checksum = 0 exp_length = None remaining_length = self.file_length for block in self.blocks: # Process uncompressed block types if block.type in [ SAPCAR_BLOCK_TYPE_UNCOMPRESSED, SAPCAR_BLOCK_TYPE_UNCOMPRESSED_LAST ]: fd.write(block.compressed) remaining_length -= len(block.compressed) # Store compressed block types for later decompression elif block.type in [ SAPCAR_BLOCK_TYPE_COMPRESSED, SAPCAR_BLOCK_TYPE_COMPRESSED_LAST ]: # Add compressed block to a buffer, skipping the first 4 bytes of each block (uncompressed length) compressed += str(block.compressed)[4:] # If the expected length wasn't already set, do it if not exp_length: exp_length = block.compressed.uncompress_length else: raise SAPCARInvalidFileException("Invalid block type found") # Check end of data block, performing decompression if needed if sapcar_is_last_block(block): checksum = block.checksum # If there was at least one compressed block that set the expected length, decompress it if exp_length: (_, block_length, block_buffer) = decompress(str(compressed), exp_length) if block_length != exp_length or not block_buffer: raise DecompressError("Error decompressing block") fd.write(block_buffer) break return checksum
class SSLv2ClientMasterKey(_SSLv2Handshake): """ SSLv2 ClientMasterKey. """ __slots__ = ["decryptedkey"] name = "SSLv2 Handshake - Client Master Key" fields_desc = [ ByteEnumField("msgtype", 2, _sslv2_handshake_type), _SSLv2CipherSuiteField("cipher", None, _tls_cipher_suites), FieldLenField("clearkeylen", None, fmt="!H", length_of="clearkey"), FieldLenField("encryptedkeylen", None, fmt="!H", length_of="encryptedkey"), FieldLenField("keyarglen", None, fmt="!H", length_of="keyarg"), XStrLenField("clearkey", "", length_from=lambda pkt: pkt.clearkeylen), _SSLv2EncryptedKeyField( "encryptedkey", "", length_from=lambda pkt: pkt.encryptedkeylen), # noqa: E501 XStrLenField("keyarg", "", length_from=lambda pkt: pkt.keyarglen) ] def __init__(self, *args, **kargs): """ When post_building, the packets fields are updated (this is somewhat non-standard). We might need these fields later, but calling __str__ on a new packet (i.e. not dissected from a raw string) applies post_build to an object different from the original one... unless we hackishly always set self.explicit to 1. """ self.decryptedkey = kargs.pop("decryptedkey", b"") super(SSLv2ClientMasterKey, self).__init__(*args, **kargs) self.explicit = 1 def pre_dissect(self, s): clearkeylen = struct.unpack("!H", s[4:6])[0] encryptedkeylen = struct.unpack("!H", s[6:8])[0] encryptedkeystart = 10 + clearkeylen encryptedkey = s[encryptedkeystart:encryptedkeystart + encryptedkeylen] if self.tls_session.server_rsa_key: self.decryptedkey = \ self.tls_session.server_rsa_key.decrypt(encryptedkey) else: self.decryptedkey = None return s def post_build(self, pkt, pay): cs_val = None if self.cipher is None: common_cs = self.tls_session.sslv2_common_cs cs_vals = get_usable_ciphersuites(common_cs, "SSLv2") if len(cs_vals) == 0: warning("No known common cipher suite between SSLv2 Hellos.") cs_val = 0x0700c0 cipher = b"\x07\x00\xc0" else: cs_val = cs_vals[0] # XXX choose the best one cipher = struct.pack(">BH", cs_val >> 16, cs_val & 0x00ffff) cs_cls = _tls_cipher_suites_cls[cs_val] self.cipher = cs_val else: cipher = pkt[1:4] cs_val = struct.unpack("!I", b"\x00" + cipher)[0] if cs_val not in _tls_cipher_suites_cls: warning("Unknown ciphersuite %d from ClientMasterKey" % cs_val) cs_cls = None else: cs_cls = _tls_cipher_suites_cls[cs_val] if cs_cls: if (self.encryptedkey == b"" and len(self.tls_session.server_certs) > 0): # else, the user is responsible for export slicing & encryption key = randstring(cs_cls.cipher_alg.key_len) if self.clearkey == b"" and cs_cls.kx_alg.export: self.clearkey = key[:-5] if self.decryptedkey == b"": if cs_cls.kx_alg.export: self.decryptedkey = key[-5:] else: self.decryptedkey = key pubkey = self.tls_session.server_certs[0].pubKey self.encryptedkey = pubkey.encrypt(self.decryptedkey) if self.keyarg == b"" and cs_cls.cipher_alg.type == "block": self.keyarg = randstring(cs_cls.cipher_alg.block_size) clearkey = self.clearkey or b"" if self.clearkeylen is None: self.clearkeylen = len(clearkey) clearkeylen = struct.pack("!H", self.clearkeylen) encryptedkey = self.encryptedkey or b"" if self.encryptedkeylen is None: self.encryptedkeylen = len(encryptedkey) encryptedkeylen = struct.pack("!H", self.encryptedkeylen) keyarg = self.keyarg or b"" if self.keyarglen is None: self.keyarglen = len(keyarg) keyarglen = struct.pack("!H", self.keyarglen) s = (pkt[:1] + cipher + clearkeylen + encryptedkeylen + keyarglen + clearkey + encryptedkey + keyarg) return s + pay def tls_session_update(self, msg_str): super(SSLv2ClientMasterKey, self).tls_session_update(msg_str) s = self.tls_session cs_val = self.cipher if cs_val not in _tls_cipher_suites_cls: warning("Unknown cipher suite %d from ClientMasterKey" % cs_val) cs_cls = None else: cs_cls = _tls_cipher_suites_cls[cs_val] tls_version = s.tls_version or 0x0002 connection_end = s.connection_end wcs_seq_num = s.wcs.seq_num s.pwcs = writeConnState(ciphersuite=cs_cls, connection_end=connection_end, seq_num=wcs_seq_num, tls_version=tls_version) rcs_seq_num = s.rcs.seq_num s.prcs = readConnState(ciphersuite=cs_cls, connection_end=connection_end, seq_num=rcs_seq_num, tls_version=tls_version) if self.decryptedkey is not None: s.master_secret = self.clearkey + self.decryptedkey s.compute_sslv2_km_and_derive_keys() if s.pwcs.cipher.type == "block": s.pwcs.cipher.iv = self.keyarg if s.prcs.cipher.type == "block": s.prcs.cipher.iv = self.keyarg s.triggered_prcs_commit = True s.triggered_pwcs_commit = True
class ARP(Packet): name = "ARP" fields_desc = [ XShortField("hwtype", 0x0001), XShortEnumField("ptype", 0x0800, ETHER_TYPES), FieldLenField("hwlen", None, fmt="B", length_of="hwsrc"), FieldLenField("plen", None, fmt="B", length_of="psrc"), ShortEnumField("op", 1, { "who-has": 1, "is-at": 2, "RARP-req": 3, "RARP-rep": 4, "Dyn-RARP-req": 5, "Dyn-RAR-rep": 6, "Dyn-RARP-err": 7, "InARP-req": 8, "InARP-rep": 9 }), MultipleTypeField( [ (SourceMACField("hwsrc"), (lambda pkt: pkt.hwtype == 1 and pkt.hwlen == 6, lambda pkt, val: pkt.hwtype == 1 and ( pkt.hwlen == 6 or (pkt.hwlen is None and (val is None or len(val) == 6 or valid_mac(val))) ))), ], StrFixedLenField("hwsrc", None, length_from=lambda pkt: pkt.hwlen), ), MultipleTypeField( [ (SourceIPField("psrc", "pdst"), (lambda pkt: pkt.ptype == 0x0800 and pkt.plen == 4, lambda pkt, val: pkt.ptype == 0x0800 and ( pkt.plen == 4 or (pkt.plen is None and (val is None or valid_net(val))) ))), (SourceIP6Field("psrc", "pdst"), (lambda pkt: pkt.ptype == 0x86dd and pkt.plen == 16, lambda pkt, val: pkt.ptype == 0x86dd and ( pkt.plen == 16 or (pkt.plen is None and (val is None or valid_net6(val))) ))), ], StrFixedLenField("psrc", None, length_from=lambda pkt: pkt.plen), ), MultipleTypeField( [ (MACField("hwdst", ETHER_ANY), (lambda pkt: pkt.hwtype == 1 and pkt.hwlen == 6, lambda pkt, val: pkt.hwtype == 1 and ( pkt.hwlen == 6 or (pkt.hwlen is None and (val is None or len(val) == 6 or valid_mac(val))) ))), ], StrFixedLenField("hwdst", None, length_from=lambda pkt: pkt.hwlen), ), MultipleTypeField( [ (IPField("pdst", "0.0.0.0"), (lambda pkt: pkt.ptype == 0x0800 and pkt.plen == 4, lambda pkt, val: pkt.ptype == 0x0800 and ( pkt.plen == 4 or (pkt.plen is None and (val is None or valid_net(val))) ))), (IP6Field("pdst", "::"), (lambda pkt: pkt.ptype == 0x86dd and pkt.plen == 16, lambda pkt, val: pkt.ptype == 0x86dd and ( pkt.plen == 16 or (pkt.plen is None and (val is None or valid_net6(val))) ))), ], StrFixedLenField("pdst", None, length_from=lambda pkt: pkt.plen), ), ] def hashret(self): # type: () -> bytes return struct.pack(">HHH", self.hwtype, self.ptype, ((self.op + 1) // 2)) + self.payload.hashret() def answers(self, other): # type: (Packet) -> int if not isinstance(other, ARP): return False if self.op != other.op + 1: return False # We use a loose comparison on psrc vs pdst to catch answers # with ARP leaks self_psrc = self.get_field('psrc').i2m(self, self.psrc) # type: bytes other_pdst = other.get_field('pdst').i2m(other, other.pdst) \ # type: bytes return self_psrc[:len(other_pdst)] == other_pdst[:len(self_psrc)] def route(self): # type: () -> Tuple[Optional[str], Optional[str], Optional[str]] fld, dst = cast(Tuple[MultipleTypeField, str], self.getfield_and_val("pdst")) fld_inner, dst = fld._find_fld_pkt_val(self, dst) if isinstance(dst, Gen): dst = next(iter(dst)) if isinstance(fld_inner, IP6Field): return conf.route6.route(dst) elif isinstance(fld_inner, IPField): return conf.route.route(dst) else: return None, None, None def extract_padding(self, s): # type: (bytes) -> Tuple[bytes, bytes] return b"", s def mysummary(self): # type: () -> str if self.op == 1: return self.sprintf("ARP who has %pdst% says %psrc%") if self.op == 2: return self.sprintf("ARP is at %hwsrc% says %psrc%") return self.sprintf("ARP %op% %psrc% > %pdst%")
class SD(_SDPacketBase): """ SD Packet NOTE : when adding 'entries' or 'options', do not use list.append() method but create a new list e.g. : p = SD() p.option_array = [SDOption_Config(),SDOption_IP6_EndPoint()] """ SOMEIP_MSGID_SRVID = 0xffff SOMEIP_MSGID_SUBID = 0x1 SOMEIP_MSGID_EVENTID = 0x100 SOMEIP_PROTO_VER = 0x01 SOMEIP_IFACE_VER = 0x01 SOMEIP_MSG_TYPE = SOMEIP.TYPE_NOTIFICATION name = "SD" _sdFlag = collections.namedtuple('Flag', 'mask offset') FLAGSDEF = { "REBOOT": _sdFlag(mask=0x80, offset=7), "UNICAST": _sdFlag(mask=0x40, offset=6) } name = "SD" fields_desc = [ ByteField("flags", 0), X3BytesField("res", 0), FieldLenField("len_entry_array", None, length_of="entry_array", fmt="!I"), PacketListField("entry_array", None, cls=_SDEntry, length_from=lambda pkt: pkt.len_entry_array), FieldLenField("len_option_array", None, length_of="option_array", fmt="!I"), PacketListField("option_array", None, cls=_SDOption, length_from=lambda pkt: pkt.len_option_array) ] def get_flag(self, name): name = name.upper() if name in self.FLAGSDEF: return ((self.flags & self.FLAGSDEF[name].mask) >> self.FLAGSDEF[name].offset) else: return None def set_flag(self, name, value): name = name.upper() if name in self.FLAGSDEF: self.flags = (self.flags & (ctypes.c_ubyte(~self.FLAGSDEF[name].mask).value)) \ | ((value & 0x01) << self.FLAGSDEF[name].offset) def set_entryArray(self, entry_list): if isinstance(entry_list, list): self.entry_array = entry_list else: self.entry_array = [entry_list] def set_optionArray(self, option_list): if isinstance(option_list, list): self.option_array = option_list else: self.option_array = [option_list] def get_someip(self, stacked=False): p = SOMEIP() p.msg_id.srv_id = SD.SOMEIP_MSGID_SRVID p.msg_id.sub_id = SD.SOMEIP_MSGID_SUBID p.msg_id.event_id = SD.SOMEIP_MSGID_EVENTID p.proto_ver = SD.SOMEIP_PROTO_VER p.iface_ver = SD.SOMEIP_IFACE_VER p.msg_type = SD.SOMEIP_MSG_TYPE if stacked: return p / self else: return p
class ISIS_AreaTlv(ISIS_GenericTlv): name = "ISIS Area TLV" fields_desc = [ByteEnumField("type", 1, _isis_tlv_names), FieldLenField("len", None, length_of= "areas", fmt="B"), PacketListField("areas", [], ISIS_AreaEntry, length_from=lambda x: x.len)]
def addfield(self, pkt, s, val): return s + raw(SDNVUtil.encode(FieldLenField.i2m(self, pkt, val)))
class ISIS_DynamicHostnameTlv(ISIS_GenericTlv): name = "ISIS Dynamic Hostname TLV" fields_desc = [ByteEnumField("type", 137, _isis_tlv_names), FieldLenField("len", None, length_of= "hostname", fmt="B"), BoundStrLenField("hostname", "", length_from=lambda pkt: pkt.len)]
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 ISIS_ExtendedIsReachabilityTlv(ISIS_GenericTlv): name = "ISIS Extended IS Reachability TLV" fields_desc = [ByteEnumField("type", 22, _isis_tlv_names), FieldLenField("len", None, length_of="neighbours", fmt="B"), PacketListField("neighbours", [], ISIS_ExtendedIsNeighbourEntry, length_from=lambda x: x.len)]
class IE_ExtensionHeaderList(IE_Base): name = "Extension Header List" fields_desc = [ByteEnumField("ietype", 141, IEType), FieldLenField("length", None, length_of="extension_headers"), # noqa: E501 FieldListField("extension_headers", [64, 192], ByteField("", 0))] # noqa: E501
def __init__(self): FieldLenField.__init__(self, "pdulength", None, length_of="tlvs", adjust=lambda pkt,x: x + pkt.underlayer.hdrlen)