Testing pfSense as an IPv6 Firewall - A Weird Case (Testing IPv6 Security Devices, Part 2)

pfSense is a clone of m0n0wall and, to the best of my knowledge, the eldest open source IPv6 firewall which is still maintained by its developers. Therefore, it should be expected that its maturity level should be good enough for normal usage.


The latest pfSense version currently available is 2.3.3, based on FreeBSD 10.3-RELEASE-p16.

pfSense provides the same capabilities with OPNsense regarding the IPv6 configuration of its interfaces, the deployment of DHCPv6 server, the sending of Router Advertisements and their configuration, etc. So, the only difference from an IPv6 configuration perspective between pfSense and OPNsense is the capability of filtering IPv6 Extension headers, which, nevertheless, does not seem to really work.

Read More





OPNsense as an IPv6 Firewall (Testing IPv6 Security Devices, Part 1)

As the Cisco Labs measurements show, IPv6 is a protocol that cannot be ignored any more. In some countries, like Belgium, Greece, Germany, the US, etc. the percentage of the users employing IPv6 is about 30% or even to 50%, and, based on the estimations, the increase of IPv6 traffic will continue to grow exponentially. So, it’s time to ensure that our firewall supports IPv6 as well.


While there are several open-source based solutions regarding firewalls, Linux-based or FreeBSD-based ones, this is not also the case when we want IPv6 support as well. Since m0n0wall project has officially ended, the only two options actually left for open-source users seeking for an iPv6 firewall are OPNsense and pfSense (if someone has an additional suggestion, please let me know).


Whilst pfSense supports IPv6 for quite a long time, as a firewall from a security perspective has a significant disadvantage: As of version 2.3.3 Community Edition it does not allow the filtering of IPv6 datagrams based on the used IPv6 Extension Headers. Therefore, if its administrator wants to filter e.g. IPv6 traffic carrying a Hop-by-Hop header, a Destination Options header, etc. (see [RFC 2460] for more details on IPv6 Extension headers), he simply cannot do it. And I do consider the capability of filtering IPv6 Extension headers really important for the reasons demonstrated here and here. In my opinion, this capability should be configurable.Therefore, I decided to give OPNsense a try since it seems to be the only open-source solutions that currently offers IPv6 Extension headers filtering capabilities.


Read More





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

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 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, 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.


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.






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



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.






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





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 :) 







How to Configure Snort to Stop IPv6 Evasion Attacks

During our BlackHat US 2014 talk titled "Evasion of High-End IPS Devices in the Age of IPv6", among others we discussed a Snort preprocessor rule (116:456) which, when enabled (not the case by default), triggers an alert when an IPv6 datagram with nine (9) or more IPv6 Extension Headers is used (such a header was used by us to evade Snort). However, we mentioned that:



a) This was not the best way to handle the risk of evasion by abusing IPv6 Extension Headers.


b) In theory there can be nine or more Extension Headers in an IPv6 chain (although in the real world I would be really surprised if we would see that number in production traffic).


Later, at our BlackHat EU 2014 talk with the detailed commands we used) we showed, in the course of our demos, how you can evade Snort by using up to five (5) IPv6 Extension Header per fragment, including the Fragment Extension Header. So, in this case the IPv6 Extensions Headers hard limit described above was actually useless.


When Snort was released on 23rd of October, a few days after BlackHat EU (coincidence?), in the changelog it was written that “a new config option `max_ip6_extensions` to change the maximum number of IPv6 extension headers decoded” was added. We do not know if this was a reaction to our comment about how Snort handles IPv6 Extension Headers during our first talk or, to the vulnerability disclosed in our second one (for which, by the way, we had informed promptly the Sourcefire/Cisco guys) but in either case, this was definitely good news. So, we decided to try it out.


First, let’s see how you can configure it. At the beginning it wasn’t that clear to me (but I am not the most experienced Snort user either); finally, I found out that you have to add a line like the following to the snort.conf file:


config max_ip6_extensions: 2


Using the aforementioned configuration option, when you send a datagram that contains more than two (2) IPv6 Extension Headers, the following WARNING is triggered:


01/11-16:40:33.391730  [**] [116:456:1] (snort_decoder) WARNING: too many IP6 extension headers [**] [Classification: Misc activity] [Priority: 3] {IPV6-OPTS} fe80::800:27ff:fe00:0 -> fe80::a00:27ff:fe74:ddaa


