SAGE - Sage feature


TCPDUMP:
The Spanner Wrench of Network Monitoring

Cox

by Phil Cox
<pcc@ntsinc.com>

Phil is a member of the Computer Incident Advisory Capability (CIAC) for the Department of Energy. He also consults and writes on issues bridging the gap between UNIX and Windows NT.


Note: A spanner wrench is a tool that can do almost anything, if you have enough creativity. I used them while in the Navy.

I have been busy dealing with Denial-of-Service attacks during the last couple of months. A colleague of mine was tasked with writing a detector for the teardrop2 attack so people could determine if someone was running it against them. He did a great job, but then had to travel. I was tasked with "cleaning" it up and making it pretty. During the process, it occurred to me that I could do this same detection with a single tcpdump command line. This article is about how to leverage this flexible command to detect suspect packets on your network.

One assumption I have made is that the reader is familiar with IP/TCP/UDP packet structures, options, and flags. If this is not the case, this article might have some confusing spots in it. I highly recommend TCP/IP Illustrated, Vol 1, by W. Richard Stevens for those who need a more detailed reference and explanation.

Packet Formats

For reference, let's examine the formats of IP, TCP, and UDP packets[1]. See their respective RFCs for really gory details.

IP (RFC 791)

Bit

IP

TCP (RFC 793)

Bit

TCP

UDP (RFC 768)

Bit

UDP

Tcpdump Specifics

The default output for tcpdump is very sparse. In order to get the amount of data in the format we want, we use the -x and -s arguments. The -x output option displays the data in HEX using 2-byte chunks, so, for example, the first 6 bytes would be represented by three "chunks" like this: 0000 0000 0000. The -s option is the snaplen, which is the amount of data to capture from the packet. This value must be large enough to encompass all the fields we are looking for. tcpdump allows you to selectively look at data at the bit or byte level for a given protocol. The format for that selection is proto[expr:size][2], where proto can be one of the following: fddi, ip, arp, rarp, tcp, udp, or icmp, indicating the protocol layer for the index operation. The byte offset, relative to the indicated protocol layer, is given by expr. size, is optional, and indicates the number of bytes in the field of interest; it can be one, two, or four and defaults to one. Heads up on the value for the byte offset, expr, as tcpdump starts counting at 0, like C, so the third byte would be represented by the number 2. That's how to use tcpdump to get output. Now let's look at a key to decipher the output.

Mapping Packets to Hex Output from Tcpdump

Let's start with the IP portion of the packet header. The standard IP header has a length of 20 bytes[3] and thus will be represented by the first ten chunks of HEX output we will see from tcpdump. TCP or UDP headers take up the next 20 bytes (10 tcpdump HEX-chunks) or 8 bytes (4 tcpdump HEX-chunks), respectively[4]. On the opposite page is the breakdown of the tcpdump HEX-chunks, so we can understand what each HEX bit represents. (Note that all number ordering is Big-Endian, and if no position is defined, the entire field is assumed.)

A Specific Example

Once we have data, generated from tcpdump, and we know the packet format and have the mapping key, we can look for patterns we want to detect. Here is a sample of HEX output from tcpdump:

4500 00b2 4ea6 2000 8006 ee3f c0a8 4803
c0a8 4804 044c 008b 00e5 c3a2 43c1 cc20
5018 217f f6f9 0000 0000 0086 ff53 4d42
3200 0000 0018 0380 0000 0000 0000 0000
0000 0000 0028 feca 0048 42f1 0f42 0000

Let's break this output down into its component parts, in this case, IP and TCP headers. As we know from the packet format above, IP is first ten chunks: 4500 00b2 4ea6 2000 8006 ee3f c0a8 4803 c0a8 4804

