Some thoughts and tools from an IT Security enthusiast.

Yet another web site regarding IT security from an IT security enthusiast.

I created this web site to share my thoughts, my work and my tools with you.

Your comments and questions are more than welcome.

Enjoy!

Sat

16

Jan

2016

A few thoughts about IPv6 Jumbograms (and how you can send them over normal MTU links)

Introduction

 

As defined in RFC 2675 [Borman, Deering, Hinden, 1999], “a "jumbogram" is an IPv6 packet containing a payload longer than 65,535 octets”. An IPv6 datagram, due to the length of the IPv6 main header (16 bits), can support up to 65535 octets of IPv6 payload [Deering, Hinden, 1998]; this includes any IPv6 extension headers that may follow the IPv6 main header, but not the main header itself. For applications that need datagrams bigger than this (by the way, are you aware of any of this kind?), IPv6 jumbograms come into place. However, as also explained in RFC 2675, “jumbograms are relevant only to IPv6 nodes that may be attached to links with a link MTU greater than 65,575 octets” (65,535 octets of an IPv6 payload plus 40 octets for the IPv6 main header itself).

 

How IPv6 Jumbograms are Constructed

 

IPv6 jumbograms are defined as an IPv6 hop-by-hop option, called the “Jumbo Payload” option, that carries a 32-bit length field in order to allow transmission of IPv6 packets with payloads between 65,536 and 4,294,967,295 octets in length [Borman, Deering, Hinden, 1999].

 

The Payload Length field in the IPv6 header must be set to zero, while the Next Header value is also set to 0 (implying that a Hop-by-Hop header follows). So, an IPv6 Jumbogram would look like:

 

 

 

 

Now, the Hop-by-Hop header itself will look like:

 

    

where “Next header” is an 8-bit field whose value indicates the header that follows (e.g. if the next header is ICMPv6, it should be 58).

 

0 is the value of the Length field of the Hop-by-Hop header (the length of the Hop-by-Hop Options header in 8-octet units, not including the first 8 octets).

 

C2 (in hexadecimal) or 194 (in decimal) is the Jumbo Option Type.

 

4 is the Option Data Length.

 

Finally, the Jumbo Payload Length is an 32-bit unsigned integer which indicates the length of the IPv6 packet in octets, excluding the IPv6 main header but including the Hop-by-Hop Options header and any other extension headers present. The Jumbo Payload Length must be greater than 65535 (since, otherwise, there is no need to use a Jumbogram).

 

According to RFC 2675, the Jumbo Payload option must not be used in a packet that carries a Fragment header.

 

Relevant Work

 

The following vulnerabilities have been discovered related with the implementation of IPv6 Jumbograms.

 

CVE-2007-4567: The ipv6_hop_jumbo function in net/ipv6/exthdrs.c in the Linux kernel before 2.6.22 does not properly validate the hop-by-hop IPv6 extended header, which allows remote attackers to cause a denial of service (NULL pointer dereference and kernel panic) via a crafted IPv6 packet.

 

CVE-2008-0352: The Linux kernel 2.6.20 through 2.6.21.1 allows remote attackers to cause a denial of service (panic) via a certain IPv6 packet, possibly involving the Jumbo Payload hop-by-hop option (jumbogram).

 

CVE-2010-0006: The ipv6_hop_jumbo function in net/ipv6/exthdrs.c in the Linux kernel before 2.6.32.4, when network namespaces are enabled, allows remote attackers to cause a denial of service (NULL pointer dereference) via an invalid IPv6 jumbogram, a related issue to CVE-2007-4567.

 

Testing IPv6 Jumbograms

 

Of course, the big problem with IPv6 Jumbograms (from a tester's / researcher's perspective) is the fact that it is not that easy to find a link with an MTU suitable for supporting them. So, I was thinking about alternative approaches. One such approach could be to … fragment an IPv6 Jumbograms; I know, this does not make sense in real life (why fragment something whose intended purpose is to avoid the necessity of fragmentation) and secondly, it is “forbidden” by the corresponding RFC (but, who cares about this)? So, I decided to give it a try.

 

