In this tutorial we will learn how to read a packet header. It’s not very common to inspect packet fields, but it is important to know how to read and inspect packet fields manually in case you ever need to, for example if a new protocol that your sniffer doesn’t yet support forces you to depend on your manual analysis skills to examine the contents of packets.
This is the 3rd part of tutorials that speak about sniffing and manual packet analysis. Here are the 1st part and the 2nd part.
But before we go in depth in the core of this topic, we need to understand computer numbering systems.
Binary – base 2: From Wikipedia
“The binary numeral system, or base-2 number system, represents numeric values using two symbols: 0 and 1. More specifically, the usual base-2 system is a positional notation with a radix of 2. Because of its straightforward implementation in digital electronic circuitry using logic gates, the binary system is used internally by almost all modern computers.”
For more information, go to the Wikipedia page.
Decimal – base 10: From Wikipedia
“The decimal numeral system (also called base ten or occasionally denary) uses ten as its base. It is the numerical base most widely used by modern civilizations.”
For more information, go to the Wikipedia Page.
Hexadecimal – base 16: From Wikipedia
“In mathematics and computer science, hexadecimal (also base 16, or hex) is a positional numeral system with a radix, or base, of 16. It uses sixteen distinct symbols, most often the symbols 0–9 to represent values zero to nine, and A, B, C, D, E, F (or alternatively a–f) to represent values ten to fifteen. For example, the hexadecimal number 2AF3 is equal, in decimal, to (2 × 163) + (10 × 162) + (15 × 161) + (3 × 160), or 10995.
Each hexadecimal digit represents four binary digits (bits), and the primary use of hexadecimal notation is a human-friendly representation of binary-coded values in computing and digital electronics. One hexadecimal digit represents a nibble, which is half of an octet (8 bits). For example, byte values can range from 0 to 255 (decimal), but may be more conveniently represented as two hexadecimal digits in the range 00 to FF. Hexadecimal is also commonly used to represent computer memory addresses.”
Here is an example show how to convert between hexadecimal and binary numbers:
0xAFB8 = 1010 1111 1011 1000
Remember that 8 bits represents a single hexadecimal value, and 4 bits represents a single hexadecimal character.
For more information, go to the Wikipedia Page.
There are a few tips we have to consider before going deeper:
- Offset starts at 0
- 4 bits = 1 hex character
- 8 bits = 1 hex value
- Fields can be any length from one bit to many bytes and can be a fixed or variable length
- One layer’s header becomes another layer’s data
We will understand the importance of these tips later.
Here are hexadecimal formats of IP packets that we will decode:
4500 0034 c9e7 4000 3d06 178c d823 d2ba
ac10 00b7 0017 12f5 729a 2105 145c db4f
6018 16d0 a7cb 0000 0204 05ba 6c73 202d
This packet was captured with tcpdump packet sniffer that shows us the content of IP packets.
The 1st byte (offset 0) is “0x45” and the corresponding value for these fields are (“Version 4, IHL 5”) so the hex character “4” indicates that this packet uses IP protocol version number 4. For IP version 6 the content in this field will be 6, and the hex character “5” indicates IP header length. This tells us how long the IP header is in 32-bit words (4 bytes), so IP header length (4 * 5) = 20 bytes.
The 2nd byte (offset 1) is “0x00” and the corresponding value for the field is (“TOS”) Type Of Service. This field is one byte and is used to convey the priority for delivering this packet, so in this packet it is set to zero.
The 3rd and 4th (offset 2, 3) is “0x0034” and the corresponding value for these fields are (“packet length”). This field indicates the total length of the IP packet, and is represented in bytes, so 0x0034 hex is equal to 52 bytes.
The 5th and 6th (offset 4, 5) is “0xc9e7” and the corresponding value for these fields is (“IPID”). The IPID field is used to associate multiple fragments of packet that make up a single IP packet when reassembled, so “0xc9e7” is represented in decimal as 51687.
The upper 3 bits from the 7th byte is “0x40” and the corresponding value for these fields is (“IP header flag field”), 0x40 = 0100 0000, matching the upper 3 bits values to the order of the bit-fields in the IP flags field.
Bit 1 Reserved 0
Bit 2 Don’t Fragment 1
Bit 3 More Fragments 0
So as we can see there is no fragmentation in this packet.
The rest of the 7th byte and 8th byte are in decimal “0 0000 0000 0000” and the corresponding value for these fields is (“Fragment offset field”). Fragment offset field is used to show the receiving station how to reassemble all the fragments. In this case all values are zeros that indicate that this field is not set.
The 9th byte (offset 8) is “0x3d” and the corresponding value for this field is Time to live (“TTL”).The Time to live value is used to prevent infinite loops of packets. When the packet travels through any router the time to live (“TTL”) value will decrease by one, until it becomes one and then the router will drop the packet and send an ICMP error message. This is the idea behind Trace-route.
Time to live (“TTL”) value in hex is “3d” that represented in decimal is 61. TTL value is used to make Operating System fingerprinting, so from the TTL value we can assume the Operating System is Linux OS.
The 10th byte (offset 9) is “0x06” and the corresponding value for this field is (“Embedded protocol”), this field indicates the upper layer protocol for the IP packet payload, we use this packet to know what the upper protocol is. It could be TCP, ICMP, UDP, etc. Our Value in hex is “0x06” which indicates we will use a TCP protocol for this IP payload.
The 11th and 12th byte (offset 10, 11) are “0x178c” and the corresponding value for these fields is (“checksum”), checksum is used to make sure the received packet is the correct one and is not a corrupted packet.
Checksum is used to store 16 bits (2 bytes) one’s complement sum of IP header data. The checksum feature is not implemented as a security mechanism because it can be easily manipulated, but it’s used to identify accidental packet corruption. The checksum value in this case in hex format is (“0x178c”), in decimal 6028.
The 13th, 14th, 15th and 16th bytes (offset 12,13,14,15) are “0xd823d9ba” and the corresponding value for these fields is (“Source Address”). This is the IP source address (Sender IP address) and the corresponding dotted-decimal values for these hexadecimal values are 126.96.36.199.
The 17th, 18th, 19th and 20th bytes (offset 16,17,18,19 ) are “0xac1000b7”, and the corresponding value for these fields is (“Destination Address”). This is the IP Destination address (recipient IP address) and the corresponding dotted-decimal values for this hexadecimal value are 172.16.0.183.
Notice that we have finished IP header fields and now we will go to examine TCP header fields by using the same methodology.
The 21st and 22nd bytes (offset 20, 21) are “0x0017”, and the corresponding value for this field is (“Source Port”). This field represents the Source port number that is associated with the connection, but you should know that the client doesn’t choose which port to use while connecting with the server. Source port value in hex format is “0x0017” and the corresponding value in decimal format is port “23”. This port is usually associated with telnet protocol which indicates that the server is trying to connect to the client.
The 23rd and 24th bytes (offset 22, 23) are “0x12f5”, and the corresponding value for this field is (“Destination Port”). This field represents the destination port number that is associated with the connection. Destination port value in hex format is “0x12f5” and the corresponding value in decimal format is port “4853”.
As we notice that the telnet server tries to connect to the client application at port 4853, during our inspection of this packet we can learn more about it.
The 25th, 26th, 27th, and 28th bytes (offset 24, 25, 26, 27) are “0x729a2105” and the corresponding value for these fields is (“Sequence number”). Sequence number field is used in a TCP session to keep track of flow between a client and a server. In other words, when the recipient receives the sequence number and sends it back after incrementing it by one to the sender with the ACK message to inform the
sender that the packet is received. So if some packet doesn’t send correctly to the recipient, the recipient will send the last Sequence number received, so the sender will send them again.
The 29th, 30th, 31st, and 32nd bytes (offset 28, 29, 30, 31), are “0x145cdb4f”, and the corresponding value for these fields is (“ACK number”). The ACK number field is used to ensure the reliable delivery of TCP packets. The ACK number just holds the value of (sequence number +1) to inform the delivery of the packet So the sender makes sure the recipient has received the data correctly.
The first 4 bits from the byte number 33 (offset 32) is “0x6”, and the corresponding value for these four bits is (“header Len”). The hex character “6” indicates TCP header length, this tells us how long the TCP header is in 32-bit words (4 bytes), so the TCP header length (4 * 6) = 24 bytes.
The last 4 bits from the byte number 33 (offset 32) is “0x0”, these bits are reserved for future use, they should always be set to ZERO.
The byte number 34 (offset 33) is “0x18” and the corresponding value for this field is (“TCP flag field”). This field is used to determine exactly the purpose of the TCP packet by setting a bit-wise field. There are eight flags that can be set, they are:
bit one: Congestion window reduced (CWR)
bit two: Explicit Congestion Notification Echo (ECN-Echo)
bit three: Urgent Pointer is valid (URG)
bit four: Acknowledgement Set (ACK)
bit five: Pass Data to Application ASAP (PSH)
bit six: Reset the Connection ( RST )
bit seven: Synchronize Set ( SYN )
bit eight: Sender if Finished (FIN)
So when mapping our eight bits with these flags:
C :: E :: U :: S :: P :: R :: S :: F
0 0 0 1 1 0 0 0
As we can see, PSH and ACK flags are set.
The 35th and 36th bytes (offset 34 and 35) are “0x16d0”, and the corresponding value for these fields is (“Window Size”). The window size field is used to indicate the number of bytes that can be transferred to the destination. The TCP window size fields values in hexadecimal format is “0x16d0” and the corresponding values in decimal format is “5840”.
The 37th and 38th bytes (offset 36 and 37) are “0xa7cb” and the corresponding value for these fields is (“checksum”). Checksum is used to make sure the received packet is the correct one and not a corrupted packet. The checksum feature is not implemented as a security mechanism because it can be easily manipulated, but it’s used to identify accidental packet corruption. Checksum value in this case in hex format ia (“0x178c”), in decimal 42955.
The 39th and 40th bytes (offset 38 and 39) are “0x0000” and the corresponding value for these fields is (“Urgent PTR”). Urgent PTR is used to point to the location of the urgent data to the recipient machine, and as you can see it’s not set.
Notice that the TCP packet header without extra options is 20 bytes (5 of 32 bit word), but in this packet we find that the TCP header was 24 bytes (6 of 32 bit word), so we can determine the options size which is 4 bytes (24 bytes – 20 bytes).
The 41st, 42nd, 43rd and 44th bytes (offset 40, 41, 42 and 43) are “0x020405b4” and the corresponding value for these fields is (“TCP Options”). The first byte “0x02” indicates a specific option is set, which is Maximum Segment Size (MSS), and the next byte “0x04” represents the number of bytes for this option, and the last two bytes “0x05b4” indicate the maximum transmission unit size which is 1500 bytes.
The rest of the bytes in this packet are the data payload and when we convert them from hexadecimal format to ASCII format, the result will be “ls -al”, which is a Linux command.