|
Subject: Updates to IKE attribute processing Newsgroups: gmane.comp.security.scapy.general Date: 2006-02-28 00:02:35 GMT (3 years, 18 weeks, 2 days, 4 hours and 21 minutes ago)
The IKE attribute processing in Scapy had a fairly major bug in that it
treated all attributes as "basic" attributes, consisting of an attribute
type and a two byte value. In reality though, some IKE attributes can
also have 'variable' lengths, where the attribute is expressed as a
type/length/value (TLV). This is perhaps most noticeable in the 'Life
Duration' attribute on transform proposals.
I am attaching a patch to this email which adds support for TLV style
IKE/ISAKMP attributes. The patch also includes much more complete
mapping of IKE Attributes and values. I introduced a small
incompatibility into this data structure (formerly named
ISAKMPTransformTypes) to store a simple boolean on whether the attribute
is allowed to have it's value expressed in a variable sized memory. I
also changed the name for this data structure to be
ISAKMPAttributeTypes, as IKE attributes exist and are used outside of
just transforms. I also changed the calling parameters of the
ISAKMPTransformSetField.num2type method to support my patch for TLV
handling.
In addition to my patch, I'm also attaching a small pcap capture that
shows an IKE proposal with transforms having life durations expressed as
a TLV. Finally, I'm attaching a unit test for some IKE functions that
demonstrate that the current scapy behavior is broken and that my patch
fixes the problem. If you put test_ike.py and the pcap files in a
subdirectory under the main scapy.py directory, you should be able to
execute it to run the tests (it's a simple unittest test case).
Finally, how does one access transform proposals beyond the first one?
For example, using the pcap I've attached:
>>> import scapy
>>> packets=scapy.rdpcap("ike-proposals.pcap")
>>> sa = packets[0].lastlayer()
>>> sa.display()
###[ ISAKMP SA ]###
next_payload= None
res= 0
length= 96
DOI= IPSEC
situation= identity
prop= <ISAKMP_payload_Proposal next_payload=None res=0 length=84 proposal=1 proto=ISAKMP
SPIsize=0 trans_nb=2 trans=<ISAKMP_payload_Transform next_payload=Transform res=0 length=40
num=1 id=KEY_IKE res2=0 transforms=[('Encryption', 7L), ('Hash', 'MD5'), ('Authentication',
'PSK'), ('GroupDesc', 5L), (14L, 256L), ('LifeType', 'Seconds'), ('LifeDuration', 4L),
('Encryption', 20864L)] |<ISAKMP_payload_Transform next_payload=None res=0 length=36 num=2
id=KEY_IKE res2=0 transforms=[('Encryption', '3DES-CBC'), ('Hash', 'SHA'), ('Authentication',
'PSK'), ('GroupDesc', '1024MODPgr'), ('LifeType', 'Seconds'), ('LifeDuration', 4L),
('Encryption', 20864L)] |>> |>
>>> transforms = sa.prop.trans
>>> transforms
<ISAKMP_payload_Transform next_payload=Transform res=0 length=40 num=1 id=KEY_IKE res2=0
transforms=[('Encryption', 7L), ('Hash', 'MD5'), ('Authentication', 'PSK'), ('GroupDesc', 5L),
(14L, 256L), ('LifeType', 'Seconds'), ('LifeDuration', 4L), ('Encryption', 20864L)]
|<ISAKMP_payload_Transform next_payload=None res=0 length=36 num=2 id=KEY_IKE res2=0
transforms=[('Encryption', '3DES-CBC'), ('Hash', 'SHA'), ('Authentication', 'PSK'),
('GroupDesc', '1024MODPgr'), ('LifeType', 'Seconds'), ('LifeDuration', 4L), ('Encryption',
20864L)] |>>
>From here, I can get to the first list of transform tuples, but I've
been unable to figure out how to get to the subsequent ones.
-- William
P.S. I know work still needs to be done on proper handling of IKE. For
example, writing attributes with TLV fields still is not currently
supported. I'll be working on that over the next couple of days
probably.
--- scapy.py-1.0.3.14 2006-02-21 23:04:23.017716605 +0000
+++ scapy.py 2006-02-27 23:20:06.952822123 +0000
@@ -3485,24 +3485,82 @@
# x = len(v)+self.shift
# return x
-ISAKMPTransformTypes = { "Encryption": (1, { "DES-CBS" : 1,
- "3DES-CBC" : 5, }),
+# see http://www.iana.org/assignments/ipsec-registry for details
+ISAKMPAttributeTypes= { "Encryption": (1, { "DES-CBS" : 1,
+ "IDEA-CBC" : 2,
+ "Blowfish-CBC" : 3,
+ "RC5-R16-B64-CBC" : 4,
+ "3DES-CBC" : 5,
+ "CAST-CBC" : 6,
+ "AES-CBC" : 7,
+ "CAMELLIA-CBC" : 8, }, 0),
"Hash": (2, { "MD5": 1,
- "SHA": 2, }),
- "Authentication":(3, { "PSK": 1, }),
+ "SHA": 2,
+ "Tiger": 3,
+ "SHA2-256": 4,
+ "SHA2-384": 5,
+ "SHA2-512": 6,}, 0),
+ "Authentication":(3, { "PSK": 1,
+ "DSS": 2,
+ "RSA Sig": 3,
+ "RSA Encryption": 4,
+ "RSA Encryption Revised": 5,
+ "ElGamal Encryption": 6,
+ "ElGamal Encryption Revised": 7,
+ "ECDSA Sig": 8,
+ "HybridInitRSA": 64221,
+ "HybridRespRSA": 64222,
+ "HybridInitDSS": 64223,
+ "HybridRespDSS": 64224,
+ "XAUTHInitPreShared": 65001,
+ "XAUTHRespPreShared": 65002,
+ "XAUTHInitDSS": 65003,
+ "XAUTHRespDSS": 65004,
+ "XAUTHInitRSA": 65005,
+ "XAUTHRespRSA": 65006,
+ "XAUTHInitRSAEncryption": 65007,
+ "XAUTHRespRSAEncryption": 65008,
+ "XAUTHInitRSARevisedEncryption": 65009,
+ "XAUTHRespRSARevisedEncryptio": 65010, }, 0),
"GroupDesc": (4, { "768MODPgr" : 1,
- "1024MODPgr" : 2, }),
- "LifeType": (11,{ "Seconds":1, }),
- "LifeDuration": (12,{}),
+ "1024MODPgr" : 2,
+ "EC2Ngr155" : 3,
+ "EC2Ngr185" : 4,
+ "1536MODPgr" : 5,
+ "2048MODPgr" : 14,
+ "3072MODPgr" : 15,
+ "4096MODPgr" : 16,
+ "6144MODPgr" : 17,
+ "8192MODPgr" : 18, }, 0),
+ "GroupType": (5, {"MODP": 1,
+ "ECP": 2,
+ "EC2N": 3}, 0),
+ "GroupPrime": (6, {}, 1),
+ "GroupGenerator1":(7, {}, 1),
+ "GroupGenerator2":(8, {}, 1),
+ "GroupCurveA": (9, {}, 1),
+ "GroupCurveB": (10, {}, 1),
+ "LifeType": (11, {"Seconds": 1,
+ "Kilobytes": 2, }, 0),
+ "LifeDuration": (12, {}, 1),
+ "PRF": (13, {}, 0),
+ "KeyLength": (14, {}, 0),
+ "FieldSize": (15, {}, 0),
+ "GroupOrder": (16, {}, 1),
}
+# the name 'ISAKMPTransformTypes' is actually a misnomer (since the table
+# holds info for all ISAKMP Attribute types, not just transforms, but we'll
+# keep it for backwards compatibility... for now at least
+ISAKMPTransformTypes = ISAKMPAttributeTypes
+
ISAKMPTransformNum = {}
for n in ISAKMPTransformTypes:
val = ISAKMPTransformTypes[n]
tmp = {}
for e in val[1]:
tmp[val[1][e]] = e
- ISAKMPTransformNum[val[0]] = (n,tmp)
+ ISAKMPTransformNum[val[0]] = (n,tmp, val[2])
del(n)
del(e)
del(tmp)
@@ -3521,29 +3579,43 @@
else:
enc = int(enc)
return ((val[0] | 0x8000L) << 16) | enc
- def num2type(self, num):
- typ = (num >> 16) & 0x7fff
- enc = num & 0xffff
+ def num2type(self, typ, enc):
val = ISAKMPTransformNum.get(typ,(typ,{}))
enc = val[1].get(enc,enc)
return (val[0],enc)
-
-
def i2m(self, pkt, i):
if i is None:
return ""
i = map(self.type2num, i)
return struct.pack("!"+"I"*len(i),*i)
def m2i(self, pkt, m):
- lst = struct.unpack("!"+"I"*(len(m)/4),m)
- lst = map(self.num2type, lst)
- return lst
+ # I try to ensure that we don't read off the end of our packet based
+ # on bad length fields we're provided in the packet. There are still
+ # conditions where struct.unpack() may not get enough packet data, but
+ # worst case that should result in broken attributes (which would
+ # be expected). (wam)
+ lst = []
+ while len(m)>0:
+ trans_type, = struct.unpack("!H", m[:2])
+ is_tlv = not (trans_type >>15)
+ trans_type &= 0x7fff
+ if is_tlv:
+ # We should probably check to make sure the attribute type we
+ # are looking at is allowed to have a TLV format and issue a
+ # warning if we're given an TLV on a basic attribute.
+ value_len, = struct.unpack("!H", m[2:4])
+ value = reduce(lambda x,y: (x<<8)|y, struct.unpack("!%s" % ("B"*value_len,), m[4:4+value_len]))
+ else:
+ value_len=0
+ value, = struct.unpack("!H", m[2:4])
+ m=m[4+value_len:]
+ lst.append(self.num2type(trans_type, value))
+ return lst
def getfield(self, pkt, s):
- l = getattr(pkt, self.fld)
- l += pkt.get_field(self.fld).shift
- i = self.m2i(pkt, s[:l])
-
- return s[l:],i
+ l = getattr(pkt, self.fld)
+ l += pkt.get_field(self.fld).shift
+ i = self.m2i(pkt, s[:l])
+ return s[l:],i
class StrNullField(StrField):
def addfield(self, pkt, s, val):
--------------------------------------------------------------------- Desinscription: envoyez un message a: scapy.ml-unsubscribe <at> secdev.org Pour obtenir de l'aide, ecrivez a: scapy.ml-help <at> secdev.org |
|
|