Now, the first approach would be to put the Fragment Extension header after the Hop-by-Hop header (which carries the “Jumbo” payload). In this case, there is a problem with the Payload Length field of the IPv6 main header. Typically, this should be zero for IPv6 Jumbograms, but given that we use fragment(ation), a correct Payload Length should be used to determine the end of the fragment. Nevertheless, this scenario can be tested as follows:

 

For 65536 bytes of IPv6 datagram (excluding the IPv6 main header), we need:

 

- 8 bytes for the Hop-by-Hop header

 

- 8 bytes for the ICMPv6 Echo Request header

 

- 65536 - 8 – 8 = 65520 bytes of layer 4 payload, that is 8190 octets of bytes.

 

 Let's fragment it in 56 fragments. Assuming that our target listens to the IPv6 address 2001:db8:1:1::2 m we can use the following Chiron command:

 

./chiron_scanner.py vboxnet0 -sn -d 2001:db8:1:1::2 -l4_data `python -c 'print "AABBCCDD"*8190'` -luE 0'(options=Jumbo;jumboplen=65536)' -nf 56 -plength 0

 

It should be noted that the reassembled packet is recognised properly as an IPv6 jumbogram, and specifically, as an ICMPv6 Echo Request of 65528 bytes (65526 bytes are reached after adding the length of the Hop-by-Hop header).

 

The other approach is to Fragment the Hob-by-Hop header (that is, to put the Hop-by-Hop header in the fragmentable part of the initial IPv6 datagram). Of course, RFC 2460 forbids this (“ The Hop-by-Hop Options header, when present, must immediately follow the IPv6 header”), but you never know. Let's try to find out what happens in the real world, using the following Chiron command.

 

./chiron_scanner.py vboxnet0 -sn -d 2001:db8:1:1::2 -lfE 0 -l4_data `python -c 'print "AABBCCDD" *1'` -nf 2

 

The above command adds a Hop-by-Hop header in the fragmentable part of the IPv6 datagram and then, it fragments it to two fragments (for explanation of the switches, please check my previous blog post).

 

The tested OS were (once more):

  • Windows 10 Home, Version 1511, OS Build 10586.36, x64

  • Centos 7, kernel 3.10.0-327.3.1 x86_64

  • Fedora 23, kernel 4.2.8-300 x86_64

  • FreeBSD 10.2-RELEASE-p7, amd64

  • OpenBSD 5.8, GENERIC#1170 amd64

After executing it, I found out that most of the tested OS respond with an ' ICMPv6 Parameter problem, unrecognized Next Header type encountered' packet, while OpenBSD responds with an Echo Reply (OK, not a vulnerability on its own, but such an RFC noncompliance is still a bit disappointing for an OS which emphasises, among else, on standardization, correctness, and proactive security.

 

How can we reproduce it? Using the previous approach, but by moving the Hop-by-Hop header to the fragmentable part of the IPv6 datagram. This time the Chiron command will like:

 

./chiron_scanner.py vboxnet0 -sn -d 2001:db8:1:1::2 -l4_data `python -c 'print "AABBCCDD"*8190'` -luE 0'(options=Jumbo;jumboplen=65536)' -nf 56 -plength

 

Again, Wireshark recognises the reassembled IPv6 Jumbogram ICMPv6 Echo Request properly!

 

Happy Jumbo-testing :-)

 

PS: The Chiron version that will support IPv6 Jumbograms will be released during the IPv6 Security Summit of Troopers 16.

 

References

 

Borman D., Deering S. & Hinden R. (1999). IETF RFC 2675 “IPv6 Jumbograms”, August 1999.

 

Deering S. & Hinden R. (1998). IETF RFC 2460 “Internet Protocol, Version 6 (IPv6) Specification”, December 1998.

 