You can easily reproduce this by using the following Chiron command, which adds a Hop-by-Hop and two Destination Options Headers (please, do not forget to enable the 116:456 Snort preprocessor rule before testing it):


./chiron_scanner.py vboxnet0 -d fe80::a00:27ff:fe74:ddaa -sn -lfE 0,60,60


Of course, you can even minimise the amount of accepted IPv6 Extension Headers by changing the max_ip_extensions to zero (0), as following:

config max_ip6_extensions: 0


Using the latest configuration, a WARNING will be triggered even when just one IPv6 Extension Header is included in an IPv6 datagram. Of course, the number of maximum Extension Headers which each organisation or company will accept/allow in their network depends on their security policy and the IPv6 operational capabilities they want to deploy.


Is this the proper way to fix the security issue of evading Snort by abusing IPv6 Extension Headers? I believe not. The optimum solution would be to avoid evasion even when several IPv6 Extension Headers are accepted. But certainly, it is much better than before, especially taking into consideration that we do not expect to see (at least not yet) even more than one IPv6 Extension Header in Internet/WAN connections in the “real world”.

At the IPv6 Security Summit which will be held during Troopers 15 in the beautiful city of Heidelberg, Rafael Schaefer and I will have the pleasure to review and update the status of two high-end commercial IDPS devices (Tipping Point and Sourcefire) and two open-source ones, including Snort regarding their (in)ability to handle IPv6 Extension Headers properly.

See you all there :)






DHCPv6 Guard: Do It Like RA Guard Evasion

RA Guard Evasion is well-known in the IPv6 “circles”; there is RFC 7113 Advice for IPv6 Router Advertisement Guard (RA-Guard) and many interesting blog-posts like this one here, here, and this excellent write-up here that discuss this issue.
Moreover, as Jim Smalls states in his comprehensive “IPv6 Attacks and Countermeasures” presentation given at the North American IPv6 Summit 2013, DHCPv6 Guard or a corresponding IPv6 ACL can stop a DHCPv6 Rogue Servers, but (only?) for non-malicious/non-fragmented DHCPv6 packets (slide 35). However, at that time there wasn’t any known attack tool in the wild that had the fragmentation evasion built in.

Since I recently integrated a DHCPv6 server module at Chiron, which comes with IPv6 Extension Headers and arbitrary fragmentation built-in capabilities, I decided to try it at against Cisco IPv6 Snooping and DHCPv6 Guard (by the way, the new version of Chiron with the DHCPv6 built-in server capabilities will be released at the IPv6 Security Summit @ Troopers 15). My testing equipment was a Cisco Catalyst 3560-CG with Software Version 15.2(2)E.

First, I enabled IPv6 Snooping, as described by Christopher here (and for “normal” circumstances, as Christopher explains IPv6 Snooping is more than enough).

Then I checked that normal DHCPv6 Advertise messages are actually blocked. I started the Chiron DHCPv6 server as following:

./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1

It was confirmed that the rogue DHCPv6 Advertise messages are blocked, by using a Wireshark captures, checking that my client (Windows 8.1) didn’t get an IPv6 address, as well as from the Cisco debugging messages (a sample is displayed below):

Mar 30 02:34:04.062: SISF[CLA]: Interested feature:
Mar 30 02:34:04.062: SISF[CLA]:                 Snooping
Mar 30 02:34:04.062: SISF[SWI]: Gi0/1 vlan 10 Feature_0  Snooping priority 128
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10 DHCPV6_MSG_ADVERTISE XID 9B6B0F
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_IA_NA
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_CLIENTID
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_PREFERENCE
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_SERVERID
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_DNS_SERVERS
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10   DHCPV6_OPTION_DOMAIN_LIST
Mar 30 02:34:04.062: SISF[PRS]: Gi0/1 vlan 10           2001:DB8:1:1:C39C:2397:D1E7:5754  valid:600-pref:375s (ignored)
Mar 30 02:34:04.067: SISF[POL]: Vlan 10 matches vlan list on policy default
Mar 30 02:34:04.067: SISF[GLN]: Gi0/1 vlan 10 IPv6 snooping Gleaner setting sec level to 2
Mar 30 02:34:04.067: SISF[POL]: Vlan 10 matches vlan list on policy default
Mar 30 02:34:04.067: SISF[PRS]: Gi0/1 vlan 10 Sec level is Guard
Mar 30 02:34:04.067: SISF[PRS]: Gi0/1 vlan 10 Disallowed DHCP ADVERTISE: default action is drop message
Mar 30 02:34:04.067: SISF[GLN]: Gi0/1 vlan 10 Unauthorized packet
Mar 30 02:34:04.067: SISF[SWI]: Gi0/1 vlan 10 Feature Snooping rc 1
Mar 30 02:34:04.067: SISF[SWI]: Gi0/1 vlan 10 Feature drop