Now we examine the individual chunk and break it into its packet fields, using the mapping key. Continuing on our example, we begin mapping to the fields, starting with the first of the ten packet header HEX chunks.
4500 IP version: 4 (Should always be 4, unless you run IPV6)
Initial header length : 5 (always 5, unless Options are present)
Type of Service : 0
00b2 Total IP packet length : 178 bytes (0xb2 = 178)
4ea6 Identification : 20134
2000 (hex) == 0010 0000 0000 0000 (binary)
Flags: More Fragments (bit 3) is set to 1
Fragment offset: 0 (means it's the first fragment)
8006 Time To Live: 128
Protocol: 6 (TCP=6, UDP=11)
eef3 header checksum 61171
c0a8 4803 = c0 a8 48 03
source address: 192.168.72.3
c0a8 4803 = c0 a8 48 04
destination address: 192.168.72.4

Because there are no IP options, the TCP packet starts next. As described previously, TCP, with no options, will occupy the next ten HEX chunks. From our example output, this is:

044c 008b 00e5 c3a2 43c1 cc20 5018 217f f6f9 0000

Just as with the IP portion, we break the TCP header chunks into fields, using the same mapping key. Beginning with the first of the ten TCP header chunks, we have:

044c
Source Port : 1100

008b
Destination Port : 139

00e5 c3a2
Sequence Number : 15057826

43c1 cc20
Ack Number : 1136774176
5018 (hex) == 0101 000000 0 1 1 0 0 0 (binary)
Offset : 5 (0101)
Reserved : (000000)
Urgent bit : 0
Ack bit : 1
Push Bit : 1
Rst bit : 0
Syn bit : 0
Fin bit : 0

217f
Window : 8575

f6f9
Checksum : 63225

0000
Urgent Pointer : 0

Because there are no TCP options, the TCP data would be the following chunks. Now that you have the hang of it, you could go as far as you desire in decoding the encapsulation of the packet, but I'll stop here.

Some Useful Applications

Armed with the mapping key and an understanding of how to use it, you should be able to identify any/all IP/TCP/UDP packet field values from the HEX output of a tcpdump session. What next? Well, let's say we want to capture all fragmented UDP packets (which is the basis for the teardrop exploit), but not the first fragment. To capture this type of packet, we could use the following tcpdump command line:

tcpdump -s 500 -x udp and '(ip[6]|0xdf = 255 and ip[6:2]&0x1fff > 0)'

tcpdump -s 500 grabs 500 bytes of the packet, which is more than enough to get the UDP headers. Next we ask for a peek at the HEX contents of the packet, as described earlier, with -x. Further, we specify UDP packets and apply some selective logic. Recall from the "Tcpdump Specifics" section, that tcpdump allows you to selectively look at data at the bit or byte level for a given protocol with the format of that selection being proto[expr:size]. So, ip[6] will correspond to the seventh byte in the IP packet. Referring to our IP packet format we see that the 8 bits in this byte correspond to the 3 flag bits and the first 5 bits of the fragment offset. From our mapping key, we know that the third flag bit is the more fragments bit. To mask the byte to select only packets with the More Fragments bit set, you can use a bit mask of 11011111 OR'd with the value in your byte. If it's = 255, the bit is set. Similarly, the fragment offset is represented in the fourth bit of the seventh byte of the ip header. It is a 13-bit field (5 bits remaining after the flag field, plus the next 8 bits). To detect if any of those 13 bits is set, we can AND the binary string 0001111111111111 (0x1fff) with ip[6:2] (i.e., 2 bytes' worth of the seventh byte of the IP packet). All told, a quick and dirty command line to look for miscreant, fragmented UDP packets.

Conclusion

With all the Denial-of-Service and other type of attacks that are roaming around the Internet, having a tool that is flexible enough to capture almost any IP data you can think of is of extreme value. Everyone needs the ability to detect attacks. Most systems I know of have a port of tcpdump, but not all have an Intrusion Detection System (IDS). tcpdump doesn't come close to replacing a proper IDS, but in a pinch, with an understanding of the attack, a creative tcpdump command line will go a long way.

Notes

[1] These diagrams were taken from the respective RFCs.

[2] See the tcpdump man page for more information.

[3] Currently, IP options are almost never used. If the Initial Header Length is not 5, then options are in use.

[4] This is only for the headers and considers that no TCP options are present.

Mapping Key

ChunkChunkPacket
NumberPositionField

IP Packet
1 1IP version number
2Initial header length, number of 32-bit WORDS
3-4Type of service
2Total IP packet length
3Identification
4Special case: You have to convert to binary
1first 3 bits are Flags
Bit 1: reserved
Bit 2: Don't Fragment bit
Bit 3: More Fragments bit
1fourth bit is part of Fragment offset
2-4Fragment offset (measured in units of 8 octets, 64 bits)
5 1-2Time To Live
3-4Protocol
6header checksum
7,8source address
9,10destination address
11 IF IP options are present, they would start here and end
on 32-bit boundaries (padded if needed).

** Otherwise (and most likely the case) this is the start of
the IP data

UDP Packet
11,12Source Port
13,14Destination Port
15Length
16Checksum
17 - nUDP Data

TCP Packet
11Source Port
12Destination Port
13,14Sequence Number
15,16Acknowledgment Number
17 1: Offset
2: reserved
3: Reserved and Bit flags
Bit 1,2: Reserved
Bit 3 : Urgent
Bit 4 : Ack
4
Bit 1 : Push
Bit 1 : Rst
Bit 1 : Syn
Bit 1 : Fin
18Window
19Checksum
20Urgent Pointer
21 ­ nTCP Data, unless TCP options


?Need help? Use our Contacts page.
7th August 1998 efc
Last changed: 7th August 1998 efc
Issue index
;login: index
SAGE home