0 Comments

Wed

13

Jan

2016

Unusual IPv6 Fragmentation and Operating Systems Responses

It has been already almost three years than I last checked and presented (at BlackHat Asia 2012 and Troopers 13) the Operating Systems (OS) behaviour in case of non-compliant (according to RFC 2460) usage of IPv6 Extension headers. One of the cases that examined (briefly) at that time was a kind of “nested” IPv6 fragmentation. In this blog post I will present my latest results regarding this topic by trying to also extend the previous work with some more potentially interesting cases.

 

Starting from the very basic, fragmentation fields in IPv6 have been removed from the IP main header (where they used to be in IPv4); instead, a specific IPv6 Extension header, the so called Fragment Extension header, is used for fragmentation purposes in IPv6. This header, incorporates, among else, the Offset field, the Fragment Identification Number field and the “More Fragment to Follow” (M) bit. Normally, there should be only one Fragment Extension header per IPv6 fragment (why a legitimate sender should use more than one?), but RFC 2460 is not that strict with this: “Each extension header should occur at most once, except for the Destination Options header which should occur at most twice. In any case though, I am not aware and I cannot think any kind of a legitimate case that an OS could incorporate more than one IPv6 Fragment header in one fragment.

 

Lab set-up

 

In my last experiments I tested the following Operating Systems:

  • Windows 10 Home, Version 1511, OS Build 10586.36, x64

  • Centos 7, kernel 3.10.0-327.3.1 x86_64

  • Fedora 23, kernel 4.2.8-300 x86_64

  • FreeBSD 10.2-RELEASE-p7, amd64

  • OpenBSD 5.8, GENERIC#1170 amd64

 The tool used for the testing was, what else, Chiron.

 

As a layer 4 protocol, ICMPv6 Echo Request was used (since it is the easiest way to trigger a response).

 

Let's start from defining a baseline by examining which OS accept Atomic fragments. These are fully compliant cases (by the way, there is a current, ongoing effort to deprecate them, but that is another story). Atomic fragments are the ones whose offset is equal to 0, and the M bit is also equal to 0, implying that this is the first and at the same time the last fragment. They are used in the very special cases (which, however, our out of the scope of our discussion). Such a use case can be reproduced by using the following Chiron command:

./chiron_scanner.py vboxnet0 -d 2001:db8:1:1::1,2001:db8:1:1::2 -lfE 44 -sn

where,

 

vboxnet0 is the network interface to use.

 

2001:db8:1:1::1 and 2001:db8:1:1::2 are (some of) our targets (obviously using a comma-separated list, more targets can also be tested using a single command, but they are not written here for brevity reasons).

 

-lfE 44 adds an “Atomic” Fragment Extension header (44 is the next header value of a Fragment Extension header), and

 

-sn is used for sending ICMPv6 Echo Request as a layer 4 header (nmap notation).

 

As expected (since this is a fully legitimate case), all OS respond to such fragments.

 

In this blogpost for convenience reasons I use the term “Atomic Fragment Extemsion header” an IPv6 Fragment Extension header which is used in Atomic fragments, that is one which has Offset=0 and M=0.

 

Tested Case 1: Two “Atomic” Fragment Extension headers in a single IPv6 datagram

 

First, let's see what happens when using two “Atomic” IPv6 Fragment Extension headers in a row in the same IPv6 datagram (figure 1).

 

 

Figure 1: Two “Atomic” Fragment Extension headers in a single IPv6 datagram (the length of the headers in the figure are not in scale)

 
The above case can be reproduced by using the following Chiron command:

 

 ./chiron_scanner.py vboxnet0 -d 2001:db8:1:1::1,2001:db8:1:1::2 -lfE 44,44 -sn

 

The results showed that it is all OS except from OpenBSD that respond to them. While typically such a case “could” be typically considered RFC compliant )according to the aforementioned RFC 2460 quote”, there is definitely no real, legitimate usage of such a case.

 

