How to Implement a New Scapy Layer: Example HSRP Protocol v2
The Scapy library provides powerful capabilities for packet manipulation. However, sometimes, specific protocols or packet types might not be natively supported. In such cases, you can extend Scapy by implementing custom layers. In this article, we’ll walk through the steps of adding support for the Hot Standby Router Protocol (HSRP) version 2 as an example.
Introducing the HSRP Protocol
Hot Standby Router Protocol (HSRP) is a Cisco proprietary redundancy protocol. It allows automatic failover at the first-hop IP router, ensuring network uptime and resilience. Especially crucial in data center or large enterprise network environments, HSRP prevents a single point of failure for the network gateway.
The Challenge with HSRP v2 Packets
A while ago a colleague had trouble analyzing an HSRP v2 packet with Wireshark. The pcap file revealed that this wasn’t a standard HSRP packet with clear text authentication but had additional data. This discovery led to a dive into Wireshark’s source code and the HSRP specification.
HSRP MD5 Authentication
In order to enhances security, safeguarding against HSRP spoofing or hijacking attempts, the HSRP v2 protocol add MD5 authentication with HSRP .
MD5 authentication, when compared to plain text, offers superior security. It allows each HSRP group member to use a secret key to produce a keyed MD5 hash of the packet. If an incoming packet’s generated hash doesn’t align with the packet’s hash, it’s disregarded.
HSRP packets are typically discarded under the following circumstances:
- Mismatched authentication methods between the router and incoming packets.
- Discrepancies between the MD5 digests on the router and the incoming packet.
- Differing text authentication strings on the router and the incoming packet.
Ensuring proper HSRP authentication is a good practice, as it protects against malicious HSRP hello packets, which can trigger a denial-of-service attack. To understand the significance further, refer to Hijacking HSRP - Packet Life
Implementing HSRP v2 in Scapy
Given the peculiarities of the packet, I decided to craft a Scapy dissector based on the HSRPv2 specification. The detailed Scapy dissector code is provided below:
#############################################################################
## ##
## hsrp.py --- HSRP protocol support for Scapy ##
## ##
## Copyright (C) 2010 Mathieu RENARD mathieu.renard(at)gmail.com ##
## ##
## This program is free software; you can redistribute it and/or modify it ##
## under the terms of the GNU General Public License version 2 as ##
## published by the Free Software Foundation; version 2. ##
## ##
## This program 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. ##
## ##
#############################################################################
## HSRP Version 1
## Ref. RFC 2281
## HSRP Version 2
## Ref. http://www.smartnetworks.jp/2006/02/hsrp_8_hsrp_version_2.html
##
## $Log: hsrp.py,v $
## Revision 0.2 2011/05/01 15:23:34 mrenard
## Cleanup code
##
##
from scapy.fields import *
from scapy.packet import *
from scapy.layers.inet import UDP
class HSRP(Packet):
name = "HSRP"
fields_desc = [
ByteField("version", 0),
ByteEnumField("opcode", 0, { 0:"Hello", 1:"Coup", 2:"Resign"}),
ByteEnumField("state", 16, { 0:"Initial",1:"Learn",2:"Listen",4:"Speak",8:"Standby",16:"Active"}),
ByteField("hellotime", 3),
ByteField("holdtime", 10),
ByteField("priority", 120),
ByteField("group", 1),
ByteField("reserved", 0),
StrFixedLenField("auth","cisco"+"\00"*3,8),
IPField("virtualIP","192.168.1.1")]
def guess_payload_class(self, payload):
if self.underlayer.len > 28:
return HSRPmd5
else:
return Packet.guess_payload_class(self, payload)
class HSRPmd5(Packet):
name = "HSRP MD5 Authentication"
fields_desc = [
ByteEnumField("type", 4, { 4:"MD5 authentication"}),
ByteField("len", None),
ByteEnumField("algo", 0, { 1:"MD5"}),
ByteField("padding", 0x00),
XShortField("flags", 0x00),
IPField("sourceip",None),
XIntField("keyid",0x00),
StrFixedLenField("authdigest","\00"*16,16) ]
def post_build(self, p, pay):
if self.len is None and pay:
l = len(pay)
p = p[:1] + hex(l)[30:]+ p[30:]
return p
bind_layers( UDP, HSRP, dport=1985, sport=1985)
Features Used in the Script:
Scapy Modules and Fields
The script begins by importing necessary Scapy modules, which provide a suite of tools and predefined field types for crafting packets.
HSRP Packet Class
The HSRP
class defines the primary structure of an HSRP packet. Here, various fields describe the HSRP version, operation codes, states, and other HSRP-specific attributes.
Payload Determination
Within the HSRP
class, the guess_payload_class
function determines if the packet contains an MD5 authentication payload or a different type.
HSRP MD5 Packet Class
The HSRPmd5
class describes the structure of an HSRP packet with MD5 authentication. This includes fields specific to MD5 authentication like algorithm type, key ID, and the authentication digest.
Length Setting
The post_build
function inside the HSRPmd5
class ensures the correct setting of the length field after the packet is created.
Layer Binding
The bind_layers
function at the end associates the HSRP protocol with the UDP protocol on port 1985, which is the standard port for HSRP.
example :
from scapy.all import *
interact()
h=rdpcap("hsrpmd5.pcap")
>>> h[0].show2()
###[ Ethernet ]###
dst= 01:00:5e:00:00:02
src= 00:00:0c:03:2c:3b
type= 0x800
###[ IP ]###
version= 4L
ihl= 5L
tos= 0xc0
len= 78
id= 0
flags=
frag= 0L
ttl= 1
proto= udp
chksum= 0xdad6
src= 192.1.223.252
dst= 224.0.0.2
\options\
###[ UDP ]###
sport= 1985
dport= 1985
len= 58
chksum= 0xe334
###[ HSRP ]###
version= 0
opcode= Hello
state= Active
hellotime= 0
holdtime= 0
priority= 120
group= 15
reserved= 0
auth= ''
virtualIP= 192.1.223.254
###[ HSRP MD5 Authentication ]###
type= MD5 authentication
len= 28
algo= MD5
padding= 0
flags= 0x0
sourceIP= 192.1.223.252
keyid= 0x0
md5auth= '\x8f\xa2\x52\x4e\x3f\x34\x78\x86\x32\xa6\x8c\xd6\x44\x96\x78\x96'
Conclusion
Extending Scapy to support additional protocols or versions, like HSRP v2, can be invaluable for network analysis and research. The process might seem intricate, but with a deep understanding of the protocol’s specification and Scapy’s structure, it’s entirely feasible.
References
With this structure, the article presents a more clear and comprehensive guide on implementing a new Scapy layer, using HSRP v2 as a detailed example.