In my last blog I covered the theory of fragmentation. Just to remind you – our ultimate goal is to use Scapy to craft overlapping fragments. So far, we've seen how Scapy can create normal fragments and the composition of normal fragments. That will come in very handy when we create our overlapping fragments. The next topic we need to cover is checksums - specifically the checksum value in the transport layer protocol. This will be very relevant when we craft our overlaps.
First, checksums are a simple mechanism used to ensure that header and payloads in a datagram do not get corrupted in transit. There are several different checksums that all use the same algorithm. There is an IP checksum that is used to validate data in the IP header, and transport layer checksums such as TCP, UDP, and ICMP. They make sure nothing has gotten altered in the headers and data. The checksum involves taking the 16-bit one's complement of all appropriate fields for the particular checksum, adding those values, and placing them in a 16-bit checksum field in the relevant header. The receiving host performs the same checksum computation over the same fields and if the value matches the one in the header, that data is deemed unaltered. If the computed checksum value does not match, the packet is silently dropped.
So why should you care? And what the heck is 16-bit one's complement blah, blah, blah anyway? I like to think of it like an assembly language mnemonic of FDB – or flip 'da bits, akin to, but totally different from FNB – franks 'n beans. If the bit is 0, it is flipped to 1 and vice versa. The emphasis is that this is performed over 16-bit fields that are then summed. We'll come back to this later, but for now, just remember that the length of 16-bit or 2-byte values is important.
First, let me show you what happens when a bad ICMP checksum is introduced while crafting a Scapy packet.
The first packet is sent normally while the second one is sent with an erroneous ICMP checksum value of 12345. The output from each of the packets shows the checksums sent.
Now, take a look at the traffic captured by tcpdump. As you can see the first ICMP echo request received a reply because the ICMP checksum was valid. You also see that the second one received no response and tcpdump, when used with the –vv command line option, informs us of a problem with the ICMP checksum.
10.3.8.108 > 10.3.8.239: ICMP echo request, id 0, seq 0
10.3.8.239 > 10.3.8.108: ICMP echo reply, id 0, seq 0
10.3.8.108 > 10.3.8.239: ICMP echo request, id 0, seq 0 (wrong icmp cksum 3039 (->e3eb)!)
So, why am I going into all of these detail with checksums? We are going to create our overlapping fragments with the ICMP echo request shown below.
When we create our first fragment that contains the ICMP header, we need to supply it the exact checksum value above of 0xe3eb. Any other value for the existing payload will cause the fragments to be rejected by the receiver. Also, we need to keep the original and overlapping fragment payloads the same or nearly the same. Remember that the first fragment we create will have the ICMP header and a payload of "AABBAABB". Now, if we manage to successfully overlap this value, the receiving host will expose which of the two fragments it favored by supplying it in the payload of the ICMP echo reply.
First, if we intend to overlap that with another 8-byte fragment, it must yield the same checksum value for those 8 bytes. But, if we overlap the original one with the same value of "AABBAABB" then we can't possibly know which one the receiving host favored since the value returned in the echo reply will be the same. It turns out we have some wiggle room as far as what we can supply as a payload that yields the same checksum. Because checksums take 16-bit chunks, it is possible to have identical checksums when successive 16-bit values are sent, but in a different order. For instance, I ran some values through a checksum calculation and found the following:
checksum for AABBAABB is f8f8
checksum for BBAABBAA is f8f8
checksum for AAAABBBB is f8f8
checksum for BBBBAAAA is f8f8
The first fragment contains "AABBAABB" in the first 8 bytes. We can use any of the following three strings without altering the checksum. We'll use BBAABBAA in the overlap fragment. The diagram that follows depicts the packets that need to be crafted.
The first fragment has an IP header with an IP ID of 12345, the MF flag set, a fragment offset value of 0, a protocol value of 1 for ICMP. The ICMP header indicates it is an echo request and has the ICMP checksum value of 0xe3eb that we know works for the payload. This is followed by the payload of "AABBAABB". The overlapping fragment has a similar IP header, yet the fragment offset has a value of 1 meaning that this fragment falls 8 bytes into the payload. That just happens to overlap the offset of the data bytes "AABBAABB" of the first fragment. However, this time, we place of value of "BBAABBAA" – one of the strings that results in the same checksum result as "AABBAABB". We finish this off with a final fragment that contains a payload of "CCCCCCCC". This is the last fragment; it has an offset of 2 or 16 bytes into the payload. If a receiving host returns an echo reply with a payload of "AABBAABBCCCCCCCC", we know that the original fragment was favored. If it returns an ICMP echo reply with a payload of "BBAABBAACCCCCCCC", we know it favored the overlap.
There is another aspect of checksums that is important. I chose to use ICMP as the protocol to carry the overlapping fragments for two reasons. The first is that it requires less set-up time – any listening host on my network should respond with an echo reply. The second is that the ICMP checksum uses fields in the ICMP header and payload only. UDP and TCP are more complex because they involve something known as the pseudo-header that take some values from the IP header too, including the IP addresses, in the checksum computation for the protocol. What this means is if everything in a TCP or UDP packet is the same except, for example, the destination IP address, the protocol checksum changes. To explain this more clearly, I've crafted some packets in the Scapy interactive interface. In the first example, I've crafted two ICMP packets bound for two different destination IP addresses and displayed the ICMP checksums. They are the same value of 0xacef.
Next, I've crafted two UDP packets bound for two different IP addresses and displayed the UDP checksums. As you can see they are different, reflecting the inclusion of the destination IP address in the computation.
That wraps up what you need to know about checksums for the next and final post that will use the knowledge about checksums and fragmentation theory to show you how to craft overlapping fragments using Scapy.