Linux kernel handling of IPv6 temporary addresses – CVE-2013-0343

I reported this bug on November 2012 but as of February 2013 it still hasn’t been fixed.

My initial report on oss-security and kernel netdev mailing lists reported it as an ‘information disclosure’ problem but then I found out that the issue is more severe and it can lead to the complete corruption of Linux kernel’s IPv6 stack until reboot. My second report wasn’t public, I thought it would be better not to make any public disclosure until the kernel people had enough time to respond, and was only sent to a number of kernel developers but I’m making it public now since the CVE is already out.

If someone wants to read all the publicly exchanged emails the best resource is probably this: http://marc.info/?t=135291265200001&r=1&w=2

Here’s the initial description of the problem:

Due to the way the Linux kernel handles the creation of IPv6 temporary addresses a malicious LAN user can remotely disable them altogether which may lead to privacy violations and information disclosure.

By default the Linux kernel uses the ‘ipv6.max_addresses’ option to specify how many IPv6 addresses an interface may have. The ‘ipv6.regen_max_retry’ option specifies how many times the kernel will try to create a new address.

Currently, in net/ipv6/addrconf.c,lines 898-910, there is no distinction between the events of reaching max_addresses for an interface and failing to generate a new address. Upon reaching any of the above conditions the following error is emitted by the kernel times ‘regen_max_retry’ (default value 3):

[183.793393] ipv6_create_tempaddr(): retry temporary address regeneration
[183.793405] ipv6_create_tempaddr(): retry temporary address regeneration
[183.793411] ipv6_create_tempaddr(): retry temporary address regeneration

After ‘regen_max_retry’ is reached the kernel completely disables temporary address generation for that interface.

[183.793413] ipv6_create_tempaddr(): regeneration time exceeded - disabled temporary address support

RFC4941 3.3.7 specifies that disabling temp_addresses MUST happen upon failure to create non-unique addresses which is not the above case. Addresses would have been created if the kernel had a higher
‘ipv6.max_addresses’ limit.

A malicious LAN user can send a limited amount of RA prefixes and thus disable IPv6 temporary address creation for any Linux host. Recent distributions which enable the IPv6 Privacy extensions by default, like Ubuntu 12.04 and 12.10, are vulnerable to such attacks.

Due to the kernel’s default values for valid (604800) and preferred (86400) lifetimes, this scenario may even occur under normal usage when a Router sends both a public and a ULA prefix, which is not an uncommon
scenario for IPv6. 16 addresses are not enough with the current default timers when more than 1 prefix is advertised.

The kernel should at least differentiate between the two cases of reaching max_addresses and being unable to create new addresses, due to DAD conflicts for example.

And here’s the second, more severe report about the corruption of the IPv6 stack:

I had previously informed this list about the issue of the linux kernel losing IPv6 privacy extensions by a local LAN attacker. Recently I’ve found that there’s actually another, more serious in my
opinion, issue that follows the previous one. If the user tries to disconnect/reconnect the network device/connection for whatever reason (e.g. thinking he might gain back privacy extensions), then the device gets IPs from SLAAC that have the “tentative” flag and never loses that. That means that IPv6 functionality for that device is from then on completely lost. I haven’t been able to bring back the kernel to a working IPv6 state without a reboot.

This is definitely a DoS situation and it needs fixing.

Here are the steps to reproduce:


== Step 1. Boot Ubuntu 12.10 (kernel 3.5.0-17-generic) ==
ubuntu@ubuntu:~$ ip a ls dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:8b:99:5d brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.96/24 brd 192.168.1.255 scope global eth0
    inet6 2001:db8:f00:f00:ad1f:9166:93d4:fd6d/64 scope global temporary dynamic 
       valid_lft 86379sec preferred_lft 3579sec
    inet6 2001:db8:f00:f00:5054:ff:fe8b:995d/64 scope global dynamic 
       valid_lft 86379sec preferred_lft 3579sec
    inet6 fdbb:aaaa:bbbb:cccc:ad1f:9166:93d4:fd6d/64 scope global temporary dynamic 
       valid_lft 86379sec preferred_lft 3579sec
    inet6 fdbb:aaaa:bbbb:cccc:5054:ff:fe8b:995d/64 scope global dynamic 
       valid_lft 86379sec preferred_lft 3579sec
    inet6 fe80::5054:ff:fe8b:995d/64 scope link 
       valid_lft forever preferred_lft forever