Test Case 2: Fragmented Atomic Fragments

 

In this case, a ...fragmented (in two fragments) Atomic fragment is sent. These fragments looks like:

 

 

Figure 2a: A ...fragmented Atomic fragment (the length of headers in the figure are not in scale)

 

 

The reassembled IPv6 datagram will look like:

 

 

Figure 2b: A reassembled ...fragmented Atomic fragment (the length of headers in the figure are not in scale)

 

 This case can be reproduced with the following Chiron command:

 

 ./chiron_scanner.py vboxnet0 -d 2001:db8:1:1::1,2001:db8:1:1::2 -lfE 44 -sn -nf 2

 

In the above command, while we have already added an “Atomic” Fragment Extension header using the -lfE 44 switch, we further fragment it using the -nf 2 switch.

 

No need to say that such a case should not be accepted in the real world :-)

 

The results showed that Fedora, Centos and Windows 10 accept these fragmented Atomic fragments.

 

Test Case 3: “Atomic Fragmentation”

 

In this case, an Atomic Fragment Extension header is added in front of each fragment of an otherwise normally fragmented IPv6 datagram. Specifically, let's assume that we have the following initial IPv6 datagram:

 

 

Figure 3a: A simple IPv6 datagram that incorporates one IPv6 Extension header (the length of headers in the figure are not in scale)

 

In the above datagram, a Destination Options Extension header was added to send the layer 4 header (ICMPv6 Echo Request in our case) to the second fragment (when fragmented, of course). So, when fragmented, the above datagram will look like:

 

 

Figure 3b: A fragmented IPv6 datagram that incorporates one IPv6 Extension header (the length of headers in the figure are not in scale)

 

 Now, let's add an Atomic Fragment Extension header just after the IPv6 main header. So, now our fragments are turn into the following: 

 

 

Figure 3c: “Atomic Fragmentation” (the length of headers in the figure are not in scale)

 

 The above case can be reproduced using the following Chiron command:

 

 ./chiron_scanner.py vboxnet0 -d 2001:db8:1:1::1,2001:db8:1:1::2 -luE 44 -lfE 60 -sn -nf 2

 

In the above command:

 

-lfE 60 adds a Destination Options Extension header in the fragmentable part (60 is the next header value of a Destination Options header),

 

-luE 44 adds an “Atomic” Fragment Extension header in the unfragmentable part (44 is the next header value of a Fragment Extension header), and

 

-nf 2 splits it in two fragments.

 

Which OS responds to such fragments? Just Windows 10!

 

 Potential security implications?

 

The typical ones. Remote OS fingerprinting, potential IDPS evasion, fuzzing of the targeted OS.

 

Can we make it even more complicated? Possibly. Using IPv6 Extension headers, sky is the limit ;-)

 

In a next blogpost I will discuss IPv6 Jumbodatagrams and how these can be sent (in very specific cases) over normal (e.g. Ethernet) MTU links.

 

Wed

25

Mar

2015

How To  Block Incoming IPv6 Fragments in Latest Red-Hat Releases

IP fragmentation is the source of many security issues, even from the IPv4 era; the case could not be different in IPv6 (see for example here and here). Of course, IPv6 Extension Headers can make the situation much worse. Hence, it seems that we have quite a few good reasons to block fragmentation at our firewalls, either at our network perimeter or even at host firewalls.

While writing an IPv6 Hardening Guide for Linux Servers, I found that the usual ip6tables rules to block fragmentation did not work in latest Red-Hat Enterprise OS and clones (e.g. Centos). Specifically, I found out that at Red Hat Enterprise version 6.6 (also affects version 7), while applying ip6tables to block incoming IPv6 fragments, IPv6 fragments are not blocked, as it should be the case, either for atomic or non-atomic ones. You can easily confirm it by:

a. Issuing the command: ip6tables -I INPUT 1 -i eth1 -m ipv6header --header frag --soft -j DROP