Then, I re-started DHCPv6 Chiron server by adding one IPv6  Destination Options header and fragmenting the datagram in two fragments. The corresponding Chiron command is the following:

./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -lfE 60 -nf 2


  1. No similar debug messages.
  2. Full DHCPv6 handshaking captured from Wireshark.
  3. Client got (and renewed later) its DHCPv6 address.

So, it seems that IPv6 Snooping regarding DHCPv6 Advertise/Reply messages can be circumvented in the same way as the RA Guard. Not very surprising, of course.

Next, I enabled DHCPv6 Guard without enabling IPv6 Snooping this time, just for testing purposes, as following:

L3SW(config)#ipv6 dhcp guard policy dhcpv6guard_pol

and then:

L3SW(config)#vlan configuration 10
L3SW(config-vlan-config)#ipv6 dhcp guard attach-policy dhcpv6guard_pol    

The results were the same. Rogue DHCPv6 Advertise/Reply messages are blocked as long as they are not fragmented.  In this test, I also confirmed that:

a) The IPv6 Destination Option Header can be at the unfragmentable part of the IPv6 fragments.
b) You do not need an IPv6 Extension Header at all (since, the DHCPv6 messages are long enough to be split in two fragments). So, something like the following still works:

./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -nf 2

Doing so, RFC 7112 is “satisfied” (since layer 4 header – UDP in our case – is in the 1st fragment).

After that, I tried to make it more difficult. I added an ACL rule that blocks the UDP traffic sent by the DHCPv6 server:

L3SW(config)#ipv6 access-list dhcpv6-protect
L3SW(config-ipv6-acl)#deny udp any eq 547 any eq 546
L3SW(config-ipv6-acl)#permit any any                                                                                                         


L3SW(config)#interface gigabitethernet0/1
L3SW(config-if)#ipv6 traffic-filter dhcpv6-protect in

Indeed, this ACL blocks DHCPv6 Advertise/Reply packets, but … only temporarily. If we add six (6) Destination Option headers and fragment it in 2 fragments, Chiron circumvents it again:

# ./chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -lfE 6X60 -nf 2
Prefix to Use is 2001:db8:1:1
The MAC address of your sender is: 00:24:54:ba:a1:97
The IPv6 address of your sender is: fe80::224:54ff:feba:a197
The interface to use is enp7s0
Source MAC address 00:24:54:ba:a1:97 Source IPv6 Address fe80::224:54ff:feba:a197
Starting sniffing…
Sniffer filter is ip6
DHCPv6 Solicit packet received with Transaction ID 13902187 from 08:00:27:68:02:b7
DHCPv6 Advertise packet sent with Transaction ID 13902187 to 08:00:27:68:02:b7 with IPv6 Address 2001:db8:1:1:ec53:a395:4d95:a54
DHCPv6 Request packet received with Transaction ID 13902187 from 08:00:27:68:02:b7
DHCPv6 Reply packet sent with Transaction ID 13902187 to 08:00:27:68:02:b7 with IPv6 Address 2001:db8:1:1:ec53:a395:4d95:a54
DHCPv6 Renew packet received with Transaction ID 2529640 from 08:00:27:68:02:b7
DHCPv6 Reply packet sent with Transaction ID 2529640 to 08:00:27:68:02:b7 with IPv6 Address 2001:db8:1:1:ec53:a395:4d95:a54



  1. For five (5) IPv6 Destination Options Extension Headers, Advertise/Reply messages are blocked. So, Cisco can count up to 5 :) ?
  2. Six (6) Destination Options and 2 fragments work despite of the fact that the UDP header is at the first fragment (please see the Wireshark screenshot displayed below – the UDP header is the yellow/light green ellipse).



