(Or How the Smallest Detail Can Make a Difference)
This is a guest post from Antonios Atlasis.
As it is well known to the IPv6 enthusiasts, one of the most significant changes that IPv6 brings with it, apart from supporting a really huge address space, is the improved support for Extensions and Options, which is achieved by the usage of IPv6 Extension headers. According to RFC 2460, “changes in the way IP header options are encoded allows for more efficient forwarding, less stringent limits on the length of options, and greater flexibility for introducing new options in the future.” So, by adding IPv6 Extension headers, according to the designers of the protocol, flexibility and efficiency in the IP layer is improved.
This can definitely be the case, but apart from it, it has already been shown that by abusing IPv6 Extension headers several security issues may arise (see for example my presentations at Black Hat Abu Dhabi 2012 and at the IPv6 Security Summit @ Troopers 13). This is why Enno Rey by talking straight to the point at the latest IPv6 Security Summit @ Troopers 14 described the IPv6 Extension headers as a “mess”!
Unfortunately, it seems that we have not exhausted yet all the potential security problems introduced by IPv6 Extension headers. In this article, I am going to describe a novel way of abusing IPv6 Extension Headers which can be used to evade successfully high-end IDPS commercial devices. Specifically, during the “Researching IPv6 Security Capabilities” (RISC) project organised by ERNW and in which I had the pleasure to participate, we found out that using this technique, we can evade the Tipping Point IDPS (for a full presentation of the results of the 1st phase of RISC which were presented at the IPv6 Security Summit @ Troopers 14, please check here). But, before describing how it works, let’s build our case first.
As it is explained in RFC 2460, “in IPv6, optional internet-layer information is encoded in separate headers that may be placed between the IPv6 header and the upper- layer header in a packet. There are a small number of such extension headers, each identified by a distinct Next Header value.” According to the protocol specification, “an IPv6 packet may carry zero, one, or more extension headers, each identified by the Next Header field of the preceding header.”
Let’s assume that the initial IPv6 datagram that needs to be fragmented contains the IPv6 main header (obviously), a few IPv6 Extension headers and the layer-4 header (e.g. TCP) plus its payload. Some of the IPv6 Extension headers (like the Hop-by-Hop and the Routing IPv6 Extension headers) may need to be processed by intermediate nodes, while some other (e.g. Destination Options IPv6 Extension header) may not. A part of this initial IPv6 datagram will remain unfragmented, and the rest of it will be fragmented as following:
The Unfragmentable Part will consist of the IPv6 main header plus any IPv6 Extension headers that must be processed by intermediate nodes en route to the destination (Hop-by-Hop and the Routing IPv6 Extension headers in our example).
The Fragmentable Part will consist of the rest of the packet, that is, any IPv6 Extension headers that need be processed only by the final destination node(s), plus the upper-layer header and data (that is, the Destination Options IPv6 Extension header, the TCP header and its payload in our example).
But let’s focus on Next Header values of the IPv6 Fragment Extension Headers. Regarding fragmentation, according to RFC 2460, page 20, each fragment packet (among else) is composed of an IPv6 Fragment Extension header containing “the Next Header value that identifies the first header of the Fragmentable Part of the original packet”. So, the Next Header values of the IPv6 Fragment Extension headers of ALL fragments should be the same and equal to the header value of the first header (IPv6 Extension header or layer-4) of the fragmentable part. To clarify it farther, RFC 2460 at page 21 suggests that the Unfragmentable Part of the reassembled packet consists of of all headers up to, but not including, the Fragment header of the first fragment packet (that is, the packet whose Fragment Offset is zero), with the following (among else) change: “The Next Header field of the last header of the Unfragmentable Part is obtained from the Next Header field of the first fragment’s Fragment header.” And, if there is a doubt, to clarify the situation, RFC 2460 at page 22 recommends that “The following conditions are not expected to occur, but are not considered errors if they do: … <snipped for brevity>… 2) The Next Header values in the Fragment headers of different fragments of the same original packet may differ. Only the value from the Offset zero fragment packet is used for reassembly. ”.
I suppose that the situation now is crystal clear. No matter what the Next Header values of the IPv6 Fragment Extension headers used in the fragments are, it is only the Next Header value of the IPv6 Fragment Extension header whose offset is zero (0) to be used as the Next Header value of the last header of the unfragmentable part. Yet another potential ambiguity introduced by our beloved IPv6 RFCs. But protocol ambiguities always ring the same bell: “IDPS Evasion”.
Let’s see an example: Let’s assume that the original packet that needs to be fragmented is the following:
Note: Of course, you can change, add or even remove one of the used IPv6 Extension headers, if you wish. Now, let’s assume that the fragmentable part is the following:
According to what have been described so far by RFC 2460, the aforementioned packet should be fragmented as following:
and the 2nd fragment:
Please, note the Next Header values of the IPv6 Fragment Extension headers, as recommended by RFC 2460.
Now, what if the Next Header value of the second fragment points to the layer-4 header, that is, what if the second fragment is like the following:
In this case, the IPv6 Fragment Extension header of the second fragment “points to” the layer-4 protocol, which is TCP in our example, the header value of which is 6. As described above, according to the RFC 2460 such a case should not occur but is not considered as an error if it does 🙂
Well, by testing such packets at the RISC lab together with the ERNW guys, we found out that:
1. Most of the popular Operating Systems (Windows, Linux, OpenBSD) accept such fragmented datagrams, as they actually should, according to RFC 2460.
2. Tipping Point IDPS (TOS Tipping Point, Package 22.214.171.12436 and vaccine 126.96.36.19930 digital) misinterprets such fragments and lets them pass through even if you have explicitly defined not to do so (again, more details on the tests that we run, the used configuration, etc. can be found here).
3. The above combination results in a layer-3 evasion of the Tipping Point IDPS device, which means that you can actually launch any kind of attack (from port scanning to SQLi) while remaining undetected.
Here, we should note that:
1. Tipping Point IDPS is not the only IDPS device that it has been found out to be vulnerable to the aforementioned attack, or a variation of it.
2. The specific vendor reacted rapidly and has already patched the described vulnerability (please, check their web site for available patches).
Is this the end? Well, I am afraid not 😉 IPv6 Extension Headers are a mess, indeed. More will follow, so, stay tuned!
What you describe is essentially the same issue described in: (which eventually became RFC 7113).
RFC7112 should take care of this, since the aforementioned packets are now considered illegal.
first of all, thank you for your comment.
RFC 7112 as well as RFC 7113 describe the case that the first fragment should include the entire IPv6 header chain including the layer-4 header too.
From RFC 7112: “When a host fragments an IPv6 datagram, it MUST include the entire IPv6 Header Chain in the First Fragment.”
This is definitely an issue correctly identified and solved by the RFCs that you mentioned, but the technique described in this article can/is also applied when the first fragment (offset = 0) contains the entire IPv6 header chain, including the layer-4 one and even a part of the layer-4 payload. So, we are talking about a fully legitimate packet. This is not a theory, it has been confirmed against specific device(s). As the article describes, it is the value used as a Next Header one at the Fragment Extension header of the second, third, or last fragment that makes the difference and creates the issue. Such a value (e.g. of the layer-4 header and not of the first Extension header of the fragmentable part) although not the recommended by the RFC 2460 one, it should be accepted but the end-hosts as the RFC recommends (and it does, actually).
To sum up, even if you include the layer-4 header and part of its payload in the first fragment, by using a non-recommending value for the Next Header of the IPv6 Fragment header of the second fragment can still make the difference (that is, to be used to circumvent IDPS).
So, this is not the issue described in RFC7112/RFC7113.
I hope I clarified it.
We are at your disposal for any further clarification.
Thanks again for your comment
Antonious – great find! So for now this is a problem. However, would you agree that Fernando solved this problem with RFC 7112? The problem of course is that it will probably take 2-3 years from publication date of Jan 2014 before most vendors implement it…
Abusing IPv6 fragmentation to avoid intrusion detection isn’t novel. It’s discussed in RFC6980 in the context of NDP. Fragmentation and reassembly is always going to be a problem for IDS’s as they have finite memory. Best mitigation is to avoid fragmentation whenever possible.
It’s a shame that the IETF hasn’t revised PMTUD for IPv6 so that it does not depend on IPMC for control messages(RFC1981). Thankfully we don’t have NAT in IPv6, but I’m still concerned that firewalls will still drop outgoing ICMP. Only time will tell. PLPMTUD(RFC4821) doesn’t cut it either.
If we had an effective way to determine path MTU then firewalls could just drop all fragments.
full ack to your points. Personally I think either fragmentation as a whole or extension headers as a concept have to “disappear” (read: be deprecated by “appropriate IETF standards”) in the mid-term. Leaving both “legitimate & alive” will create too many security (=> network stability) problems in the IPv6 world which that one won’t be able to afford in the long term.
to clarify it further, in the example mentioned in the article:
Part 1 out of 2 of the fragmentable part = IPv6 Destination Options Header + TCP header + part of TCP payload. This is carried in the fragment with offset = 0.
Part 2 out of 2 of the fragmentable part = the rest of the TCP payload. This is carried in the second fragment (offset #0)
These fragments are legitimate according to what is defined in RFC 7112, RFC 7113, RFC 6980, as well as in RFC 2460. But they still “work” (that is, they can evade a device like TP).
If you want block it in an RFC way, I believe that p.22 of RFC 2460 should be changed as following:
Delete paragraph: “The Next Header values in the Fragment headers of different fragments of the same original packet may differ. Only the value from the Offset zero fragment packet is used for reassembly.”
and add sthg like “if the Next Header values in the Fragment headers of different fragments of the same original packet differ, all the fragments that comprise this datagram should be dropped…” etc., or sthg similar.
However, if ALL the vendors strictly follow RFC 2460 in this subject, there wouldn’t be a security issue and a need for an RFC update.
Thank you all
I received a couple of questions to clarify whether this is a kind of “0-day” or not. This specific vulnerability has been patched by Tipping Point!
I apologise for any confusion.
As mentioned in RFC 2460 “The Next Header values in the Fragment headers of different fragments of the same original packet may differ. Only the value from the Offset zero fragment packet is used for reassembly”
As I understand the only the first fragment (offset zero) will be used, the non-first fragments will not be used. Thus even if the next header second of the non-first fragments has 6 which refer to TCP, this value will not be used because it is not the first fragment.