If you ever see a packet flying by on your network that has a SYN flag set and does not have a TCP options Maximum Segment Size (MSS) – you can be fairly certain that it was crafted. And, if it was crafted – it probably is for some nefarious purposes. There are other TCP options too that can be included, but most current well-known TCP/IP stacks list the MSS as the first of the TCP options in the TCP header. However, Solaris stacks do not follow this convention and may present some false positives if you include this check.
Another unusual condition that may be a reflection of a crafted packet or a poorly written TCP/IP stack is where a client SYN packet has a non-zero acknowledgement value. After all, the client has received nothing to acknowledge.To filter (SYN and !MSS) with tcpdump:
tcp[13] & 2 != 0 and ((tcp[12]/16 == 5) or (tcp[12]/16 > 5 and tcp[20] != 02))
- 'tcp[13] & 2 !=0' looks for the SYN flag set
- 'tcp[12]/16 ==5' looks for a TCP header length of 5. This is fairly convoluted because the value for the TCP header length is found in the high-order nibble so we must first divide by 16 to make it more logical (at least for me). Now, a TCP header length of 5 (32-bit words) means a conventional 20-byte TCP header with no options.
- There can still be TCP options, yet no MSS. The rest of the "and" clause examines that by finding TCP options where the TCP header length is greater than 5, and assumes that the MSS value appears first in the 20th byte offset of the TCP header with a value of 02.
!(tcp.options.mss) && (tcp.flags.syn == 1)
To find bogus packet with Wireshark (display filter):
tcp.flags.syn == 0 && (tcp.options.mss || tcp.options.wscale || tcp.options.sack)
tcp[13] = 2 and tcp[8:4] > 0To filter (SYN and non-zero ACK ) with tcpdump:
tcp.flags.syn == 1 && tcp.flags.ack == 0 && tcp[8:4] > 0