From c2333696ccc842c56658dc85a24f786f9e9e4466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Sebechlebsk=C3=BD?= <sebechlebskyjan@gmail.com> Date: Thu, 23 Mar 2017 11:27:49 +0100 Subject: [PATCH] Fix EAP (#557) * Add message field in EAP-Indentity request EAP-Identity request may contain message as stated in RFC3748. * Fix fragmented EAP-TLS Current implementation fails to dissect fragmented EAP-TLS. Fragmented EAP-TLS messages are quite common, in this case only first EAP-TLS will contain tls_message_len field (indicated by L bit), which will be total length of reassembled tls message. Length of tls payload in single EAP-TLS message should therefore be determined by EAP.len field (see RFC5216-Fragmentation). To implement this I find reasonable to make EAP-TLS subclass of EAP. * Fix fragmented EAP-FAST Implementation of EAP-FAST suffers from the same issue as EAP-TLS, see previous commit message. * Fix EAP-MD5 Dissection Implementation of EAP-MD5 was not following RFC3748 (which is referencing RFC1994) properly. Field value_size is determining only size of value_field. It might have length different than 16B in EAP-MD5 request, because in that case it is not used to transmit MD5 hash, but random challenge value. Size of optional_name(extra data) is determined as "rest of" EAP message (len field of EAP). --- scapy/layers/l2.py | 59 +++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py index 584deda1..1bda6318 100644 --- a/scapy/layers/l2.py +++ b/scapy/layers/l2.py @@ -455,7 +455,10 @@ class EAP(Packet): lambda pkt:pkt.code == EAP.RESPONSE and pkt.type == 3), ConditionalField( StrLenField("identity", '', length_from=lambda pkt: pkt.len - 5), - lambda pkt: pkt.code == EAP.RESPONSE and hasattr(pkt, 'type') and pkt.type == 1) + lambda pkt: pkt.code == EAP.RESPONSE and hasattr(pkt, 'type') and pkt.type == 1), + ConditionalField( + StrLenField("message", '', length_from=lambda pkt: pkt.len - 5), + lambda pkt: pkt.code == EAP.REQUEST and hasattr(pkt, 'type') and pkt.type == 1) ] #________________________________________________________________________ @@ -472,6 +475,21 @@ class EAP(Packet): INITIATE = 5 FINISH = 6 + 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: + c = ord(_pkt[0]) + if c in [1, 2] and len(_pkt) >= 5: + t = ord(_pkt[4]) + return cls.registered_options.get(t, cls) + return cls + def answers(self, other): if isinstance(other, EAP): if self.code == self.REQUEST: @@ -491,7 +509,7 @@ class EAP(Packet): return p + pay -class EAP_MD5(Packet): +class EAP_MD5(EAP): """ RFC 3748 - "Extensible Authentication Protocol (EAP)" @@ -499,13 +517,18 @@ class EAP_MD5(Packet): name = "EAP-MD5" fields_desc = [ - ByteField("value_size", 0), - StrFixedLenField("value", 0, length=16), # MD5 hash length - StrLenField("optional_name", "", length_from=lambda p: p.value_size - 16) + ByteEnumField("code", 1, eap_codes), + ByteField("id", 0), + FieldLenField("len", None, fmt="H", length_of="optional_name", + adjust=lambda p, x: x + p.value_size + 6), + ByteEnumField("type", 4, eap_types), + FieldLenField("value_size", None, fmt="B", length_of="value"), + StrLenField("value", '', length_from=lambda p: p.value_size), + StrLenField("optional_name", '', length_from=lambda p: p.len - p.value_size - 6) ] -class EAP_TLS(Packet): +class EAP_TLS(EAP): """ RFC 5216 - "The EAP-TLS Authentication Protocol" @@ -513,18 +536,21 @@ class EAP_TLS(Packet): name = "EAP-TLS" fields_desc = [ + ByteEnumField("code", 1, eap_codes), + ByteField("id", 0), + FieldLenField("len", None, fmt="H", length_of="tls_data", + adjust=lambda p, x: x + 10 if p.L == 1 else x + 6), + ByteEnumField("type", 13, eap_types), BitField('L', 0, 1), BitField('M', 0, 1), BitField('S', 0, 1), BitField('reserved', 0, 5), - ConditionalField( - IntField('tls_message_len', 0), lambda pkt: pkt.L == 1), - ConditionalField( - StrLenField('tls_data', '', length_from=lambda pkt: pkt.tls_message_len), lambda pkt: pkt.L == 1) + ConditionalField(IntField('tls_message_len', 0), lambda pkt: pkt.L == 1), + StrLenField('tls_data', '', length_from=lambda pkt: pkt.len - 10 if pkt.L == 1 else pkt.len - 6) ] -class EAP_FAST(Packet): +class EAP_FAST(EAP): """ RFC 4851 - "The Flexible Authentication via Secure Tunneling @@ -533,14 +559,18 @@ class EAP_FAST(Packet): name = "EAP-FAST" fields_desc = [ + ByteEnumField("code", 1, eap_codes), + ByteField("id", 0), + FieldLenField("len", None, fmt="H", length_of="data", + adjust=lambda p, x: x + 10 if p.L == 1 else x + 6), + ByteEnumField("type", 43, eap_types), BitField('L', 0, 1), BitField('M', 0, 1), BitField('S', 0, 1), BitField('reserved', 0, 2), BitField('version', 0, 3), ConditionalField(IntField('message_len', 0), lambda pkt: pkt.L == 1), - ConditionalField( - StrLenField('data', '', length_from=lambda pkt: pkt.message_len), lambda pkt: pkt.L == 1) + StrLenField('data', '', length_from=lambda pkt: pkt.len - 10 if pkt.L == 1 else pkt.len - 6) ] @@ -1068,9 +1098,6 @@ bind_layers( GRErouting, conf.raw_layer,{ "address_family" : 0, "SRE_len" : 0 bind_layers( GRErouting, GRErouting, { } ) bind_layers( EAPOL, EAP, type=0) bind_layers( EAPOL, MKAPDU, type=5) -bind_layers(EAP, EAP_TLS, type=13) -bind_layers(EAP, EAP_FAST, type=43) -bind_layers( EAP, EAP_MD5, type=4) bind_layers( LLC, STP, dsap=66, ssap=66, ctrl=3) bind_layers( LLC, SNAP, dsap=170, ssap=170, ctrl=3) bind_layers( SNAP, Dot1Q, code=33024) -- GitLab