Given the current situation, it seems that blocking fragmentation is the only way to mitigate risks like the aforementioned ones (blocking Extension Headers wouldn’t help, since we need some of them for other protocols, as for example the Router Alert option at the Hop-by-Hop Extension Header for MLD).

Finally, I also try to find out if evading DHCPv6 Guard AND the aforementioned ACL is feasible without using fragmentation. I tried several numbers of IPv6 Extension Headers; the maximum number of them is achieved by using the following Chiron command:

chiron_attacks.py enp7s0 -dhcpv6_server -pr 2001:db8:1:1 -lfE 0,164X60,43

The above command creates an IPv6 header chain by one hundred and sixty-four (164) Destination Option Headers, preceded by a Hop-by-hop header and followed by a Routing Type header (just to have some …variety). Unfortunately (?) no success this time.

We cannot add more Extension Headers without using fragmentation, because the size of the datagram gets bigger than the Ethernet MTU (1500 bytes) and hence, needs to be fragmented.

Btw (and unrelated to the DHCPv6 [Guard] discussion), just as a small side observation, Windows 8.1 happily responds even to the following packet (which uses 180 IPv6 Extension Headers!):

./chiron_scanner.py enp7s0 -sS -p 445 -d fe80::fc04:9f2b:68d0:5129 -lfE 0,178X60,43
The MAC address of your sender is: 00:24:54:ba:a1:97
The IPv6 address of your sender is: fe80::224:54ff:feba:a197
The interface to use is enp7s0
Starting sniffing…
Sniffer filter is ip6 and dst fe80::224:54ff:feba:a197 and not host 2001:470:20::2
System’s default gateway for interface enp7s0 not found, or there are two default gateways
If you need to use a gateway, you must define it on your own
Let’s start scanning
Press Ctrl-C to terminate before finishing
08:00:27:68:02:b7 fe80::fc04:9f2b:68d0:5129 00:24:54:ba:a1:97 fe80::224:54ff:feba:a197 TCP microsoft_ds 19400 SA
Scanning Complete!
IPv6 address                                                         Protocol    Port    Flags
[‘fe80::fc04:9f2b:68d0:5129′, ‘ TCP ‘, ‘microsoft_ds’, ‘SA’]


So, once again, actual testing helps to really evaluate the security posture of certain “well-known controls”…
See you at Troopers, take care






Should IPv6 Packets With Source Address ::1 Be Processed When Received on an External Interface?

Most of you are probably aware of the recently discovered/-closed severe ntpd vulnerabilities (CVE-2014-9293, CVE-2014-9294, CVE-2014-9295, CVE-2014-9296, see also the initial ntp.org security notice). Some days ago the Project Zero team at Google published a blog post “Finding and exploiting ntpd vulnerabilities” with additional details. In this one they mentioned a seemingly minor but quite important detail: on a default OS X installation one of the built-in protection mechanisms of ntpd (that is the restriction to process certain packets only if they are sourced on the local machine) can easily be circumvented by sending IPv6 packets with a spoofed source address of ::1 (the equivalent to in IPv4 which would be discarded by the kernel once received from an external source).

This brought up a number of more generic questions:

a) Should such packets having as source address the IPv6 loopback one be processed at all?
b) Which OSs process such packets?
c) How can we protect our systems from them?

Taking into account that a legitimate user or host has no reason to send packets to an external interface having as source address the IPv6 loopback one (::1/128), the answer to the first question is , in my opinion, “No”. Several services, like ntpd, listen by default to this address and so, if the underlying OS processes such packets, these services are reachable even if they are (should) not by other addresses. So, let’s try now to answer the second questions. Which modern OSs process such packets? For our study, the following OSs were tested:

  • Centos 6.6, 2.6.32-504.3.3.el6.i686
  • Windows 2012R2 64bit
  • FreeBSD 10.1-RELEASE #0 r274401 amd64
  • FreeBSD 8.4-RELEASE #0 r251259 amd64
  • OpenBSD 5.6 GENERIC#310 amd64
  • Centos 7, kernel 10.0-123.13.2.el7.x86_64
  • Fedora 20, 3.17.7-200.fc20.i686
  • OS-X Yosemite, version 10.10.1 (before and after applying the ntpd patch, just in case)