b. Sending ICMPv6 Echo Requests with size bigger than the MTU size, e.g.: ping6 -s 4000 <IPv6 address of the target machine>.

Note: This issue affects only the blocking of IPv6 Fragment header, not the rest of the IPv6 Extension headers.

Similar results (no blocking of IPv6 fragments) are obtained for the following commands:


ip6tables -I INPUT 1 -m frag --fragfirst -j DROP #(it should drop the first fragment)

ip6tables -I INPUT 1 -m frag --fraglast -j DROP #(it should drop the last fragment)

ip6tables -I INPUT 1 -m frag --fragmore -j DROP #(it should drop all but the last fragment)


I immediately reported it as a bug at Red Hat Bugzilla (Bug 1170144), assuming that this would be a kind of a bug that it would be fixed easily and quickly. However, the developers that responded mentioned that actually this was a consequence of a deliberate change of fragmentation handling in these systems. Specifically, they mentioned that this was probably because after bug id 1011214 (kernel-2.6.32-437.el6) netfilter started processing the reassembled packet instead of the fragments, like IPv4 does. For Red Hat 6.5 this was fixed on kernel-2.6.32-431.5.1.el6 and thus, any kernel before that would work differently. Now netfilter works like it works for IPv4. That is, the only way to see such fragments again through netfilter chains is by unloading nf_defrag_ipv6 module. They also mentioned that the change of behavior is because now only the final, reassembled, packet is pushed through netfilter chains - and not the fragments.

There is also a positive effect though. Due to this change, atomic fragments are not forward anymore, meaning that they will get reassembled and forwarded as a “clean” (without IPv6 Fragment header) packet, which is obviously good, at least from a security perspective.

However, this is not true for genuine fragments, since they will get re-fragmented on output in case you're forwarding them.

By unloading that module, you can still receive such packets locally but you're not able to use conntrack on that system.

After confirming that this was the case, it was obvious that a workaround should be found. A first few comments though.

First, the fact that "...genuine fragments, they will get re-fragmented on output, in case you're forwarding" seems to somewhat break one of the basic IPv6 principles (RFC 2460, section 4.5) which defines that: "unlike IPv4, fragmentation in IPv6 is performed only by source nodes, not by routers along a packet's delivery path". But this is not the most important consequence, although it introduces a delay (due to reassembly-refragmentation process).

As a security engineer I would like to have the ability to block fragments if I wanted to. Fragmentation in IPv6 when combined with Extension headers can have some really bad security consequences, as discussed briefly at the beginning of this article; so, I would like to be able to block them, if, for instance, this is the policy of my organisation, company, etc.

Now, if we use the aforementioned workaround (unloading the suggested kernel module), we will lose the capability of connection tracking, which is not good either (if not worse).

After a (short) discussion and a kinf of brainstorming, Florian Westphal from Red Hat suggested that IPv6 fragmented traffic could be filtered using nftables, because with them you can define arbitrary tables and priorities; so, its easy to hook packets before they hit defrag. However, at the time of this writing, March of 2015, nftables were not supported even on RHEL 7.1. Anyway, Marcelo Ricardo Leitner suggested a rule to block IPv6 fragments using nftables which would look like as follows:

table ip6 filter {

   chain preroute500 {

      type filter hook prerouting priority -500; policy accept;

      ip6 nexthdr ipv6-frag counter packets 2 bytes 2104

   }

}


As Marcelo explained, the line "ip6 nexthdr ipv6-frag counter" will match whenever an IPv6 packet is seen with a nexthdr field being set to ipv6-frag, which is only used for fragments (even atomic ones); other traffic will pass this check. Of course, for dropping, you have to add a 'drop' in this rule.

Is the aforementioned approach effective on blocking IPv6 fragments? Frankly, I have not tested it yet, but certainly, taking into account the latest kernel changes it seems to be the only way to do go. Hopefully, I will have the chance to test it soon, so, stay tuned :)

