TCP Sequence Numbers Explained

Today I was reading a new book on "intrusion detection and prevention" which repeats an often misinformed interpretation of TCP sequence numbers. The book said "When either party wishes to send data to the other, it will send a packet with the ACK flag set, with an acknowledgement of the last sequence number (in the Acknowledgement field) received from the remote host, and with its own sequence number incremented to reflect the amount of data being transmitted." This gets both the acknowledgement and sequence numbers wrong.

The following excerpt from my upcoming book The Tao of Network Security Monitoring explains how TCP sequence and acknowledgement numbers work by following a TCP session through Ethereal:

This brief section uses Ethereal screen captures to definitively explain TCP sequence numbers. 192.168.2.4 is a workstation named “caine” and 204.152.184.75 is ftp.netbsd.org, contracted to “netbsd” here.

Packet 1 shows a SYN from caine to netbsd. The TCP segment’s ISN is 1664882716. The hexadecimal shorthand is highlighted. Directly to the right of the ISN is a 4 byte value of zeroes. This is where the acknowledgement number would reside, if the ACK flag were set.



Packet 2 shows a SYN ACK from netbsd to caine. Netbsd sets a Initial Response Number of 829007135 and an ACK value of 1664822717. The ACK value is highlighted in the figure. ACK 1664822717 indicates that the next real byte of application data netbsd expects to receive from caine will be number 1664822717. That ACK value also indicates netbsd received a “byte of data” implied in the SYN packet caine sent, whose ISN was 1664822716. No bytes of data were actually sent. This is an example of a sequence number being “consumed” in the three-way handshake.



Packet 3 shows the completion of the three-way handshake. Caine sends an ACK 829007136, which acknowledges receipt of the one “byte of data” implied in the SYN ACK packet netbsd sent, whose IRN was 829007135. 829007136 indicates that the first real byte of data caine expects to receive from netbsd will be number 829007136. Again, no bytes of application data have actually been sent by either party. This is another example of a sequence number being “consumed” in the three-way handshake.



Packet 4 shows the first real bytes of application data sent from netbsd to caine. Netbsd still sends ACK 1664882717 because that is the sequence number of the first real byte of application data netbsd expects to receive from caine. Netbsd’s sequence number is 829007136, meaning the first byte of application data in packet 4 is numbered 829007136. That is the byte with hexadecimal value 0x32, which is ASCII 2 of the first digit in the “220” status code sent by Netbsd’s FTP service. You can see “32 32 30” in the line below the highlighted acknowledgement number in the screen capture.

Observe that this packet bears a sequence number indicating the sequence number of the first byte of application data in the packet. The value of this sequence number bears no relationship with the amount of application data in the packet. If netbsd sends 58 bytes or 580 bytes, it still uses sequence number 829007136, because that is the number of the first byte of data it promised to send to caine.

Ethereal reports the “next sequence number” to be 829007194. This value does not specifically appear anywhere in the packet. It is calculated by adding the number of bytes of application data in the packet (58) to the sequence number of the first byte of data in the packet (829007136). This does not mean the last sequence number of data in this packet is 829007194. Rather, the sequence number of the last byte of data is 829007193. How is this so? The following table tracks the sequence numbers of the bytes of application data in this packet.











Sequence NumberHex RepASCII
829007136322
829007137 32 2
829007138 30 0
829007139 2d -
...50 bytes omitted...
829007190 79 y
829007191 2e .
829007192 0d carriage return
829007193 0a new line

This fact probably accounts for most of the misunderstandings regarding the relationship between sequence numbers and byte counts of application data.



Packet 5 shows caine acknowledges receipt of bytes 829007136 through 829007193 from netbsd by sending ACK 829007194. This means the next byte of application data caine expects to receive from netbsd will be number 829007194. Caine’s own sequence number 1664882717 is unchanged as it has not yet sent any application data.



Packet 6 shows netbsd sending more data to caine. The “next sequence number field” is highlighted to show there is no corresponding real field in the TCP header of the bottom pane. The value 829008140 means netbsd sent 946 bytes of application data. Netbsd sets its sequence number as 829007194 to represent the first byte of data in this packet. The sequence number of the last byte of application data is 829008139. Its acknowledgement number remains at 1664882717 because caine still has not sent any application data.



Packet 7 shows caine acknowledges receipt of 946 bytes of application data with an ACK 829008140. This means the last byte of data caine received was number 829008139. Caine expects to receive 829008140 next from netbsd. Caine’s sequence number is still set at 1664882717 because it has not yet sent any application data to netbsd.



In packet 8 caine finally sends its own application data to netbsd. Caine transmits 11 bytes, starting with sequence number 1664882717 (0x55, or ASCII U) and ending with 1664882727 (0x0a, or new line). Caine’s acknowledgement number stays at 829008140 because that is the number of the next byte of application data caine expects from netbsd. Should caine send more application data, the first byte will be number 1664882728, as depicted in the “next sequence number” calculated by Ethereal.

As we saw earlier when netbsd sent application data, the sequence number carried in the packet is the number of the first byte of application data. Here it is 1664882717, which is what caine promised to send netbsd way back in packet 2.



Packet 9 shows netbsd acknowledges bytes 1664882717 through 1664882727 by sending an ACK 1664882728. Netbsd sends 45 bytes of its own application data, demonstrating that TCP allows acknowledging data sent by another party while transmitting new data to that party.



By now you should have a good understanding of how TCP sequence numbers work. We skip packets 10, 11, and 12 as they offer nothing new in terms of watching sequence numbers. Packet 13 begins the TCP “graceful close” or “orderly release,” by which each side of the conversation closes the session. We can inspect the one-line summary of the sequence and acknowledgement numbers in the next screen shot to follow the closing of the session.

Packet 13 shows netbsd terminates the session by sending a FIN ACK packet. Netbsd sets its ACK number at 1664882734, indicating it has received bytes of data through 1664882733 from caine. Packet 13 bears a sequence number of 829008199.

Packet 14 shows caine’s response, an ACK 829008200. This acknowledges receipt of the “byte of data” implied by packet 13 from netbsd. This is similar to the way sequence numbers were “consumed” during the three-way handshake to confirm acknowledgement of SYN and SYN ACK packets. Packet 14 is caine’s way of saying it received the FIN ACK from netbsd.

Packet 15 is caine’s own FIN ACK. Caine uses ACK 829008200, the same as it used in packet 14. Caine sets its own sequence number at 1664882734. Netbsd will use this as the basis for its own acknowledgement in packet 16.

Why doesn’t caine combine packets 14 and 15 into a single FIN ACK? The reason lies with the work being done at different levels of the OSI model. Packet 14 shows the TCP layer talking. By immediately replying with an ACK to netbsd’s FIN ACK, caine indicates its receipt of packet 13. Caine’s TCP/IP stack then needs to check with its FTP client application to see if it has any more application data to send. When the stack learns the FTP client is done with the session, caine sends its own FIN ACK in packet 15.

Packet 16 is netbsd’s acknowledgement of caine’s FIN ACK. Netbsd sets its ACK value to 1664882735, indicating it received the “byte of data” implied by packet 15 from caine. This is another consumption of a sequence number used to complete the TCP graceful close.



I hope this helps dispel the fog surrounding TCP sequence numbers.

Popular posts from this blog

Zeek in Action Videos

New Book! The Best of TaoSecurity Blog, Volume 4

MITRE ATT&CK Tactics Are Not Tactics