ubuntu@ubuntu:~$ sysctl -a | grep use_tempaddr
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
net.ipv6.conf.eth0.use_tempaddr = 2
net.ipv6.conf.lo.use_tempaddr = 2

ubuntu@ubuntu:~$ nmcli con status
NAME                      UUID                                   DEVICES    DEFAULT  VPN   MASTER-PATH
Wired connection 1        923e6729-74a7-4389-9dbd-43ed7db3d1b8   eth0       yes      no    --
ubuntu@ubuntu:~$ nmcli dev status
DEVICE     TYPE              STATE
eth0       802-3-ethernet    connected

//ping6 2a00:1450:4002:800::100e  while in another terminal: tcpdump -ni eth0 ip6

ubuntu@ubuntu:~$ ping6 2a00:1450:4002:800::100e -c1
PING 2a00:1450:4002:800::100e(2a00:1450:4002:800::100e) 56 data bytes
64 bytes from 2a00:1450:4002:800::100e: icmp_seq=1 ttl=53 time=70.9 ms

--- 2a00:1450:4002:800::100e ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 70.994/70.994/70.994/0.000 ms

# tcpdump -ni eth0 host 2a00:1450:4002:800::100e
17:57:37.784658 IP6 2001:db8:f00:f00:ad1f:9166:93d4:fd6d > 2a00:1450:4002:800::100e: ICMP6, echo request, seq 1, length 64
17:57:37.855257 IP6 2a00:1450:4002:800::100e > 2001:db8:f00:f00:ad1f:9166:93d4:fd6d: ICMP6, echo reply, seq 1, length 64

== Step 2. flood RAs on the LAN ==

$ dmesg | tail
[ 1093.642053] IPv6: ipv6_create_tempaddr: retry temporary address regeneration
[ 1093.642062] IPv6: ipv6_create_tempaddr: retry temporary address regeneration
[ 1093.642065] IPv6: ipv6_create_tempaddr: retry temporary address regeneration
[ 1093.642067] IPv6: ipv6_create_tempaddr: regeneration time exceeded - disabled temporary address support

ubuntu@ubuntu:~$ sysctl -a | grep use_tempaddr
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
net.ipv6.conf.eth0.use_tempaddr = -1
net.ipv6.conf.lo.use_tempaddr = 2

//ping6 2a00:1450:4002:800::100e  while in another terminal: tcpdump -ni eth0 ip6

ubuntu@ubuntu:~$ ping6 2a00:1450:4002:800::100e -c1
PING 2a00:1450:4002:800::100e(2a00:1450:4002:800::100e) 56 data bytes
64 bytes from 2a00:1450:4002:800::100e: icmp_seq=1 ttl=53 time=77.5 ms

--- 2a00:1450:4002:800::100e ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 77.568/77.568/77.568/0.000 ms

# tcpdump -ni eth0 host 2a00:1450:4002:800::100e
17:59:38.204173 IP6 2001:db8:f00:f00:5054:ff:fe8b:995d > 2a00:1450:4002:800::100e: ICMP6, echo request, seq 1, length 64
17:59:38.281437 IP6 2a00:1450:4002:800::100e > 2001:db8:f00:f00:5054:ff:fe8b:995d: ICMP6, echo reply, seq 1, length 64

//notice the change of IPv6 address to the one not using privacy extensions even after the flooding has finished long ago.

== Step 3. Disconnect/Reconnect connection  ==
// restoring net.ipv6.conf.eth0.use_tempaddr to value '2' makes no difference at all for the rest of the process