read more 0 Comments

Tue

17

Mar

2015

pfSense and IPv6 Extension Headers. Configuration Capabilities and Default Behaviour.

Given the fresh release of the latest pfSense, version 2.2.1 (which is based on FreeBSD 10.1-RELEASE-p6) and the recently announced end of the m0n0wall project, I decided to give pfSense a try since it seems that this is the only remaining open-source firewall solution that supports IPv6 out-of-the-box (I am not aware of any Linux alternative, if there is one, please let me know). My question was twofold. First, can the firewall administrator configure which IPv6 Extension headers should be allowed or not at the perimeter and secondly, what is the default behaviour of pfSense regarding the acceptance or not of IPv6 Extension headers?

 

The answer to the first question was rather easy, but disappointing. You can only configure the acceptance/dropping of  IPSec-related Extension headers, namely ESP and AH, probably because these are the ones known from the IPv4 era. Regarding the rest ones (Hop-by-Hop, Destinatioon Options, Routing header, or even fragmentation) there are no similar capabilities. This was not the case regarding m0n0wall where their configuration was possible (and this was one of the reasons why I used to prefer m0n0wall instead of pfSense).

 

OK, since we are not able of configuring them, what is the default behaviour of pfSense?  Are we ...protected from the "evil" IPv6 Extension headers? The tested configuration is really simple and it is displayed below:

 

 Attacker --------->  pfSense (running www server) ----------> target (running ssh).

       

As we can see, there is a pfSense firewall in the middle, running a web server available in the WAN interface too (this is not / should not be normally the case, but it was enabled just for my testing purposes), as well as a target "behind" the pfSense firewall running ssh.

Attacker and target reside on different network prefixes.

pfSense is configured to allow ssh traffic to the target and http traffic to the firewall itself over IPv6. All the other traffic, by default is blocked at the WAN interface.

For the tests, Chiron was used.

 

First, it was examined using which IPv6 Extension headers can be used to reach the otherwise allowed to port 80 tcp traffic. In this case, the WAN interface of pfSense itself is the target. The results are summarised below:

 

Extension Header                       Allowed

----------------                       ------

Hop-by-Hop header                     YES

Destination Options Header           YES

Fragmentation                            YES

Atomic Fragments                        NO

Type-0 Routing Header                 NO

Type 1, 2,3 Routing Header           NO

Layer 4 header in 2nd fragment      NO

(RFC 7112 implementation)

 

 

 

Not that bad. What I liked is that a) Type-0 Routing header (which is deprecated) is dropped, b) Atomic fragments (which may be deprecated in the near future) are also drooped and more importantly, c) RFC 7112 is actually implemented (actually, given the FreeBSD inheritance of pfSense, this was actually the case even before RFC 7112 was published).

 

But, what is the case when we try to reach a target behind the firewall itself (reminder: in the tested scenario ssh traffic to the target is allowed)?  The results are summarised below:

 

Extension Header                       Allowed

----------------                       ------

Hop-by-Hop header                     YES

Destination Options Header           YES

Fragmentation                            NO

Atomic Fragments                        NO

Type-0 Routing Header                 NO

Type 1, 2,3 Routing Header           NO

Layer 4 header in 2nd fragment      NO

(RFC 7112 implementation)

 

As we can see, the situation is even more strict now; fragmentation is also not allowed, which is certainly a good thing from a security perspective (the question is, if for any reason fragmentation over IPv6 is required, what can be the operational implications)?

 

To sum up, pfSense, in its latest release 2.2.1 a) does not offer any capabilities to customise IPv6 rules using IPv6 Extension headers (with the exception of IPSec ones) and, b) due to the FreeBSD inheritance, by default only very basic IPv6 Extension headers functionality is allowed, which does not include fragmentation.

 

What about if we want to customise our IPv6 rules regarding Extension headers? Well, it seems that for the time being, CLI and pfctl is the only option.

 

Have a nice day :) 

 

0 Comments