I was doing some testing this week and needed to craft some overlapping fragments. Though I did some extensive work and research of overlapping fragments about 5 years ago when I worked at Sourcefire, I have not revisited crafting overlapping fragments in the interim. At the time, I used Perl modules and support since Scapy was not around at the time and/or I was not familiar with it. Ultimately, I'm going to show you how to craft overlapping fragments using Scapy. Frankly, the Scapy code itself is pretty simple; the knowledge of TCP/IP is more challenging. I'm going to do multiple posts to explain all the necessary concepts to craft overlapping fragments.
It's embarrassing to admit that I forgot many of the issues associated with fragmentation. First, you have to understand fragmentation – what happens to some fields in the IP header, the protocol header, and the data. While Scapy has excellent support for normal fragmentation – i.e. no overlaps, you need to understand the theory of fragmentation to properly craft your own atypical fragments.
As if this is not complex enough, you also have to understand the role of checksums in general, and more specifically at the transport layer to make the packet acceptable to the receiver. Scapy usually takes care of all the checksum details for you and you don't have to understand them or bother with them. But, when we craft overlapping fragments, we are responsible for computing and supplying a valid protocol layer checksum.
This first blog concentrates on the creation and composition of normal fragments. Additional posts will address the issue of the protocol layer checksum and finally how to use Scapy to craft overlapping fragments.
Usually, fragmentation occurs when an IP datagram is larger than the link layer it needs to traverse. For instance, the Maximum Transmission Unit (MTU) for Ethernet is 1500 bytes. If a datagram is larger than 1500 bytes, it must be fragmented into multiple associated datagrams. However, if we're doing the crafting and fragmenting, we can craft fragments from far smaller datagrams than 1500 bytes.
Assume we have a datagram depicted in the diagram that follows. It is an ICMP echo request with 16 bytes of data. The datagram is composed of a standard 20-byte IP header, followed by an 8-byte ICMP header with a type value of 8 and a code value of 0 to indicate it is an ICMP echo request, followed by a 16-byte payload. Some of the pertinent IP header fields have been listed using Scapy output. Specifically, this IP header has a unique identifying value in the IP ID field of 12345. No fragment-associated flags are set; this is the 0-offset fragment, but since no fragment flags are set, this is not really relevant. And, the protocol that follows is ICMP.
If this datagram were to become fragmented, all created fragments are associated by the common16-bit IP ID value of 12345. The More Fragments (MF) bit flag indicates that there are other fragments that follow. This bit is set for all fragments except the final one. Finally, the offset represents the displacement of the fragment with regard to all other fragments. It adds the notion of chronology of the fragments so that the receiver can reassemble them after they arrive. The offset is represented as an 8-byte multiple of where the fragment resides relative to the beginning of the original unfragmented datagram. We'll revisit this later in this blog when we examine some fragments.
Now, suppose we wanted to split this datagram into 16-byte fragments. What would happen?
First you have to understand that every fragment has an IP header otherwise there would be no way to get it to the destination. The original IP header is pretty much "cloned" except for the MF flag and the fragment offset values. A 16-byte fragment means 16-bytes of data after the original or cloned IP header. We don't fragment the IP header itself – that remains intact. The actual fragmentation occurs to the data following the IP header. In this case, that means the 8-byte ICMP header plus 8 bytes of the ICMP payload "AABBAABB" constitute the first fragment. Now, there are only 8-bytes of remaining ICMP payload "CCCCCCCC" for the 2nd and final fragment.
I created a Scapy program to fragment the original datagram displayed in the first diagram. It first creates the packet, shows the values of some fields in the the packet, creates 16-byte fragments, and loops to show the fragment data and then send the packets.
Let's examine the fragments that the program created. The first one is depicted below with the relevant associated datagram fields and values.
The Scapy output for the first fragment indicates that the length of the new datagram that holds the first fragment is 36 bytes – 20 bytes of IP header, 8 bytes of ICMP header, and 8 bytes of data. The original IP ID of 12345 is the identifier for associated fragments, there are more fragments that follow, this is the 0-offset fragment, and the protocol is ICMP. The ICMP header shows a type of 8 and code of 0 for an echo request and an ICMP checksum that reflects that ICMP header and payload. We'll revisit the checksum in a later blog post. But remember this must be correct; otherwise the receiving host will drop it. Scapy computes the checksum for us when we use the Scapy "fragment" function. Finally, we see the payload of "AABBAABB".
Now, let's look at the second fragment that Scapy created.
It has a similar IP header as the first fragment, sharing the IP ID number, but the MF bit is set to 0 since no more fragments follow. The fragment offset is 2. This is the offset in the original unfragmented datagram where the "CCCCCCCC" falls. It is located at 16 bytes offset from the data that follows the IP header. There are 8 bytes of ICMP header and 8 bytes of data "AABBAABB" found in the first fragment. The value in the IP header is expressed in terms of 8-byte multiples – therefore a value of 2 means 16-bytes. This is a legacy storage space savings from when data transfer rates were far slower and using a bit or two less space in the header was considered pragmatic. The associated protocol is ICMP.
No doubt you've noticed there is data only that follows the IP header. The ICMP header is not repeated; the protocol layer that follows the IP header is part of the first fragment only. The length of 28 in the IP header reflects this 20-byte IP header followed by 8 bytes of data. When the receiving host gets all fragments associated with IP ID 12345 it orders them according to offset and knows it has received all the fragments when there are no gaps and the last fragment has been received. In this case, the receiving host responds with an ICMP echo reply that contains a payload of "AABBAABBCCCCCCCC" meaning that these were well-formed wholesome packets. When we craft our own overlapping fragments, we'll use the data contained in the receiver's ICMP echo reply to learn which of the overlapping fragments it favored.
Stay tuned for future posts.