# nmcli dev disconnect iface eth0
# nmcli con up uuid 923e6729-74a7-4389-9dbd-43ed7db3d1b8

ubuntu@ubuntu:~$ ip a ls dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:8b:99:5d brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.96/24 brd 192.168.1.255 scope global eth0
    inet6 2001:db8:f00:f00:5054:ff:fe8b:995d/64 scope global tentative dynamic 
       valid_lft 86400sec preferred_lft 3600sec
    inet6 fdbb:aaaa:bbbb:cccc:5054:ff:fe8b:995d/64 scope global tentative dynamic 
       valid_lft 86400sec preferred_lft 3600sec
    inet6 fe80::5054:ff:fe8b:995d/64 scope link tentative 
       valid_lft forever preferred_lft forever

//Notice the "tentative" flag of the IPs on the device

//ping6 2a00:1450:4002:800::100e  while in another terminal: tcpdump -ni eth0 ip6

ubuntu@ubuntu:~$ ping6 2a00:1450:4002:800::100e -c1
PING 2a00:1450:4002:800::100e(2a00:1450:4002:800::100e) 56 data bytes
^C
--- 2a00:1450:4002:800::100e ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

# tcpdump -ni eth0 host 2a00:1450:4002:800::100e
18:01:45.264194 IP6 ::1 > 2a00:1450:4002:800::100e: ICMP6, echo request, seq 1, length 64

Summary:
Before flooding it uses IP: 2001:db8:f00:f00:ad1f:9166:93d4:fd6d
After flooding it uses IP: 2001:db8:f00:f00:5054:ff:fe8b:995d –> it has lost privacy extensions
After disconnect/reconnect it tries to use IP: ::1 –> it has lost IPv6 connectivity

The problem currently affects all Linux kernels (including the latest 3.8), that have IPv6 Privacy Extensions enabled. The only distribution that has IPv6 Privacy Extensions enabled by default is Ubuntu starting from version 12.04. So Ubuntu 12.04 and 12.10 are currently vulnerable to this attack and can have their IPv6 stack corrupted/disabled by a remote attacker in an untrusted network.

Kernel developers and people from RedHat Security Team are trying to fix the issue which in my opinion involves changing parts of the logic of IPv6 addressing algorithms in the Linux kernel.

No mitigation currently exists apart from disabling IPv6 Privacy Extensions.

You can play with this bug using flood_router26 tool from THC-IPv6 toolkit v2.1.
Usage: # ./flood_router26 -A iface

P.S. I can’t tell if the stack corruption could also lead to other kernel problems, that would probably need some professional security researchers to look into it.

AthCon 2012 – Are you ready for IPv6 insecurities ?

My presentation for AthCon 2012 is now available online: Are you ready for IPv6 insecurities ?

End Users IPv6 Training by Hellenic IPv6 Task force

Today the Hellenic IPv6 Task force organized a training day for end users. Most of the presentations were entry level, since they were targeting end users, but most of them were very interesting. I was happily surprised by Cosmote‘s presentation on their mobile IPv6 tests using native IPv6 and NAT64.

My presentation was about what is architecturally different inside an IPv6-enabled CPE. I tried to present topics like WAN addressing, LAN addressing, auto-configuration (SLAAC), DHCPv6 as well as some migration/tunneling techniques. There were lots of comments, a lot of interesting questions and I was happy to “provoke” an interesting exchange of ideas/perceptions on IPv4 NAT mainly due to the previous to last slide of my presentation 🙂

At the end of the event there was a draw and people got 4 IPv6-enabled CPEs produced by the company I work for (Gennet), 4 DSL accounts by OTE ready to use for OTE’s pilot IPv6 program and 5 IPv6 related books generously provided by Cisco.

My presentation: Defining an IPv6-ready CPE
All presentations: IPv6 End Users Training Day (2011)

