A bit over a year ago my friend Marc and I started getting interested in IPv6. We had seen a number of IPv6 addresses in some of our previous work and they had been instrumental in acquiring some 26 CVEs. Through this research it seemed that the network interfaces we could access over IPv6 were routinely worse off from a security perspective, and that got us thinking… What would it take to start measuring the difference in security posture between IPv6 and IPv4?
What follows here is part brain dump of what all we’ve learned on IPv6 addresses in the 1.5 years since then and part background information on our new ipv666 tool suite. We’re giving a first talk at Hack in the Box Dubai which is our “official” tool release and hope to continue iterating on the tool suite and research. We anticipate that the talk will cover some of the trickier points of the software in better detail and will link the video once it’s available. The quick n’ dirty on the tool suite is that it should enable you to start finding hosts over IPv6 that do not appear in public IPv6 data sets. While the information put forth in this blog post is by no means required reading to use our new tools, understanding the scope and nature of the IPv6 address discovery problem will enable you to use our tools better.
Internet Protocol version 6 (IPv6) is the most recent version of the Internet Protocol (IP), the communications protocol that provides an identification and location system for computers on networks and routes traffic across the Internet. IPv6 was developed by the Internet Engineering Task Force (IETF) to deal with the long-anticipated problem of IPv4 address exhaustion. IPv6 is intended to replace IPv4. IPv6 became a Draft Standard in December 1998, and became an Internet Standard on 14 July 2017.
You’ve probably seen plenty of IPv4 addresses before (like 192.168.0.1, 10.0.0.1, and 127.0.0.1), and IPv6 is just the next iteration. IPv6 addresses are quite a bit uglier than their IPv4 cousins (we know, it’s not nice) as they are 128 bits long as opposed to the 32 bit length of IPv4. Some example addresses are below:
IPv6 comes with a slew of changes that all reflect some hard-earned lessons that came from the adoption of IPv4. From an engineering standpoint IPv6 is worlds ahead of IPv4. From a security standpoint… It’s rather hard to say. After learning a bit about IPv6 Marc and I were thinking that the security posture of hosts accessible over IPv6 had to be considerably worse off than their IPv4 counterparts.
What made us feel that way? I’m glad you asked.
Security Implications of IPv6
In no particular order, here are some significant changes between IPv4 and IPv6 that have security implications.
No More NAT
Network Address Translation (NAT) is a technology that we all rely on every day. Per Wikipedia, NAT is:
Network address translation (NAT) is a method of remapping one IP address space into another by modifying network address information in the IP header of packets while they are in transit across a traffic routing device. The technique was originally used as a shortcut to avoid the need to readdress every host when a network was moved. It has become a popular and essential tool in conserving global address space in the face of IPv4 address exhaustion. One Internet-routable IP address of a NAT gateway can be used for an entire private network.
NAT was initially created back in 1994 via RFC 1631. Together with RFC 1918 NAT is what gives us private address space like 10.0.0.0/8 and 192.168.0.0/16. The motivation behind NAT was never focused on security but instead on alleviating the IPv4 address space exhaustion problem. Despite this initial motivation lacking security context, NAT is arguably one of the strongest security controls for home network security. NAT is what makes it so that when you join your laptop and your Chromecast and your mobile phone to your home network the rest of the Internet can’t immediately start routing traffic to your devices. NAT is a technology that provides a very nice “secure by default” network topology for your home (and other) network(s).
In IPv6 we don’t really need to worry much about address exhaustion. As such, NAT was never intended to be available in IPv6. Humans being humans, though, NAT does actually exist in IPv6, but it still isn’t the default deployment. This means that in IPv6 there is no such thing as a “private network” anymore. When your devices join your home network and are allocated IPv6 addresses, those addresses are all public and traffic can be routed to them immediately. We are effectively swapping the security gains of NAT (secure by default) with the security gains of a firewall (opt in, confusing, difficult to manage, not secure by default). For example, Marc was able to ping my Chromecast on my home network from his apartment. Here’s hoping there aren’t any memory corruption vulnerabilities in the ICMPv6 parsing stacks out there (SOMEBODY SHOULD TOTALLY LOOK INTO THIS).
One exception to note here is that there are things called Unique Local Addresses, which purport to fulfill the same purpose in IPv6 as private network addresses in IPv4. Unless your devices are ONLY getting unique local addresses (which defeats a lot of the design considerations of IPv6) this is still not as good as IPv4’s NAT by default.
iptables? More Like ip6tables
If you’ve looked at your iptables -L output, seen that your entire INPUT chain is default rejected, and thought “phew I’m safe over IPv6” then I’ve got some bad news for you. The content of iptables has nothing to do with traffic that you’re receiving over IPv6. There’s a completely separate binary (ip6tables) for that!
ip6tables works exactly the same as iptables but just has its own set of rules. Not such a big deal but when attackers rely on administrative errors this is good to note, and unless you’ve explicitly set up your IPv6 firewall rules you’re probably wide open.
DHCP? Nah I’m Good.
When IPv4 was designed the issue of how machines would figure out their own IP addresses was more or less kicked down the road (as initial usage would have administrators statically set their machines’ IP addresses). This resulted in the creation of the Dynamic Host Configuration Protocol (DHCP) and its implementation in DHCP servers.
In order for your devices to start talking across networks they need IP addresses, and they will use DHCP to get those addresses provisioned to them in IPv4. Thus for an IPv4 network to actually work, an administrator (or device manufacturer) must provision a properly configured DHCP server. In IPv6, though, there’s a new protocol that enables devices to automatically provision addresses for themselves.
Enter Stateless Address Autoconfiguration (SLAAC). SLAAC is a protocol that defines a quick song and dance between a host and any/all gateways on its LAN. Without going into the details, a host is able to negotiate an IPv6 address for itself using only the existing networking infrastructure and its own MAC address instead of requiring a separately provisioned server/service.
As a side note, SLAAC had a few design flaws as far as privacy was concerned which resulted in Privacy Extensions being rolled out for SLAAC (making PSLAAC). PSLAAC addresses have all of their host bits (read: right-hand side of the address) generated using a pseudorandom number generator, which makes predicting PSLAAC addresses quite difficult (if not computationally unfeasible).
What does this mean for security, then? Devices can start talking over IPv6 without a network administrator having to provision specific services to support the IPv6 address allocation. This coupled with the following section…
Your Devices Love IPv6
Most (if not all) modern operating systems prefer IPv6 over IPv4, and most (if not all) modern networking equipment supports IPv6 out of the box. It seems that a big design aspect of IPv6 is to make things “just work,” and the engineers behind all the networking devices and operating systems appear to have followed that mantra closely.
Overall, we find these responses interesting in their variability with respect to how forthcoming operators are, or are not, with details of their address plan. We appreciate their candid, collegial responses, such as one even admitting, essentially, that some network gear“just works,” and that they did not study the resultant SLAAC-based address assignments to user equipment.
So, IPv6 is so damn good at “just working” that a network engineer at either an ISP or CDN didn’t have to care about how SLAAC-based addresses were assigned.
The takeaway here is that if your device can establish an IPv6 connection to a remote host it will prefer that connection over an IPv4 connection in most cases.
N Addresses, One Interface
In IPv4 there is a one-to-one mapping of IP addresses to interfaces. While there are plenty of exceptions to this (such as VLAN tagging an interface and IP aliasing), these exceptions only allow multiple IP addresses for a single PHYSICAL interface. When you have a number of addresses aliased on the same interface and run ifconfig, you’ll see individual VIRTUAL interfaces for each of the aliased networks:
Ergo, in IPv4 if I tell something to bind on eth0 there is a single IP address that it will be bound to. If I want to bind to localhost I know I can bind to lo0. If I’m on a private network I can bind to eth0 without worrying about publicly exposing myself. In IPv6, though, binding to an INTERFACE rather than an ADDRESS has the side effect of exposing that network service on all of the IP addresses associated with that interface.
If you’ve ever set up a network service and had to configure it, what sort of information did you have to provide when setting the network interface for it to bind to? Did it ask for an IP address or an interface? I know that I have seen both, and I don’t know how this problem is intended to be addressed (I’m guessing there’s either some sort of common method for binding to a specific address+interface pair or you’re supposed to firewall off traffic destined to the bound port to only the intended address).
People have been conditioned to associate a single interface with a single IP address in IPv4 and now using the same configuration nomenclature could expose a service that is only meant for link local communication to all the other addresses exposed on the interface. I wonder how many network services are misconfigured in this way.
For a protocol that sounds so important, I’ve only ever heard of the Internet Control Message Protocol (ICMP) in regards to sending ICMP ping probes. In the interest of full disclosure I’m also not a network engineer so it could just be that I was never exposed to its other uses. My main perspective on ICMP though is that it’s mostly unused and can be blocked without having adverse effects on your network.
ICMPv6, on the other hand, cannot be disabled and/or completely blocked at the network level.
In IPv4 we have the Address Resolution Protocol (ARP) which hosts will use to map a layer two address (ie: MAC address) to a layer three address (ie: IP address). This is pretty critical, as if you can’t go up the stack in the OSI network model you’re not going to be all that effective of a network. ARP is its own layer two protocol. In IPv6 we have something new called the Neighbor Discovery Protocol (NDP) which is built on top of ICMP. NDP serves the same purpose as ARP (mapping layer two addresses to layer three addresses), which is to say that without it your host wouldn’t be able to communicate above layer two.
As such, properly working ICMPv6 is a requirement for IPv6 networks to function. There are also some other additions in ICMPv6 which can do some pretty interesting network reconnaissance. While there are ways in ip6tables to specify different types of ICMP packets to let through, the (what I perceive to be common) method of blocking all ICMP in all the places (or disabling it entirely on hosts) is no longer tenable in IPv6.
There are no more broadcast addresses in IPv6. Instead, there are multicast addresses which can accomplish everything that broadcast addresses did and then some. While multicast is not new (it existed in IPv4), it was not particularly well-supported until IPv6. Multicast is part of the core protocol for IPv6 and various critical services (such as NDP) use it. Multicast enables a host to send a single packet and have the networking infrastructure duplicate and propagate that packet a certain distance before delivering it to a certain class of recipients.
Multicast in IPv6 works by having the left half of the address dictate the scope (how far to propagate a packet) and the right half of the address dictate who should receive the message. For instance the multicast address ff0e::1 means “keep propagating this multicast packet as far as you can and deliver it to everyone.”
Some well-known multicast addresses (taken from Wikipedia) are below:
As stated above, multicast has been around for a while so this isn’t all that new, but its widespread support certainly is. That and the distance that multicast packets are propagated rely upon proper network infrastructure configuration. Will we ever see an attack that uses IPv6 multicast to deliver a single malicious packet to a plethora of devices? Talk about an amplification attack!
Taken in sum, the differences listed above have the following takeaways:
IPv6 works out of the box without any configuration
All your devices and networking equipment prefer it
There’s no such thing as private address space (for the most part)
Everything is routable
Your existing firewall rules don’t apply
Existing service configurations might bind sensitive services to unintended IP addresses
You can’t easily prevent ping scans
Single packets can be relayed to lots and lots of hosts
Let’s Go Hunting
After coming to the above realizations and the ensuing necessary cold showers, Marc and I wanted to start validating whether or not IPv6 host security posture is significantly different from IPv4. It was about this time that we ran into the bottleneck that we’ve spent the time since trying to solve.
The problem? The search space for IPv6 is absolutely massive.
In IPv4 there are 2^32 (4,294,967,296) possible addresses. In IPv6 there are 2^128 (340,282,366,920,938,463,463,374,607,431,768,211,456) addresses. Attempting to scan across the IPv6 address space using standard high-throughput scanning tools like Zmap and MassScan won’t do much of anything.
Additionally, as mentioned previously, most client devices (read: laptops, desktops, cell phones, tablets, etc) will use PSLAAC to generate their own addresses, which in turn results in a significant chunk of these addresses being cryptographically random (typically around 64 bits). If you’ve ever tried to guess a correct number in 2^64 then I applaud your enthusiasm and revile your thick-headedness (crypto researchers not withstanding).
These facts made us re-evaluate our goals and resulted in us breaking the one problem into two separate new problems; enumerating IPv6 hosts that use PSLAAC and enumerating IPv6 hosts that have statically or DHCP allocated addresses. To tackle the first problem we went with a honeypotting approach, and to tackle the second we built the ipv666 software suite.
I’m mentioning this for the sake of completeness, as it is work that we did, but targeting PSLAAC addresses was way less fruitful and way less intriguing than the statistical modeling shenanigans.
Our approach for honeypotting was to set up a number of different services that client devices might connect to, and try to force those connections over IPv6. This was our first error, as we didn’t really internalize just how often a host will prefer IPv6 over IPv4. Our findings showed that if an IPv6 connection was possible it would be preferred, so there went a bunch of unnecessary engineering effort attempting to force these IPv6 connections.
We stood up a web server, an SMTP server, and a DNS server, all accessible over IPv6. We also had the web server run a WebRTC IP address enumeration script and post the results back to our collection endpoint.
The SMTP server was a complete bust, as we found that there aren’t all that many parties out there running their own SMTP servers anymore. It’s all Google, Microsoft, Yahoo, etc, and any mail we received from those domains were from a handful of mailservers. All of the addresses we got through SMTP honeypotting were infrastructure that often already had AAAA DNS records pointing to it. Womp womp.
The DNS server was successful to an extent, but as was the case with the SMTP honeypotting, pretty much all the requests we received to our DNS server were from other DNS servers (ie: recursive resolvers and not clients). Cool to enumerate DNS infrastructure that you might not know of in particular companies, but again not what we were looking for. As a side note DNS data collection is quite interesting as while most code may have some hesitance around issuing an HTTP request, resolving domain names is almost always seen as innocent (despite the fact that it can be a decent information leak). Womp (kinda) womp.
The web server was our biggest hit. A picture of our landing page is shown below:
We were, for a time, the world’s leading purveyor of IPv6-enabled kittens.
We also sprayed the URL to our honeypot site (http://ipv6.exposed/, thanks to anyone that clicked <3) over social media and the like and got a handful of visits that way.
So, what did we get for nine months of collection, hours and hours of engineering, and sending some blood money to a botnet? Check out the charts below. Top left is DNS queries, top right is HTTP requests, and bottom left is successful WebRTC enumerations:
We got a total of 92,609 unique IPv6 addresses over nine months, and plenty of those were for infrastructure that we weren’t particularly excited about. Interesting, for sure, but nothing groundbreaking.
Our takeaway here was that if we were doing an IPv6 external network penetration test of an organization and we wanted to target client devices, we would set up a web server over IPv6, enumerate email addresses for the organization via LinkedIn, and then send an email blast out to the employees with a pixel tracker and link pointing to our web server. Standard non-exciting social engineering attacks. Whoopee.
Modeling IPv6 Address Structure
Alright now that we’re done with that snoozefest let’s get down to brass tacks.
From looking at the IPv6 addresses in a number of public data sets it was rather obvious that there was quite a bit of recurring structure in the non-PSLAAC addresses. This is also the point at which we found out about the Entropy/IP paper, wherein they describe their own statistical model in significant detail. Their work is extraordinary, but they also have access to lots and lots of the IPv6 addresses that communicate across the Akamai network. It’s easy to build a model when you have billions of candidate data points to start from!
One of our first steps was to accumulate our own IPv6 address corpus from public data sets. We found as many public data sets as possible, from the Rapid7 Sonar AAAA records to PCAP databases to Censys (the more the merrier). We didn’t know at the time that some folks in Munich had made the IPv6 address hit list which contained all of the addresses we found. Yet another womp womp. In total we amassed 15,004,894 unique addresses across all of our data sources.
With the training address set in hand we set out to create a model that could predict IPv6 addresses. We started where any sane, reasonable person would…
WITH MACHINE LEARNING!!!
We are by no means machine learning experts, which made this endeavour even more laughable, but alas we persisted. With the help of one of our friends we tried building some predictive models with fairly basic algorithms and in all cases the result was an overfit model that would predict the same addresses that we fed it (this is to say that the ML prediction process would take in a list of IP addresses and generate an equally long list of new addresses, but in this case the addresses that it predicted were the same as the input data set). After trying a few different things to fix the overfitting, we went back to the Entropy/IP paper and felt that we were over-engineering things. Ah yes the usual ML experience when you realize that far simpler heuristic models are equally viable.
The statistical model that we came up with is stupid simple and is definitely a place where the power of the ipv666 software could be improved. Whereas the Entropy/IP folks broke addresses down into byte blocks based on entropy calculations across bit boundaries, we only have per-nybble probability distributions.
We processed each of the IP addresses in our data set and kept track of the probability of a nybble’s value in a position based on the content of the preceding nybble. For instance, take the following four addresses:
ff00::1 (first four nybbles 0x0f, 0x0f, 0x00, 0x00)
ff10::1 (first four nybbles 0x0f, 0x0f, 0x01, 0x00)
ff10::1 (first four nybbles 0x0f, 0x0f, 0x01, 0x00)
ff20::1 (first four nybbles 0x0f, 0x0f, 0x02, 0x00)
If we built our model on only these four nybbles and started generating a new address starting with the nybble 0x0f, then the second nybble would be 0x0f as it’s 100% of what we’ve seen in our input data set when the first nybble is 0x0f. We then go to predicting the third nybble, which has the following probabilities:
p(0x00) = 0.25
p(0x01) = 0.5
p(0x02) = 0.25
We then roll a weighted die to figure out what the next nybble will be based on these distributions and continue to the fourth nybble, so on and so forth.
In summary, we have a model that predicts on a per-nybble basis from probability distributions of what nybble values have been seen at that offset, and these probability distributions change depending on what the preceding nybble value is. These addresses are generated left-to-right and always start with 0x02. The model, when implemented in Golang, can generate 10mm addresses and write those addresses to a file in approximately 90 seconds, including some blacklisting and prior existence checks.
Once we had this model built we were all kinds of excited. Then we found out about aliased networks.
We generated 10mm addresses, wrote the addresses to a file, and then fired up the IPv6-enabled ZMapv6.
WE WERE FLOORED! IT WAS SO SUCCESSFUL!!
…too successful. I want to say that the first time we ran the scan, out of an initial 10mm addresses to scan, around 50,000 of them responded as being live. Upon further investigation we found that there were network ranges where every single address in the range would respond to an ICMP ping. We did a bit more digging and found that every address was being routed to the same host (determined via SSH host key checking). At the time we referred to these network ranges as “asshole network ranges” but the folks in Munich have a much more amicable “aliased network” term.
So now we faced a big problem. As these ranges would respond to every ICMP probe we sent their way they would be disproportionately represented in our discovered address data sets. This would in turn skew our statistical model toward those ranges, thereby generating more addresses to scan within them. This positive feedback loop could (and did) train itself into only generating addresses in aliased network ranges, which dropped the efficacy of our statistical model to nil.
We needed a way to both (1) identify aliased network ranges and (2) discount any addresses in them from our model and resultant data sets.
We went back and forth with some suboptimal ways of solving this problem, but came up with the following strategy which identifies aliased network ranges with precision.
First we must determine if a network range exhibits traits of an aliased network range. To do this, we take all of the addresses that responded to our ICMP ping scans and group them into /96 networks. We then generate N random addresses in each of these networks and ICMP scan them. Once we have the ICMP responses, we look at how many responses we got for each of the networks. It is highly unlikely that randomly guessing a bunch of addresses in a network with a size of 2^32 will correctly guess a bunch of legitimate responsive hosts, so if a certain threshold of addresses in a particular /96 network responded to our ICMP probes then we marked that /96 network as aliased.
Second, we must now take all of these /96 aliased networks and determine just how large the containing aliased network is. To do this we perform a binary search on the bits of each network. For instance, if a particular address responded to an ICMP ping in one of the /96 networks, we know that at least the right-most 32 bits of the address are within the aliased network, which leaves the left-most 96 bits in question. So we then flip all of the bits from the 48th position through the 96th position in the address and send it another ICMP ping. If a ping response is received, we know that those 48 bits we flipped are also within the aliased network range. Otherwise we know that the border of the aliased network is somewhere within those 48 bits. We continue to do this “bit flip and scan” approach with smaller and smaller sections until we’ve found the network boundary, which takes five to six iterations.
It was a lot of hair-pulling, dying inside, and crying blood, but we made it and it worked! We were now able to identify the exact network ranges that were aliased from our scan results and remove them.
It’s Scannin’ Time
The ipv666 scanner uses the following loop to predict addresses, scan them, identify aliased networks, clean scan results, and update the statistical model. It’s built based on the statistical modeling and aliased network discovery described in the preceding two sections.
Generate Addresses – Generate a fixed number of addresses from the statistical model
Ping Scan Addresses – Perform the initial ICMP ping scans of the generated addresses
Network Grouping – Take the addresses found in (2) and group them into /96 networks
Seek Aliased Networks – Using the algorithm detailed in the preceding section, determine which (if any) of the networks is aliased
Process Aliased Networks – Process the results of the aliased network discovery and add them to the blacklist
Remove Bad Addresses – Clean the addresses found in (2) using the newly-updated blacklist
Update Model – Update the statistical model with the cleaned addresses resulting from (6)
Update Address File – Add the cleaned addresses to the cumulative output file
Clean Up – Clean up temporary and older files from this loop
The scanner then starts back over and keeps running until you kill it or it errors out (hopefully the prior, although it can be a bit memory hungry).
So just how well does this scanner work? Well, we’ve been furiously working on it more than we have been using it so we haven’t had it running in its optimal state for too long. BUT, in about a week, throttled to 20Mbps, falling over and working in various states of disrepair, our software identified 84,007 live hosts over IPv6, and 61,615 of those addresses were not found in any of the data sets that we used for training.
We also pointed our scanner at a particular ISP’s network range (a /32) and within 20 minutes had found 5,000 hosts, all of which appeared to be ISP customers’ home gateways (eesh, the flashbacks).
We really haven’t had the breathing room to experiment more with this software yet but once the dust settles from our upcoming conference talks we’re gonna see what we can find with this shiny newness >:)
At the time of writing this I’m halfway around the world with a burner laptop and thus don’t have access to the data sets. Please pester me on Twitter (@_lavalamp) and remind me to post the data when I return home.
We’re happy that we’ve gotten the software to its current (mostly) working state. That being said, there’s always room for improvement.
One obvious improvement is to have a more complicated statistical model. Our current model is limited in that its prediction capabilities are only based on a single preceding nybble, while simple visual analysis of IPv6 data sets shows that there are relations across nybble boundaries.
Another improvement would be to have models for specific network ranges. It is likely that different networks are organized in different (but common) ways. In fact, the work by the Munich crew found (LINK) that there were only a handful of ways that networks were organized. If we could generate addresses with models that were specific to the ranges in which addresses were being generated, I would imagine the scanner’s efficacy would be boosted significantly.
Lastly, as can be seen in the data set listed above, our approach is really good at finding the lowest address in a network (e.g. ::1). It is not so good at finding addresses around those starting addresses. Adjusting the scanner to find initial “landing points” and then spreading out from there would probably net us a lot more addresses.
AND THAT’S IT! This was a long blog post – thanks for sticking with me to the end. With any luck our software will enable further research into IPv6 security posture.
Please check out our software and see what you think. If you find any bugs, report them and we’ll do our best to get ’em fixed. If you liked this post, like the software, or are just generally feeling altruistic, tips help us keep cranking on research like this. If you can spare it we’d appreciate your contributions:
EDIT 1 – Removed “(although ISPs are tempting fate by allocating /64 and /56 networks to all customer premise equipment gateways – you would think they’d be the first ones to realize the wastefulness there).” Thanks to those that pointed out that this is intended through RFC 6177. We’re still learning!
EDIT 2 – Changed some wording around the network engineer quote.