## Friday, August 12, 2016

### Calculating Seq & Ack Numbers in Packets

I thought it'd be interesting to walk through a Wireshark PCAP packet capture and see if I can explain how certain fields like the Lengths, Sequence, Ack #s, etc. were calculated. It involves a client (10.8.8.101) making a single HTTP GET request to a web server (108.60.15.36) over port 80 and getting an HTTP 200 success response back. Note this PCAP originated from the awesome Malware Traffic Analysis blog and is a real capture from the locky malspam @malware_traffic analyzed.

The first 3 packets above are the initial TCP handshake.

1.) You see a SYN from the client (10.8.8.101, flag 0x0002) saying 'hey server i want to talk to you'. The Seq and Ack #s are not used yet. The Total packet is 66 bytes. The ethernet header is always 14, thus the remainder (66-14 = 52) is IP Total Length is 52. Since the IP header is 20 that leaves (52-20 = 32) left for TCP packet. Since the TCP packet only contains a header of 32, that means that there is no tcp payload in this packet (32-32=0) which makes sense since it's the initial SYN.

2.) The server responds with a SYN-ACK (108.60.15.36, flag 0x0012) saying 'hey client i received your syn'. The Seq # is still not used yet, but the Ack # is incremented to 1 because the prior received packet contained a SYN. The Total packet is 60 bytes. There are 14 for ethernet again so 60-14=46 for IP. But notice the IP total header says 44. That means that the remaining 46-44=2 bytes are just 0 padding because the Ethernet frame has a minimum size it must be. Since the IP header is 20 and the we know (44-20=24) is the size of the TCP packet. Since the TCP header takes up all of the tcp packet (24-24=0) we again have no tcp payload.

3.) The client then response with an ACK (flag 0x0010) saying 'hey server i got your syn-ack, lets start talking'. The Seq # is now increased by 1 because of the prior received packet containing a SYN. The Ack # stays untouched at 1 right now. The Total packet is 60 bytes (14 for ethernet, 44 for ip frame). Since the IP header is 20 and the we know (44-20=24) is the size of the TCP packet. Since the TCP header takes up all of the tcp packet (24-24=0) we again have no tcp payload.

The next several packets are the actual application layer HTTP GET request.

4.) You see that application layer traffic starting now that the TCP handshake is complete. This is an HTTP GET request, so the client requesting a web page from the server. It is a PSH/ACK (flag 0x0018), all packets go forward during normal communication with contain an ACK, and the PSH is to indicate that the client is ready for data. The Seq # and Ack # both stay at 1 for this initial request since no data was actually transferred yet. You'll notice the total packet is 408 bytes this time though. The Ethernet Header is 14 and the IP total length is 408-14=394. Then in the IP packet the header is 20 meaning the rest of it (the tcp packet) is 394-20=374. And in the TCP packet the tcp header is 20 meaning the tcp payload (which in this case is an HTTP GET is 374-20=354 bytes). If you were to look in the Packet Bytes in wireshark for this packet you'd see actual HTTP Request Headers like the host host, useragent, etc.

5.) This next packet is the Server simply Acknowledging that it received the HTTP GET request. Notice it's an ACK (0x0010) for acknowledgement. Also notice the total length is small again, only 60 bytes. Take out the 14 byte ethernet header and you get 60-14=46 bytes for rest of IP. But notice again it says the total IP length is only 40 so that means 46-40=6 bytes of zero padding has been added to the end to fill out the Ethernet frame. Take out the 20 byte IP header and you get 40-20=20 bytes for TCP. Take out the TCP header and you get 20-20=0 bytes of actual TCP payload. There is none since this is just the acknowledgement. Notice the Sequence # stayed at 1, but the Ack # actually increased. If you recall from the previous packet we said the TCP total length was 354. Thus the Acknowledgement # because 1+354=355 because it's the server saying 'hi client, i acknowledge I have now received a total of 355 bytes from you'.

6.) Next you'll see the web server continue with it's 2nd packet in a row ... actually responding back to the client's GET request with some data, so it's going to get interesting now. See how the total length is 1514 bytes. Take out the 14 byte ethernet header and you get 1514-14=1500 bytes of IP. Take out the 20 byte IP header and you get 1500-20=1480 bytes of TCP. Take out the 20 bytes of TCP Header and you get 1480-20=1460 bytes of TCP payload (or in this case actual HTML code getting returned by the web server in response to the HTTP GET request for a specific page). If you were to look in the packet bytes of wireshark for this packet you'd see actual HTML code like the HTTP Response headers and perhaps an HTML or BODY tag eventually here soon. Now notice that the Ack # stayed at 355 because the Server has not received any more data from the client and the Seq # stays at 1 because no data has actually been received by the client prior to this packet yet.