On Friday(s) 27/05 and 03/06 I’ll be giving two more IPv6 presentations at University of Pireus: [oss-unipi] Event #26: Introduction to TCP/IP and IPv6. The first one will be introductory and the second one will be more technical and maybe workshop based. In the same day(s) there will also be in-depth technical IPv4 presentations by Apollon Oikonomopoulos. Be there if you like technical presentations!

IPv6 workshop at Fosscomm 2011

This weekend, 7-8 May 2011, I’ll be doing a workshop about “IPv6 usage on Linux” at Fosscomm 2011 conference. Fosscomm is the biggest Greek Open Source conference with lots of interesting presentations, workshops and events. In the spirit of enabling IPv6 wherever possible, I am very happy to have managed to enable IPv6 connectivity for the website of Fosscomm this year!

During the workshop I will try to show the necessary tools to use, debug network problems and configure various services for IPv6. My goal is to explain to participants the abolishment of NAT, introduce the concepts of SLAAC and DHCPv6 and show them how to configure their networks to effectively use IPv6. If there’s enough time some issues related to IPv6 security will also be discussed. Target audience is people who are not afraid of the command line, have basic networking skills and are eager to learn things regarding IPv6!

Unfortunately it was impossible to have IPv6 upstream connectivity at the LAB, so participants will be testing everything on an IPv6 enabled remote infrastructure. Due to the limited number of LAB computers and Virtual Machines available, only 35, there is a registration form for participants to fill in. Please take the time to fill in the form any specific topics that you would like the workshop to pay attention to.

The workshop is taking place on Saturday 07/05/2011 and it will start _exactly_ at 10:45 in order to take full advantage of the time given to us by Fosscomm’s organizers.

Workshop is supported by the Greek IPv6 Taskforce and there miiiight be IPv6-related material distributed to the participants.

Please don’t forget to fill in the registration form!!!

Assigning IPv6 addresses from Cisco BRAS

A sample config for PPPoE clients connecting to a Cisco BRAS. The following example uses Stateless Address Autoconfiguration (SLAAC) to provide an IPv6 /64 subnet to clients on their PPP interface and DHCPv6 for Prefix Delegation in order to provide to a /56 subnet to them.

ipv6 unicast-routing
ipv6 general-prefix ISP-PREFIX 2001:DB8:BBBB::/48
ipv6 cef
ipv6 dhcp pool v6dhcppool
prefix-delegation pool v6prefixpool2
dns-server 2001:DB8:DDDD::1
dns-server 2001:DB8:EEEE::1
sip address 2001:DB8:CCCC::1
sip domain-name ipv6-test.example.com
Interface FastEthernet0/0.100
[ snip ]
ipv6 address ISP-PREFIX ::1:0:0:0:1/64
ipv6 enable
ipv6 mtu 1492
ipv6 nd reachable-time 30
ipv6 nd ra-interval 10
ipv6 nd ra-lifetime 3600
ipv6 nd prefix 2001:DB8:AAAA:2222::/64 86400 3600 off-link
ipv6 nd other-config-flag
ipv6 dhcp server v6dhcppool
!
Interface Virtual-Template1
[ snip ]
ipv6 unnumbered FastEthernet0/0.100
ipv6 enable
ipv6 mtu 1480
ipv6 nd reachable-time 30
ipv6 nd ra-interval 10
ipv6 nd ra-lifetime 3600
ipv6 nd prefix default infinite infinite off-link
ipv6 nd prefix 2001:DB8:BBBB:CCCC::/64 86400 3600 off-link
no ipv6 nd suppress-ra
ipv6 nd other-config-flag
ipv6 dhcp server v6dhcppool
peer default ipv6 pool v6prefixpool2
!
ipv6 local pool v6prefixpool 2001:DB8:9999:8800::/56 64
ipv6 local pool v6prefixpool2 2001:DB8:8888::/48 56

As the above config is just an example it uses the appropriate address space that IPv6 provides for examples, 2001:db8::/32

Hope it helps someone…