| #!/usr/bin/env python |
| |
| # This file is part of Scapy |
| # Scapy is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 2 of the License, or |
| # any later version. |
| # |
| # Scapy is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with Scapy. If not, see <http://www.gnu.org/licenses/>. |
| |
| # scapy.contrib.description = IKEv2 |
| # scapy.contrib.status = loads |
| |
| import logging |
| import struct |
| |
| |
| ## Modified from the original ISAKMP code by Yaron Sheffer <yaronf.ietf@gmail.com>, June 2010. |
| |
| from scapy.packet import * |
| from scapy.fields import * |
| from scapy.layers.inet6 import * |
| from scapy.layers.x509 import X509_Cert, X509_CRL |
| from scapy.ansmachine import * |
| from scapy.layers.inet import IP,UDP |
| from scapy.layers.isakmp import ISAKMP |
| from scapy.sendrecv import sr |
| |
| # see http://www.iana.org/assignments/ikev2-parameters for details |
| IKEv2AttributeTypes= { "Encryption": (1, { "DES-IV64" : 1, |
| "DES" : 2, |
| "3DES" : 3, |
| "RC5" : 4, |
| "IDEA" : 5, |
| "CAST" : 6, |
| "Blowfish" : 7, |
| "3IDEA" : 8, |
| "DES-IV32" : 9, |
| "AES-CBC" : 12, |
| "AES-CTR" : 13, |
| "AES-CCM-8" : 14, |
| "AES-CCM-12" : 15, |
| "AES-CCM-16" : 16, |
| "AES-GCM-8ICV" : 18, |
| "AES-GCM-12ICV" : 19, |
| "AES-GCM-16ICV" : 20, |
| "Camellia-CBC" : 23, |
| "Camellia-CTR" : 24, |
| "Camellia-CCM-8ICV" : 25, |
| "Camellia-CCM-12ICV" : 26, |
| "Camellia-CCM-16ICV" : 27, |
| }, 0), |
| "PRF": (2, {"PRF_HMAC_MD5":1, |
| "PRF_HMAC_SHA1":2, |
| "PRF_HMAC_TIGER":3, |
| "PRF_AES128_XCBC":4, |
| "PRF_HMAC_SHA2_256":5, |
| "PRF_HMAC_SHA2_384":6, |
| "PRF_HMAC_SHA2_512":7, |
| "PRF_AES128_CMAC":8, |
| }, 0), |
| "Integrity": (3, { "HMAC-MD5-96": 1, |
| "HMAC-SHA1-96": 2, |
| "DES-MAC": 3, |
| "KPDK-MD5": 4, |
| "AES-XCBC-96": 5, |
| "HMAC-MD5-128": 6, |
| "HMAC-SHA1-160": 7, |
| "AES-CMAC-96": 8, |
| "AES-128-GMAC": 9, |
| "AES-192-GMAC": 10, |
| "AES-256-GMAC": 11, |
| "SHA2-256-128": 12, |
| "SHA2-384-192": 13, |
| "SHA2-512-256": 14, |
| }, 0), |
| "GroupDesc": (4, { "768MODPgr" : 1, |
| "1024MODPgr" : 2, |
| "1536MODPgr" : 5, |
| "2048MODPgr" : 14, |
| "3072MODPgr" : 15, |
| "4096MODPgr" : 16, |
| "6144MODPgr" : 17, |
| "8192MODPgr" : 18, |
| "256randECPgr" : 19, |
| "384randECPgr" : 20, |
| "521randECPgr" : 21, |
| "1024MODP160POSgr" : 22, |
| "2048MODP224POSgr" : 23, |
| "2048MODP256POSgr" : 24, |
| "192randECPgr" : 25, |
| "224randECPgr" : 26, |
| }, 0), |
| "Extended Sequence Number": (5, {"No ESN": 0, |
| "ESN": 1, }, 0), |
| } |
| |
| IKEv2AuthenticationTypes = { |
| 0 : "Reserved", |
| 1 : "RSA Digital Signature", |
| 2 : "Shared Key Message Integrity Code", |
| 3 : "DSS Digital Signature", |
| 9 : "ECDSA with SHA-256 on the P-256 curve", |
| 10 : "ECDSA with SHA-384 on the P-384 curve", |
| 11 : "ECDSA with SHA-512 on the P-521 curve", |
| 12 : "Generic Secure Password Authentication Method", |
| 13 : "NULL Authentication", |
| 14 : "Digital Signature" |
| } |
| |
| IKEv2NotifyMessageTypes = { |
| 1 : "UNSUPPORTED_CRITICAL_PAYLOAD", |
| 4 : "INVALID_IKE_SPI", |
| 5 : "INVALID_MAJOR_VERSION", |
| 7 : "INVALID_SYNTAX", |
| 9 : "INVALID_MESSAGE_ID", |
| 11 : "INVALID_SPI", |
| 14 : "NO_PROPOSAL_CHOSEN", |
| 17 : "INVALID_KE_PAYLOAD", |
| 24 : "AUTHENTICATION_FAILED", |
| 34 : "SINGLE_PAIR_REQUIRED", |
| 35 : "NO_ADDITIONAL_SAS", |
| 36 : "INTERNAL_ADDRESS_FAILURE", |
| 37 : "FAILED_CP_REQUIRED", |
| 38 : "TS_UNACCEPTABLE", |
| 39 : "INVALID_SELECTORS", |
| 40 : "UNACCEPTABLE_ADDRESSES", |
| 41 : "UNEXPECTED_NAT_DETECTED", |
| 42 : "USE_ASSIGNED_HoA", |
| 43 : "TEMPORARY_FAILURE", |
| 44 : "CHILD_SA_NOT_FOUND", |
| 45 : "INVALID_GROUP_ID", |
| 46 : "AUTHORIZATION_FAILED", |
| 16384 : "INITIAL_CONTACT", |
| 16385 : "SET_WINDOW_SIZE", |
| 16386 : "ADDITIONAL_TS_POSSIBLE", |
| 16387 : "IPCOMP_SUPPORTED", |
| 16388 : "NAT_DETECTION_SOURCE_IP", |
| 16389 : "NAT_DETECTION_DESTINATION_IP", |
| 16390 : "COOKIE", |
| 16391 : "USE_TRANSPORT_MODE", |
| 16392 : "HTTP_CERT_LOOKUP_SUPPORTED", |
| 16393 : "REKEY_SA", |
| 16394 : "ESP_TFC_PADDING_NOT_SUPPORTED", |
| 16395 : "NON_FIRST_FRAGMENTS_ALSO", |
| 16396 : "MOBIKE_SUPPORTED", |
| 16397 : "ADDITIONAL_IP4_ADDRESS", |
| 16398 : "ADDITIONAL_IP6_ADDRESS", |
| 16399 : "NO_ADDITIONAL_ADDRESSES", |
| 16400 : "UPDATE_SA_ADDRESSES", |
| 16401 : "COOKIE2", |
| 16402 : "NO_NATS_ALLOWED", |
| 16403 : "AUTH_LIFETIME", |
| 16404 : "MULTIPLE_AUTH_SUPPORTED", |
| 16405 : "ANOTHER_AUTH_FOLLOWS", |
| 16406 : "REDIRECT_SUPPORTED", |
| 16407 : "REDIRECT", |
| 16408 : "REDIRECTED_FROM", |
| 16409 : "TICKET_LT_OPAQUE", |
| 16410 : "TICKET_REQUEST", |
| 16411 : "TICKET_ACK", |
| 16412 : "TICKET_NACK", |
| 16413 : "TICKET_OPAQUE", |
| 16414 : "LINK_ID", |
| 16415 : "USE_WESP_MODE", |
| 16416 : "ROHC_SUPPORTED", |
| 16417 : "EAP_ONLY_AUTHENTICATION", |
| 16418 : "CHILDLESS_IKEV2_SUPPORTED", |
| 16419 : "QUICK_CRASH_DETECTION", |
| 16420 : "IKEV2_MESSAGE_ID_SYNC_SUPPORTED", |
| 16421 : "IPSEC_REPLAY_COUNTER_SYNC_SUPPORTED", |
| 16422 : "IKEV2_MESSAGE_ID_SYNC", |
| 16423 : "IPSEC_REPLAY_COUNTER_SYNC", |
| 16424 : "SECURE_PASSWORD_METHODS", |
| 16425 : "PSK_PERSIST", |
| 16426 : "PSK_CONFIRM", |
| 16427 : "ERX_SUPPORTED", |
| 16428 : "IFOM_CAPABILITY", |
| 16429 : "SENDER_REQUEST_ID", |
| 16430 : "IKEV2_FRAGMENTATION_SUPPORTED", |
| 16431 : "SIGNATURE_HASH_ALGORITHMS", |
| 16432 : "CLONE_IKE_SA_SUPPORTED", |
| 16433 : "CLONE_IKE_SA" |
| } |
| |
| IKEv2CertificateEncodings = { |
| 1 : "PKCS #7 wrapped X.509 certificate", |
| 2 : "PGP Certificate", |
| 3 : "DNS Signed Key", |
| 4 : "X.509 Certificate - Signature", |
| 6 : "Kerberos Token", |
| 7 : "Certificate Revocation List (CRL)", |
| 8 : "Authority Revocation List (ARL)", |
| 9 : "SPKI Certificate", |
| 10 : "X.509 Certificate - Attribute", |
| 11 : "Raw RSA Key", |
| 12 : "Hash and URL of X.509 certificate", |
| 13 : "Hash and URL of X.509 bundle" |
| } |
| |
| IKEv2TrafficSelectorTypes = { |
| 7 : "TS_IPV4_ADDR_RANGE", |
| 8 : "TS_IPV6_ADDR_RANGE", |
| 9 : "TS_FC_ADDR_RANGE" |
| } |
| |
| IPProtocolIDs = { |
| 0 : "All protocols", |
| 1 : "Internet Control Message Protocol", |
| 2 : "Internet Group Management Protocol", |
| 3 : "Gateway-to-Gateway Protocol", |
| 4 : "IP in IP (encapsulation)", |
| 5 : "Internet Stream Protocol", |
| 6 : "Transmission Control Protocol", |
| 7 : "Core-based trees", |
| 8 : "Exterior Gateway Protocol", |
| 9 : "Interior Gateway Protocol (any private interior gateway (used by Cisco for their IGRP))", |
| 10 : "BBN RCC Monitoring", |
| 11 : "Network Voice Protocol", |
| 12 : "Xerox PUP", |
| 13 : "ARGUS", |
| 14 : "EMCON", |
| 15 : "Cross Net Debugger", |
| 16 : "Chaos", |
| 17 : "User Datagram Protocol", |
| 18 : "Multiplexing", |
| 19 : "DCN Measurement Subsystems", |
| 20 : "Host Monitoring Protocol", |
| 21 : "Packet Radio Measurement", |
| 22 : "XEROX NS IDP", |
| 23 : "Trunk-1", |
| 24 : "Trunk-2", |
| 25 : "Leaf-1", |
| 26 : "Leaf-2", |
| 27 : "Reliable Datagram Protocol", |
| 28 : "Internet Reliable Transaction Protocol", |
| 29 : "ISO Transport Protocol Class 4", |
| 30 : "Bulk Data Transfer Protocol", |
| 31 : "MFE Network Services Protocol", |
| 32 : "MERIT Internodal Protocol", |
| 33 : "Datagram Congestion Control Protocol", |
| 34 : "Third Party Connect Protocol", |
| 35 : "Inter-Domain Policy Routing Protocol", |
| 36 : "Xpress Transport Protocol", |
| 37 : "Datagram Delivery Protocol", |
| 38 : "IDPR Control Message Transport Protocol", |
| 39 : "TP++ Transport Protocol", |
| 40 : "IL Transport Protocol", |
| 41 : "IPv6 Encapsulation", |
| 42 : "Source Demand Routing Protocol", |
| 43 : "Routing Header for IPv6", |
| 44 : "Fragment Header for IPv6", |
| 45 : "Inter-Domain Routing Protocol", |
| 46 : "Resource Reservation Protocol", |
| 47 : "Generic Routing Encapsulation", |
| 48 : "Mobile Host Routing Protocol", |
| 49 : "BNA", |
| 50 : "Encapsulating Security Payload", |
| 51 : "Authentication Header", |
| 52 : "Integrated Net Layer Security Protocol", |
| 53 : "SwIPe", |
| 54 : "NBMA Address Resolution Protocol", |
| 55 : "IP Mobility (Min Encap)", |
| 56 : "Transport Layer Security Protocol (using Kryptonet key management)", |
| 57 : "Simple Key-Management for Internet Protocol", |
| 58 : "ICMP for IPv6", |
| 59 : "No Next Header for IPv6", |
| 60 : "Destination Options for IPv6", |
| 61 : "Any host internal protocol", |
| 62 : "CFTP", |
| 63 : "Any local network", |
| 64 : "SATNET and Backroom EXPAK", |
| 65 : "Kryptolan", |
| 66 : "MIT Remote Virtual Disk Protocol", |
| 67 : "Internet Pluribus Packet Core", |
| 68 : "Any distributed file system", |
| 69 : "SATNET Monitoring", |
| 70 : "VISA Protocol", |
| 71 : "Internet Packet Core Utility", |
| 72 : "Computer Protocol Network Executive", |
| 73 : "Computer Protocol Heart Beat", |
| 74 : "Wang Span Network", |
| 75 : "Packet Video Protocol", |
| 76 : "Backroom SATNET Monitoring", |
| 77 : "SUN ND PROTOCOL-Temporary", |
| 78 : "WIDEBAND Monitoring", |
| 79 : "WIDEBAND EXPAK", |
| 80 : "International Organization for Standardization Internet Protocol", |
| 81 : "Versatile Message Transaction Protocol", |
| 82 : "Secure Versatile Message Transaction Protocol", |
| 83 : "VINES", |
| 84 : "Internet Protocol Traffic Manager", |
| 85 : "NSFNET-IGP", |
| 86 : "Dissimilar Gateway Protocol", |
| 87 : "TCF", |
| 88 : "EIGRP", |
| 89 : "Open Shortest Path First", |
| 90 : "Sprite RPC Protocol", |
| 91 : "Locus Address Resolution Protocol", |
| 92 : "Multicast Transport Protocol", |
| 93 : "AX.25", |
| 94 : "IP-within-IP Encapsulation Protocol", |
| 95 : "Mobile Internetworking Control Protocol", |
| 96 : "Semaphore Communications Sec. Pro", |
| 97 : "Ethernet-within-IP Encapsulation", |
| 98 : "Encapsulation Header", |
| 99 : "Any private encryption scheme", |
| 100 : "GMTP", |
| 101 : "Ipsilon Flow Management Protocol", |
| 102 : "PNNI over IP", |
| 103 : "Protocol Independent Multicast", |
| 104 : "IBM's ARIS (Aggregate Route IP Switching) Protocol", |
| 105 : "SCPS (Space Communications Protocol Standards)", |
| 106 : "QNX", |
| 107 : "Active Networks", |
| 108 : "IP Payload Compression Protocol", |
| 109 : "Sitara Networks Protocol", |
| 110 : "Compaq Peer Protocol", |
| 111 : "IPX in IP", |
| 112 : "Virtual Router Redundancy Protocol, Common Address Redundancy Protocol (not IANA assigned)", |
| 113 : "PGM Reliable Transport Protocol", |
| 114 : "Any 0-hop protocol", |
| 115 : "Layer Two Tunneling Protocol Version 3", |
| 116 : "D-II Data Exchange (DDX)", |
| 117 : "Interactive Agent Transfer Protocol", |
| 118 : "Schedule Transfer Protocol", |
| 119 : "SpectraLink Radio Protocol", |
| 120 : "Universal Transport Interface Protocol", |
| 121 : "Simple Message Protocol", |
| 122 : "Simple Multicast Protocol", |
| 123 : "Performance Transparency Protocol", |
| 124 : "Intermediate System to Intermediate System (IS-IS) Protocol over IPv4", |
| 125 : "Flexible Intra-AS Routing Environment", |
| 126 : "Combat Radio Transport Protocol", |
| 127 : "Combat Radio User Datagram", |
| 128 : "Service-Specific Connection-Oriented Protocol in a Multilink and Connectionless Environment", |
| 129 : "IPLT", |
| 130 : "Secure Packet Shield", |
| 131 : "Private IP Encapsulation within IP", |
| 132 : "Stream Control Transmission Protocol", |
| 133 : "Fibre Channel", |
| 134 : "Reservation Protocol (RSVP) End-to-End Ignore", |
| 135 : "Mobility Extension Header for IPv6", |
| 136 : "Lightweight User Datagram Protocol", |
| 137 : "Multiprotocol Label Switching Encapsulated in IP", |
| 138 : "MANET Protocols", |
| 139 : "Host Identity Protocol", |
| 140 : "Site Multihoming by IPv6 Intermediation", |
| 141 : "Wrapped Encapsulating Security Payload", |
| 142 : "Robust Header Compression", |
| } |
| |
| # the name 'IKEv2TransformTypes' is actually a misnomer (since the table |
| # holds info for all IKEv2 Attribute types, not just transforms, but we'll |
| # keep it for backwards compatibility... for now at least |
| IKEv2TransformTypes = IKEv2AttributeTypes |
| |
| IKEv2TransformNum = {} |
| for n in IKEv2TransformTypes: |
| val = IKEv2TransformTypes[n] |
| tmp = {} |
| for e in val[1]: |
| tmp[val[1][e]] = e |
| IKEv2TransformNum[val[0]] = tmp |
| |
| IKEv2Transforms = {} |
| for n in IKEv2TransformTypes: |
| IKEv2Transforms[IKEv2TransformTypes[n][0]]=n |
| |
| del(n) |
| del(e) |
| del(tmp) |
| del(val) |
| |
| # Note: Transform and Proposal can only be used inside the SA payload |
| IKEv2_payload_type = ["None", "", "Proposal", "Transform"] |
| |
| IKEv2_payload_type.extend([""] * 29) |
| IKEv2_payload_type.extend(["SA","KE","IDi","IDr", "CERT","CERTREQ","AUTH","Nonce","Notify","Delete", |
| "VendorID","TSi","TSr","Encrypted","CP","EAP", "", "", "", "", "Encrypted Fragment"]) |
| |
| IKEv2_exchange_type = [""] * 34 |
| IKEv2_exchange_type.extend(["IKE_SA_INIT","IKE_AUTH","CREATE_CHILD_SA", |
| "INFORMATIONAL", "IKE_SESSION_RESUME"]) |
| |
| |
| class IKEv2_class(Packet): |
| def guess_payload_class(self, payload): |
| np = self.next_payload |
| logging.debug("For IKEv2_class np=%d" % np) |
| if np == 0: |
| return conf.raw_layer |
| elif np < len(IKEv2_payload_type): |
| pt = IKEv2_payload_type[np] |
| logging.debug(globals().get("IKEv2_payload_%s" % pt, IKEv2_payload)) |
| return globals().get("IKEv2_payload_%s" % pt, IKEv2_payload) |
| else: |
| return IKEv2_payload |
| |
| |
| class IKEv2(IKEv2_class): # rfc4306 |
| name = "IKEv2" |
| fields_desc = [ |
| StrFixedLenField("init_SPI","",8), |
| StrFixedLenField("resp_SPI","",8), |
| ByteEnumField("next_payload",0,IKEv2_payload_type), |
| XByteField("version", 0x20), |
| ByteEnumField("exch_type",0,IKEv2_exchange_type), |
| FlagsField("flags",0, 8, ["res0","res1","res2","Initiator","Version","Response","res6","res7"]), |
| IntField("id",0), |
| IntField("length",None) # Length of total message: packets + all payloads |
| ] |
| |
| def guess_payload_class(self, payload): |
| if self.flags & 1: |
| return conf.raw_layer |
| return IKEv2_class.guess_payload_class(self, payload) |
| |
| def answers(self, other): |
| if isinstance(other, IKEv2): |
| if other.init_SPI == self.init_SPI: |
| return 1 |
| return 0 |
| def post_build(self, p, pay): |
| p += pay |
| if self.length is None: |
| p = p[:24]+struct.pack("!I",len(p))+p[28:] |
| return p |
| |
| |
| class IKEv2_Key_Length_Attribute(IntField): |
| # We only support the fixed-length Key Length attribute (the only one currently defined) |
| def __init__(self, name): |
| IntField.__init__(self, name, 0x800E0000) |
| |
| def i2h(self, pkt, x): |
| return IntField.i2h(self, pkt, x & 0xFFFF) |
| |
| def h2i(self, pkt, x): |
| return IntField.h2i(self, pkt, x if x !=None else 0 | 0x800E0000) |
| |
| class IKEv2_payload_Transform(IKEv2_class): |
| name = "IKE Transform" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,{0:"last", 3:"Transform"}), |
| ByteField("res",0), |
| ShortField("length",8), |
| ByteEnumField("transform_type",None,IKEv2Transforms), |
| ByteField("res2",0), |
| MultiEnumField("transform_id",None,IKEv2TransformNum,depends_on=lambda pkt:pkt.transform_type,fmt="H"), |
| ConditionalField(IKEv2_Key_Length_Attribute("key_length"), lambda pkt: pkt.length > 8), |
| ] |
| |
| class IKEv2_payload_Proposal(IKEv2_class): |
| name = "IKEv2 Proposal" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,{0:"last", 2:"Proposal"}), |
| ByteField("res",0), |
| FieldLenField("length",None,"trans","H", adjust=lambda pkt,x:x+8+(pkt.SPIsize if pkt.SPIsize else 0)), |
| ByteField("proposal",1), |
| ByteEnumField("proto",1,{1:"IKEv2", 2:"AH", 3:"ESP"}), |
| FieldLenField("SPIsize",None,"SPI","B"), |
| ByteField("trans_nb",None), |
| StrLenField("SPI","",length_from=lambda pkt:pkt.SPIsize), |
| PacketLenField("trans",conf.raw_layer(),IKEv2_payload_Transform,length_from=lambda pkt:pkt.length-8-pkt.SPIsize), |
| ] |
| |
| |
| class IKEv2_payload(IKEv2_class): |
| name = "IKEv2 Payload" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| FlagsField("flags",0, 8, ["critical","res1","res2","res3","res4","res5","res6","res7"]), |
| FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4), |
| StrLenField("load","",length_from=lambda x:x.length-4), |
| ] |
| |
| |
| class IKEv2_payload_AUTH(IKEv2_class): |
| name = "IKEv2 Authentication" |
| overload_fields = { IKEv2: { "next_payload":39 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+8), |
| ByteEnumField("auth_type",None,IKEv2AuthenticationTypes), |
| X3BytesField("res2",0), |
| StrLenField("load","",length_from=lambda x:x.length-8), |
| ] |
| |
| class IKEv2_payload_VendorID(IKEv2_class): |
| name = "IKEv2 Vendor ID" |
| overload_fields = { IKEv2: { "next_payload":43 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"vendorID","H", adjust=lambda pkt,x:x+4), |
| StrLenField("vendorID","",length_from=lambda x:x.length-4), |
| ] |
| |
| class TrafficSelector(Packet): |
| @classmethod |
| def dispatch_hook(cls, _pkt=None, *args, **kargs): |
| if _pkt and len(_pkt) >= 16: |
| ts_type = struct.unpack("!B", _pkt[0:1])[0] |
| if ts_type == 7: |
| return IPv4TrafficSelector |
| elif ts_type == 8: |
| return IPv6TrafficSelector |
| elif ts_type == 9: |
| return EncryptedTrafficSelector |
| else: |
| return RawTrafficSelector |
| return IPv4TrafficSelector |
| |
| class IPv4TrafficSelector(TrafficSelector): |
| name = "IKEv2 IPv4 Traffic Selector" |
| fields_desc = [ |
| ByteEnumField("TS_type",7,IKEv2TrafficSelectorTypes), |
| ByteEnumField("IP_protocol_ID",None,IPProtocolIDs), |
| ShortField("length",16), |
| ShortField("start_port",0), |
| ShortField("end_port",65535), |
| IPField("starting_address_v4","192.168.0.1"), |
| IPField("ending_address_v4","192.168.0.255"), |
| ] |
| |
| class IPv6TrafficSelector(TrafficSelector): |
| name = "IKEv2 IPv6 Traffic Selector" |
| fields_desc = [ |
| ByteEnumField("TS_type",8,IKEv2TrafficSelectorTypes), |
| ByteEnumField("IP_protocol_ID",None,IPProtocolIDs), |
| ShortField("length",20), |
| ShortField("start_port",0), |
| ShortField("end_port",65535), |
| IP6Field("starting_address_v6","2001::"), |
| IP6Field("ending_address_v6","2001::"), |
| ] |
| |
| class EncryptedTrafficSelector(TrafficSelector): |
| name = "IKEv2 Encrypted Traffic Selector" |
| fields_desc = [ |
| ByteEnumField("TS_type",9,IKEv2TrafficSelectorTypes), |
| ByteEnumField("IP_protocol_ID",None,IPProtocolIDs), |
| ShortField("length",16), |
| ByteField("res",0), |
| X3BytesField("starting_address_FC",0), |
| ByteField("res2",0), |
| X3BytesField("ending_address_FC",0), |
| ByteField("starting_R_CTL",0), |
| ByteField("ending_R_CTL",0), |
| ByteField("starting_type",0), |
| ByteField("ending_type",0), |
| ] |
| |
| class RawTrafficSelector(TrafficSelector): |
| name = "IKEv2 Encrypted Traffic Selector" |
| fields_desc = [ |
| ByteEnumField("TS_type",None,IKEv2TrafficSelectorTypes), |
| ByteEnumField("IP_protocol_ID",None,IPProtocolIDs), |
| FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4), |
| PacketField("load", "", Raw) |
| ] |
| |
| class IKEv2_payload_TSi(IKEv2_class): |
| name = "IKEv2 Traffic Selector - Initiator" |
| overload_fields = { IKEv2: { "next_payload":44 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"traffic_selector","H", adjust=lambda pkt,x:x+8), |
| ByteField("number_of_TSs",0), |
| X3BytesField("res2",0), |
| PacketListField("traffic_selector",None,TrafficSelector,length_from=lambda x:x.length-8,count_from=lambda x:x.number_of_TSs), |
| ] |
| |
| class IKEv2_payload_TSr(IKEv2_class): |
| name = "IKEv2 Traffic Selector - Responder" |
| overload_fields = { IKEv2: { "next_payload":45 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"traffic_selector","H", adjust=lambda pkt,x:x+8), |
| ByteField("number_of_TSs",0), |
| X3BytesField("res2",0), |
| PacketListField("traffic_selector",None,TrafficSelector,length_from=lambda x:x.length-8,count_from=lambda x:x.number_of_TSs), |
| ] |
| |
| class IKEv2_payload_Delete(IKEv2_class): |
| name = "IKEv2 Vendor ID" |
| overload_fields = { IKEv2: { "next_payload":42 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"vendorID","H", adjust=lambda pkt,x:x+4), |
| StrLenField("vendorID","",length_from=lambda x:x.length-4), |
| ] |
| |
| class IKEv2_payload_SA(IKEv2_class): |
| name = "IKEv2 SA" |
| overload_fields = { IKEv2: { "next_payload":33 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"prop","H", adjust=lambda pkt,x:x+4), |
| PacketLenField("prop",conf.raw_layer(),IKEv2_payload_Proposal,length_from=lambda x:x.length-4), |
| ] |
| |
| class IKEv2_payload_Nonce(IKEv2_class): |
| name = "IKEv2 Nonce" |
| overload_fields = { IKEv2: { "next_payload":40 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4), |
| StrLenField("load","",length_from=lambda x:x.length-4), |
| ] |
| |
| class IKEv2_payload_Notify(IKEv2_class): |
| name = "IKEv2 Notify" |
| overload_fields = { IKEv2: { "next_payload":41 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+8), |
| ByteEnumField("proto",None,{0:"Reserved",1:"IKE",2:"AH", 3:"ESP"}), |
| FieldLenField("SPIsize",None,"SPI","B"), |
| ShortEnumField("type",0,IKEv2NotifyMessageTypes), |
| StrLenField("SPI","",length_from=lambda x:x.SPIsize), |
| StrLenField("load","",length_from=lambda x:x.length-8), |
| ] |
| |
| class IKEv2_payload_KE(IKEv2_class): |
| name = "IKEv2 Key Exchange" |
| overload_fields = { IKEv2: { "next_payload":34 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+8), |
| ShortEnumField("group", 0, IKEv2TransformTypes['GroupDesc'][1]), |
| ShortField("res2", 0), |
| StrLenField("load","",length_from=lambda x:x.length-8), |
| ] |
| |
| class IKEv2_payload_IDi(IKEv2_class): |
| name = "IKEv2 Identification - Initiator" |
| overload_fields = { IKEv2: { "next_payload":35 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+8), |
| ByteEnumField("IDtype",1,{1:"IPv4_addr", 2:"FQDN", 3:"Email_addr", 5:"IPv6_addr", 11:"Key"}), |
| ByteEnumField("ProtoID",0,{0:"Unused"}), |
| ShortEnumField("Port",0,{0:"Unused"}), |
| # IPField("IdentData","127.0.0.1"), |
| StrLenField("load","",length_from=lambda x:x.length-8), |
| ] |
| |
| class IKEv2_payload_IDr(IKEv2_class): |
| name = "IKEv2 Identification - Responder" |
| overload_fields = { IKEv2: { "next_payload":36 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+8), |
| ByteEnumField("IDtype",1,{1:"IPv4_addr", 2:"FQDN", 3:"Email_addr", 5:"IPv6_addr", 11:"Key"}), |
| ByteEnumField("ProtoID",0,{0:"Unused"}), |
| ShortEnumField("Port",0,{0:"Unused"}), |
| # IPField("IdentData","127.0.0.1"), |
| StrLenField("load","",length_from=lambda x:x.length-8), |
| ] |
| |
| class IKEv2_payload_Encrypted(IKEv2_class): |
| name = "IKEv2 Encrypted and Authenticated" |
| overload_fields = { IKEv2: { "next_payload":46 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+4), |
| StrLenField("load","",length_from=lambda x:x.length-4), |
| ] |
| |
| class IKEv2_payload_Encrypted_Fragment(IKEv2_class): |
| name = "IKEv2 Encrypted Fragment" |
| overload_fields = {IKEv2: {"next_payload": 53}} |
| fields_desc = [ |
| ByteEnumField("next_payload", None, IKEv2_payload_type), |
| ByteField("res", 0), |
| FieldLenField("length", None, "load", "H", adjust=lambda pkt, x: x+8), |
| ShortField("frag_number", 1), |
| ShortField("frag_total", 1), |
| StrLenField("load", "", length_from=lambda x: x.length-8), |
| ] |
| |
| class IKEv2_payload_CERTREQ(IKEv2_class): |
| name = "IKEv2 Certificate Request" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"cert_data","H",adjust=lambda pkt,x:x+5), |
| ByteEnumField("cert_type",0,IKEv2CertificateEncodings), |
| StrLenField("cert_data","",length_from=lambda x:x.length-5), |
| ] |
| |
| class IKEv2_payload_CERT(IKEv2_class): |
| @classmethod |
| def dispatch_hook(cls, _pkt=None, *args, **kargs): |
| if _pkt and len(_pkt) >= 16: |
| ts_type = struct.unpack("!B", _pkt[4:5])[0] |
| if ts_type == 4: |
| return IKEv2_payload_CERT_CRT |
| elif ts_type == 7: |
| return IKEv2_payload_CERT_CRL |
| else: |
| return IKEv2_payload_CERT_STR |
| return IKEv2_payload_CERT_STR |
| |
| class IKEv2_payload_CERT_CRT(IKEv2_payload_CERT): |
| name = "IKEv2 Certificate" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"x509Cert","H",adjust=lambda pkt,x: x+len(pkt.x509Cert)+5), |
| ByteEnumField("cert_type",4,IKEv2CertificateEncodings), |
| PacketLenField("x509Cert", X509_Cert(''), X509_Cert, length_from=lambda x:x.length-5), |
| ] |
| |
| class IKEv2_payload_CERT_CRL(IKEv2_payload_CERT): |
| name = "IKEv2 Certificate" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"x509CRL","H",adjust=lambda pkt,x: x+len(pkt.x509CRL)+5), |
| ByteEnumField("cert_type",7,IKEv2CertificateEncodings), |
| PacketLenField("x509CRL", X509_CRL(''), X509_CRL, length_from=lambda x:x.length-5), |
| ] |
| |
| class IKEv2_payload_CERT_STR(IKEv2_payload_CERT): |
| name = "IKEv2 Certificate" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,IKEv2_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"cert_data","H",adjust=lambda pkt,x: x+5), |
| ByteEnumField("cert_type",0,IKEv2CertificateEncodings), |
| StrLenField("cert_data","",length_from=lambda x:x.length-5), |
| ] |
| |
| IKEv2_payload_type_overload = {} |
| for i, payloadname in enumerate(IKEv2_payload_type): |
| name = "IKEv2_payload_%s" % payloadname |
| if name in globals(): |
| IKEv2_payload_type_overload[globals()[name]] = {"next_payload": i} |
| |
| del i, payloadname, name |
| IKEv2_class._overload_fields = IKEv2_payload_type_overload.copy() |
| |
| split_layers(UDP, ISAKMP, sport=500) |
| split_layers(UDP, ISAKMP, dport=500) |
| |
| bind_layers( UDP, IKEv2, dport=500, sport=500) # TODO: distinguish IKEv1/IKEv2 |
| bind_layers( UDP, IKEv2, dport=4500, sport=4500) |
| |
| def ikev2scan(ip, **kwargs): |
| """Send a IKEv2 SA to an IP and wait for answers.""" |
| return sr(IP(dst=ip)/UDP()/IKEv2(init_SPI=RandString(8), |
| exch_type=34)/IKEv2_payload_SA(prop=IKEv2_payload_Proposal()), **kwargs) |