To keep things simple, I tried to use a network-wise way to find out if the discussed packets are processed or not. To this end, I used the following two steps.

  1. Send a TCP SYN packet to a port where there is a listening service (e.g. http, ssh, or smb, depending on the OS) by following the normal procedure (perform Neighbor Solicitation first before sending the TCP SYN packet).
  2. Send the TCP SYN packet by specifying manually the correct target and source MAC addresses, to avoid the Neighbor Solicitation process.

To verify that the packets were processed, I checked the following:

  • Whether there is a Neighbor Advertisement response to the Neighbor Solicitation packet.
  • Whether there is a TCP SYN-ACK, or TCP RST (for non-listening services) as a response to the TCP SYN packet.

To generate the spoofed packets, I used Chiron, and specifically its scanner module.

Let’s start with Centos 6.6. For the 1st test, I used the following command:

./chiron_scanner.py vboxnet0 -sS -d fe80::a00:27ff:fed1:d17a -p 80 -s ::1


vboxnet0 is the interface to use,

and fe80::a00:27ff:fed1:d17a is the link-local address of the target (I could use the global one too, but I wanted to make the test more generic).

The source MAC address of the attacker is 0a:00:27:00:00:00.

A screenshot of a Wireshark capture at the outer interface is displayed below:

Screenshot - 01042015 - 103515 PM

As we can see:

a) Chiron performs Neighbor Solicitation using as source IPv6 address the ::1 (packet 1)

b) Target responds to ::1 with a Neighbor Advertisement (but using the attacker’s MAC address as a destination address). => It processes the Neighbor Solicitation message directed to ::1 (packet 2)

c) Attacker (Chiron) sends a TCP SYN to ::1 (packet 3)

d) Target initiates its own Neighbor Solicitation to ::1 => processes the TCP SYN? (packets 4-6)

Obviously, there is no response to these last Neighbor Solicitation messages to ::1 and hence, no further communication.

Now, let’s continue with the 2nd test mentioned above:

./chiron_scanner.py vboxnet0 -sS -d fe80::a00:27ff:fed1:d17a -p 80 -s ::1 -tm 08:00:27:D1:D1:7A -m 0a:00:27:00:00:00

The corresponding Wireshark output is displayed below:

Screenshot - 01042015 - 104126 PM

As we can observe:

a) Chiron sends a TCP SYN to ::1 (directly to target’s MAC address) (packet 1).

b) The target sends a SYN-ACK to ::1 (packet 2)!

c) The target, using as source address the ::1, RESETs the connections since it never really initiated it. (packet 3)

The two tests above demonstrate that Centos 6.6 processes incoming packets from external interfaces having as source address the ::1/128.

To make a long story short, this was also the case for the rest of the tested Linux systems (Centos 7, Fedora 20). These Linux distros were chosen as representatives of different Linux kernel generations.
This was also the case for OS-X Yosemite, version 10.10.1 , both before and after applying the ntp patch (which, of course, patches just the ntpd vulnerabilities and not that OS-X processes IPv6 packets from external interfaces having as source address the ::1/128 one).
On the contrary, all the rest (FreeBSD tested variants, OpenBSD and Windows 2012R2) do not process them.
So, how serious is the aforementioned issue? Well, it allows an attacker to access and interact with a connectionless service (e.g. based on UDP) even if this listens only to localhost (and there are plenty of them out there!).

How can we mitigate this risk? In my humble opinion, the best way would be the Operating Systems not to process such packets. But, when this is not the case, an alternative is to use the host firewall.
For instance, using ip6tables, to allow the IPv6 localhost packets only for the loopback interface, you can do the following:

ip6tables -A INPUT -s ::1 -d ::1 -i lo -j ACCEPT

ip6tables -A INPUT -s ::1 -j DROP

The above ip6tables commands simply accept IPv6 packets having as source address the ::1 only when they are destined to ::1 and only using the loopback interface, while they drop all the rest. Simple, but effective.

As always, comments and questions are welcome.
If you are interested in all the nice things that can be done with Chiron (incl. the IDPS evasion stuff we demonstrated at Black Hat) it might be a good idea to join my half-day Chiron workshop in the course of the upcoming Troopers IPv6 Security Summit in Heidelberg on Mar 16th and 17th.

Have a great week






A “Please, Don’t Waste my Time” Approach and the Sourcefire/Snort Evasion

