Following my work with the FreeBSD implementation of RFC 6980 I was happy to present my work at last week’s DENOG 9 meeting.
To make it available to anyone who did not meet me there and go into some more detail that would have exceeded the boundaries of the talk, I will cover the topic here.
After the preceding work on Windows Server 2016 and the FreeBSD testing, as a Linux user, lover and administrator, I of course wanted to take a look at how different Linux systems complied with the RFC 6980 standard.
As many people I spoke with before my talk weren’t familiar with the topic I’m going to give a short introduction. So if you just grabbed a link to this from twitter and don’t want to take a detailed look at the RFC right now, here’s a short sketchy description of the topic. If you’re already familiar with the previous posts, feel free to skip the next two paragraphs.
An important design component of IPv6 is the Neighbor Discovery (ND) protocol, which provides a framework for all local management tasks like Router Discovery, Prefix Delegation, Address Autoconfiguration, Duplicate Address Detection and so on. As this only takes place on the local link, all of these mechanisms are unencrypted by design – if not replaced by SEcure Neigbor Discovery (SEND). Thus, clients on the network have no means of verifying the sender or data of ND messages. While in IPv4, a router was mainly a forwarding device, in IPv6 – through the Router Advertisement (RA) – a router also provides the client with the necessary information to connect to the network, like IP and prefix information. The risk of an attack, because of which I did this research, lies in an unauthorized client on the network sending a rogue RA, feeding clients a different IP address and default route and thus interceping its traffic by replacing the original router. Another problematic part of IPv6 design are Extension Headers. For the purpose of simplifying the IPv6 header, the “Next Header” field was introduced, thus allowing any number of extension headers to be placed in nearly any order in the IPv6 packet.
RFC 6980 states that these ND packets, as they’re only traveling on the local link, need not be fragmented. Thus, it advises the client (RFC 2119 “MUST”) to silently ignore such messages, if fragmented. In our preceding work, my colleagues and I could show that this was not properly done if the RA came in fragments with some arrangements of Extension Headers placed in the fragmentable part of the message. A possible protection mechanism is the Router Advertisement Guard (RFC 6105) which can be enabled on a switch interface and forbidding RAs to be sent on that interface. However, as this mechanism can be evaded by some creative aligning of Extension Headers as well, we could successfully combine both flaws in the past. This way we managed to provide Windows and FreeBSD targets with freely chosen prefixes, have them set corresponding IP addresses and set routes to our attacker.
After the spooking results on FreeBSD and Windows, offering multiple possibilities to evade the Router Advertisement Guard on the switch and inject malicious route and IP information to the client, I wanted to know if it looked quite as shocking in the Linux world.
Was my Debian laptop, my daily companion that I treasure and update regularly (and thus myself), that susceptible to fraud?
Spoiler alert: It’s not, but it’s time for my Arch using colleagues to stop mocking me.
Please note: As this kind of benchmarking and testing is forbidden in some EULAs, I only used free Linux distributions and did not test any enterprise versions.
I mainly reused my lab setup that consisted of
- A Cisco Catalyst 3560 switch
- The “attacker” system running Linux and Chiron
- The “target” system, which was continuously re-installed with different operating systems
- My laptop, running a script to control attacker and target via SSH and collect the results
What I did to evaluate the behavior was basically the same as in the preceding work, so I’ll just cover the basics here, for more details feel free to read the previous posts linked above.
Once with the attacker connected to a plain switch interface and once with it plugged into a port where RAguard was enabled, I executed the following steps for every test case:
- Reset target network interface to ensure a clean slate
- Start tcpdump packet capture on attacker and target
- Call Chiron with test flags on attacker machine
- Stop tcpdump and collect the PCAPs
- Collect target IP and route information
The observations were, albeit not as shocking as with Windows and FreeBSD 11.0, not completely pleasing.
In summary, the results were:
- I managed to get through to the ArchLinux and CentOS systems (in addition to the previously tested Windows and FreeBSD).
- For the Debian, Ubuntu and OpenSUSE systems, however, I did not manage to find a combination that would allow me to inject addresses and/or routes.
- As with the FreeBSD before, I could only see the fragments and not the original RAs in the PCAP when RA guard was enabled.
- This leads to the even more shocking conclusion, that – on some systems at least – fragments of packets without the original first packet are evaluated based only on the contained Extension Headers.
As this affects nearly everyone who has IPv6, a local link and a router, the feedback I got after the talk was overwhelming. Thank you to all of you guys who approached me with questions, additional input or praise. This was my first talk at any conference ever and it has been a pleasure to be able to give it, so thanks to the DENOG organizers as well! The reactions I got really broadened the scope of where I thought this might apply and gave a lot of input to what still is there to be tested.
Many people approached me with the question of whether this was already being discussed with developers or vendors. The question of where this problem or incorrect behavior as of RFC 6980 originates is still to be discussed. My next steps will be looking at the different kernel versions, parameters and whether or not systemd-networkd is involved in the processing.
However, if you’re reading this and you are a kernel, systemd or other network stack developer, feel free to approach me on this topic.
Thanks for everyone who helped this talk be possible and a success and have a nice weekend!
Small comment on: “RFC 6980 states that these ND packets, as they’re only traveling on the local link, need not be fragmented. ”
The actual reason is that fragmentation for ND does not make sense. Note that the fact that the protocol runs on link-local does not really have implications n whether fragmentation should or shouldn’t take place: ND/ICMPv6 cannot segment data into multiple packets if you need to end lots of info in an RA you have no other option than to fragment. But this doesn’t happen in practice at all.
The only case where that might happen is SeND. But I would bet money on SeND never seeing finding widespead usage.