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.
I was recently asked what is the methodology that I follow to analyse protocols (like IPv6) for potential vulnerabilities, i.e. how can you perform a protocol security assessment. I thought that the answer might be interesting for other guys too and so, I decided to share my experience with you writing a short blog post.
For protocol analysis from a security perspective neither I use any standard fuzzers, as many people would expect, nor I review the source code of a specific implementation, if available (because this last approach would restrict my research to specific implementations only). However, I do agree that in some cases the use of fuzzers could also be useful. What I usually do can be summarised as follows:
First, I study thoroughly the corresponding standards (provided that these are available). Typically, open/public standards are defined in RFCs. Two notes here: First, you usually have to examine more than one RFC – there can be several related ones. All these must be identified, even drafts (because some implementations are described in draft RFCs). Secondly, you will probably need to revisit them several times [digesting them is not an easy process, at least not for me :-) ].
While reading them, try to identify “interesting” cases, that is, potential security issues or testing scenarios. Experience is really important at this step. Use your imagination. Create “what-if” scenarios (e.g. what-if a host constructs a packet not according to the standardised way – of course, you have to make it more specific). You should try to identify either protocol standardisation issues, or cases where a potential implementation may miss an important requirement.
While reading the specs, start building your own tool. You may expect that you will find an open-source available one, but in my experience even if there are available, they can hardly satisfy all your requirements or to address your testing scenarios and needs. You can always use an open source tool and modify it accordingly (contributing also to the corresponding project), but personally I find it easier and more convenient to start from scratch. Doing so you do not inherit potential code weaknesses, but, on the other hand, it requires good programming knowledge from you. Although I love C/C++, for this kind of tasks I prefer Python (and Scapy), just because it is easy :-)
After implementing the basic functionality in your tool, start implementing the features required to address the identified testing scenarios. Try to code your tool in such a way that becomes flexible, i.e. to be able to implement different testing scenarios without requiring too many code changes.
Except from your tool, you will also need a bunch of other tools, at least a network sniffer. I personally prefer wireshark (when I can have a GUI in a system) and tcpdump (for CLI sniffing). Good knowledge of their capabilities is mandatory. Using a sniffer you will be able to identify whether your tool constructs the packets as you expect (or not), how your targets respond, you can store the communication (e.g. in pcap files) for later review, etc.
Finally, you need a lab. Try to incorporate in your testing as many systems as possible, preferably popular ones (either open source, and if possible, commercial too).
Enjoy (testing)! But do not forget to keep detailed notes during the whole process.
I should note that all this aforementioned process is an iterative one, that is, it requires to re-visit the standards, identify new testing cases, implement them, test them, etc. Based on the initial outcome you may have new testing ideas, etc.
Hey, I never said that it is going to be easy. However, if you follow the above, you will end up with:
a. A good knowledge of the tested protocol and its implementation by various systems.
b. A tool (that you can make it available to the community).
c. A good report of a security assessment of a protocol (a write-up is always important). On its own can be a good publication.
d. If you are lucky (or good enough), you may identify a few vulnerabilities, either on specific implementations or on the protocol design itself. In such a case, please disclosure
Hope you have fun with this ;-)
Oh, one last requirement. You also need to find ...time. If you know a way how to buy some, please let me know (I have a list of protocols waiting…).
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).
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.
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 220.127.116.11 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 18.104.22.168, 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.
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 :-)
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.