About two weeks ago we (Rafael Schaefer, Enno and me) had the pleasure to deliver our talk at BlackHat Europe 2014 named Evasion of High-End IDPS Devices at the IPv6 Era (by the way, latest slides and the white paper can be found here). In this talk we summarised all the IDPS evasion techniques that we have found so far. At previous blogposts I had the chance to describe how to evade Suricata and TippingPoint. In this post I am going to describe some other techniques that can be used to evade Snort, and its companion commercial version, Sourcefire. The tool used to evade these IDPS is –  what else – Chiron (Chiron can be downloaded here)

The versions that we used for our tests are the latest available ones at the time of this writing, that is:

  • Sourcefire, Model 3D7020 (63) Version (Build 48), VDB version 216.
  • Snort GRE (build 77), Registered User’s Release Rules.


As an “attacking” vector, for reasons of simplicity we considered the ICMPv6 Echo Request message. That is, we enabled the rule that detects such messages and we tried to deliver our packet without being blocked or triggering an alert (during our tests, Sourcefire was used inline while Snort in parallel).

In both devices we enabled some additional rules that come disabled by default in order to make our evasion attempts harder and, possibly, more realistic. To this end, we enabled the Preproc decoder rules GID 116 family and specifically, the ones with SID 458 (IPV6_BAD_FRAG_PKT), 272 and 273. These rules detect some of the attacks that have been reported in the past.

However, even doing so Sourcefire can be evaded by using the following arbitrary IPv6 header chain:

a. The unfragmentable part consists of three (3) Destination Option headers.

b. The fragmentable part consists of two (2) Destination Option headers plus the layer 4 header.

c. The aforementioned datagram is split in two fragments, as shown in the figure:


A Wireshark output of the above technique is displayed below:


We should note that when we enable the rule with SID:296 an alert is triggered (“DECODE_IPV6_UNORDERED_EXTENSIONS”) but there is no alert about ICMPv6 Echo Request (our “attack” itself). Furthermore the problem with this rule is that it also triggers alerts when fully legitimate and RFC compliant packets with IPv6 Extension headers are used (= false positives). Hence, there is a doubt whether this would be useful to a real working environment since it can rather confuse the intrusion analysts with the produced false alarms. So, this does not seem to be a realistic and effective way of detecting any kind of attacks when specific arbitrary IPv6 header chains are used.

However, the aforementioned technique does not work against latest Snort. Probably because latest Sourcefire is based on Snort 2.9.6, while latest Snort release is Anyway, we did not bother that much. We tried to find an evasion technique that works against Snort too. And here it is. To do so, the IPv6 header chain must consist of:

a. An unfragmentable part, which consists of a Hop-by-Hop header, a Type 3 Routing header and a Destination Options header.

b. A fragmentable part, which consists of a Destination Options header, the layer-4 header and its payload.

c. The fragmentable part is split in two fragments, as displayed in the next figure:


As you can easily notice, first, the latest technique is actually a variation of the previous one and secondly, this last case could be a fully legitimate combination of IPv6 packets (OK, unless RFC 7112 is implemented, of course). A final note: This last technique works also against Sourcfire.

Now, the sad side of the story.

We first tried to contact the Snort developers on 17th of June for reporting a previous issue. They asked us to send a pcap file, which we did. Unfortunately, we haven’t heard back from them yet. Then, we reported the aforementioned issue to Sourcefire on Sep 14th, as well as to Cisco on Sep 25 (since now Sourcefire has been acquired by Cisco),  including pcap files. Their reaction?

“If you are concerned about Sourcefire product, I suggest that you contact … customer support versus emailing … directly”

Well, sorry guys, but we just tried to help; we do not need any customer support. [for the record: we even tried that given we had some cases/tickets from an ongoing customer project, to no reasonable avail.]

On the contrary, we must say that during our tests and the process of discovering IDPS evasion techniques, the Suricata developers had always the fastest reaction (patching each reported issue in about a week) and, they also say …thank you. On the other hand, TippingPoint, when we reported to them two vulnerabilities, they preferred to patch them …silently.
Anyway, we are pretty sure that Snort and Sourcefire are going to fix these issues at some point. In the meantime, enjoy IPv6 ;).

For more info regarding the techniques and each specific case (including Suricata and TippingPoint), please check our white paper.