7.) Next it's a kinda interesting normal occurence in TCP. The Server (108.60.15.36) had received the HTTP GET request prior and now is ready to start firing off packets back to the client in small chunks in order to send back the entire large HTTP response. The server isn't necessarily going to wait for the client to Acknowledge every packet, but instead the Server is going to start firing off a bunch of packets. Thus in the case we are going to see the server send 2 packets of http data before the client even Acknowledges it received some (in packet #8). This thus is similar to packet #6. It's a PSH/ACK with data (0x0018) the ACK because there is data in this payload and the PSH because the Server is saying he's ready to receive data from the client. The total length of the packet is 1308. If you remove the 14 for the ethernet header then 1308-14=1294 for IP. Then the IP header is 20 so 1294-20=1274 bytes for the TCP. Then take away the 20 bytes TCP header then 1274-20=1254 bytes for the TCP payload (which is more HTML code in the HTTP response). So you can see that the Ack # stays at 355 because the data received by the server has not changed, but the SEq # has increased to 1+1460=1461 bytes as the server is saying 'hey client i've now sent you 1461 bytes of data'.

8.) So this is the client finally sending an ACK (0x0010) back to the server saying 'hello server i acknowledge i received your first 2 packets of data'. You'll notice the total length is small at 60 bytes again because this is just an ACK. The Ethernet header is 14 so 60-14=46 again for IP. But since it says the IP total length is only 40, then we get 46-40=6 bytes of zero padding for the Ethernet header minimum size. Then again the ip header is 20 so 40-20=20 bytes remaining for TCP. And the TCP header is 20 so 20-20=0 bytes for the actual tcp payload which makes sense again since this is just the tiny quick Acknowledgment packet. The Seq # is set to 355 because the client is saying 'hi server just so you know I have sent 355 bytes if tcp payload to you so far'. The Ack # is now pretty large at 1+1460+1254=2715 bytes of TCP payload, saying 'hi server i have so far receiving 2715 bytes of tcp payload from you.'

9-360.) Packets 9 thru 360 are a repeat of 6 thru 8 over and over again. The server sends 1 or 2 packets of data. The client Acknowledges the data it received. Each time the client's Ack # keeps increasing by the # of TCP payload bytes it received so that it's telling the server 'hey i have so far received X # of bytes from you successfully.' And the server's Seq # keeps increasing by the # of TCP payload bytes it sent so that it's telling the client 'he i have so far sent Y # of bytes to you.'

361.) Now in Wireshark packet #361 looks different because it says HTTP/1.1 200 OK. But you'll notice from the wireshark snippet above that Wireshark is just being smart and "re-assembling" all the TCP (HTTP Response) payloads together to give you an easy to read understanding of the HTTP Response which in this case was a 200 success meaning everybody was happy. This particular packet is actually otherwise essentially the same as packet #7 for example as it's just more TCP payload data (HTTP Response) with a PSH/ACK flag. The only difference is that this is the "last one" in the sequence. Note in this packet that it's 1001 total bytes. If we take out the 14 byte ethernet header there's 1001-14=987 bytes for IP. Take out the 20 bytes IP header and we have 987-20=967 bytes for TCP . Take out the 20 byte tcp header and we have 967-20=947 bytes of tcp payload (the final portion of the HTTP Response). You'll notice the ack # is still 355 because the server is saying 'hey client just so you know i've still only received 355 bytes from you' but you'll notice the Seq # is now huge at 280900 because the server is saying 'hey client i have now sent you a total of 280900 bytes.'

362.) This next packet is nearly identical to what we described in packet #8. It's the client's Acknowledgement of the Server sending data again. Notice the Seq # is still 355 saying 'hey server i have sent you 355 bytes so far' and the Ack # is 280900 saying 'hey server i have received 280900 bytes from you so far successfully'. This is actually the acknowlegement of packet #360 (not #361).

363.) This packet is the acknowledgment of the final server packet #361. You can tell because the Ack # has jumped to 280900+947=281847 bytes of total TCP payloads thus the client saying 'hey server i have received successfully now 281847 bytes of tcp payload from you.'

364.) Finally we get to a graceful teardown. The server sends a FIN/PSH/ACK (0x0019) basically telling the client, I have nothing more to send to you (FIN), I'm ready for data back from you now (PSH). Notice the server has a Seq # of 281847 because it's saying 'hey client i have sent you 281847 bytes of tcp payload data now' and the ack # is still 355 because it's saying 'hey client i have still only received 355 bytes of tcp payload data from you'. The packet is a small one again because it's just a teardown. 60 bytes total, take away 14 for the ethernet header leaves 60-14=46 for IP. But since the IP total length only says 40 then 46-40=6 bytes of zero padding in the ethernet header again. Then 20 bytes for the ip header leaves us with 40-20=20 bytes for the tcp packet. And 20 bytes of tcp header means there are 20-20=0 bytes of tcp payload in this.

365.) The client now acknolwedges (ACK 0x0010) that the FIN teardown request was received. Since the prior packet contained a FIN the ack # increases by 1 to 1+281847=281848.

398.) Now notice the gap in wireshark # (365 to 398) , this is because there is a larger time delay between the last packet and this one. This is basically the client finishing up whatever it was doing and saying ok I have nothing more to send you (FIN) either.

399.) Finally the server Acknolwedges the client's request to teardown (FIN). Notice since the prior packet request contained a FIN then the Ack # increases to 1+355=356. The conversation is done.