A SYN scan is, maybe, one of the simplest stealth port scanning techniques you can think about. There are some claims around the Internet about how it works and I was curious to know more about thats. This post summarises my findings.
Recently I had to look into the details of port scanning and I started looking into the SYN Scan, as being one of the simplest, so-called stealth, port scanning techniques. The idea is very simple and it is very well explained in many places in the Internet. Let's just repeat it here for completeness.
There you go. I bet this is the noisy thingy. It is at application level and it is the application who actually logs the IP. I will try an IDS (e.g. The
You will read in many places around the Internet that a
So, the
■
SYN Scan
Roughly, a SYN Scan works initiating a normal TCP connection but not completing the TCP three-way-handshake. A normal connection looks like this:SOURCE DESTINATION SOURCE DESTINATION +-------- SYN -------> +-------- SYN -------> <------ SYN | ACK ----+ <-------- RST -------+ +--------- ACK --------> OPEN PORT CLOSED PORTA SYN Scan, will send the
SYN
packet normally, but it will never send back the ACK
to complete the connection (in the case that the port is open).
What happens is that, we know the estate of the remote port just after receiving the first packet from the destination. If it is a SYN|ACK
, the port is Open and we do not really need to complete the three-way-handshake. In other words we do not need to send the last ACK
packet. If we receive a RST
, then the port is closed and we are done.
A real port scanner like nmap
, considers a few more cases: Filtered packets not returning anything and host/networks unreachable errors manifested as ICMP
packets received back by the port scanner. However, all this is very well explained in many different websites and I will not go further into those topics.
The Claims
Despite of the very good explanation on how the SYN scan works, I have found a couple of common sentences all around the Internet that are not fully explained in detail, but taken for granted by everybody. This is what I want to cover in this paper. Specifically the claims I'm looking at are:- A connect scan is much noisy than a SYN scan.
- The scanner (e.g.
nmap
) send aRST
packet after receiving theSYN|ACK
- You can be DoSed if you do not send that last
RST
packet
The Noisy Connect Scan
The first claim is that a SYN scan is a less noisy that a full connect scan. This is completely true but... what does it really mean?. After looking around for some time the conclusion I reached is that this is not as sophisticated as it may sound. To illustrate this claim, let's make use of a small server program:#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main (int argc, char *argv[]) { struct sockaddr_in server, client; socklen_t len = sizeof (struct sockaddr_in); int s,s1; server.sin_addr.s_addr = INADDR_ANY; server.sin_family = AF_INET; server.sin_port = htons(9000); s = socket (PF_INET, SOCK_STREAM, 0); bind (s, (struct sockaddr *) &server, sizeof (server)); listen (s, 10); while (1) { s1 = accept (s, (struct sockaddr *)&client, &len); printf ("Connection from %s\n", inet_ntoa (client.sin_addr)); write (s1, "Hi!\n", 4); close (s1); } return 0; }This is a typical server program, that greets any client and.... LOGS its IP. The server can only get the IP of the client once the
accept
system call returns and that only happens whenever the connection is fully established.
Let's see how our server behaves when scanned using a connect scan and a SYN scan.

Connect and SYN scan on our test server
snort
), but I will expect that an IDS can detect both scans without problems.
Let's move on
The RST
Packet
You will read in many places around the Internet that a SYN
scanner has to send a RST
packet at the end. This claims comes from the fact that you will always see that packet if you sniff the traffic when doing a scan.
Just start up you preferred sniffer, and scan one single port you know it is open in your machine (alternatively, start a netcat listening in some port `nc -l 10000`). You will see something like:

SYN Scan as seen by Wireshark
RST
packet seems to be sent but... it is not sent by the port scanner. The easiest way to verify this is to strace
nmap
and see what it is actually sending. (Alternatively use the --packet-trace
flag):
Stracing NMAP
Let's see what we will get:$ sudo strace -e trace=network -x -s 1024 -f nmap -sS 127.0.0.1 -p 22 socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3 connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory) socket(PF_FILE, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3 connect(3, {sa_family=AF_FILE, path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory) Starting Nmap 5.21 ( http://nmap.org ) at 2016-11-04 14:36 CET socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3 socket(PF_INET, SOCK_RAW, IPPROTO_RAW) = 3 setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0 setsockopt(3, SOL_IP, IP_HDRINCL, [1], 4) = 0 socket(PF_PACKET, SOCK_RAW, 768) = 4 bind(4, {sa_family=AF_PACKET, proto=0x03, if1, pkttype=PACKET_HOST, addr(0)={0, }, 20) = 0 getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 setsockopt(4, SOL_PACKET, PACKET_AUXDATA, [1], 4) = 0 getsockopt(4, SOL_PACKET, PACKET_HDRLEN, [28], [4]) = 0 setsockopt(4, SOL_PACKET, PACKET_VERSION, [1], 4) = 0 setsockopt(4, SOL_PACKET, PACKET_RESERVE, [4], 4) = 0 getsockopt(4, SOL_SOCKET, SO_TYPE, [3], [4]) = 0 getsockopt(4, SOL_PACKET, PACKET_RESERVE, [4], [4]) = 0 setsockopt(4, SOL_PACKET, PACKET_RX_RING, {block_size=4096, block_nr=518, frame_size=176, frame_nr=11914}, 16) = 0 socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 5 setsockopt(4, SOL_SOCKET, SO_ATTACH_FILTER, "\x01\x00\x00\x00\x00\x00\x00\x00\x68\x93\xa3\x6e\x28\x7f\x00\x00", 16) = 0 recvfrom(4, 0x7ffc637e32af, 1, 32, 0, 0) = -1 EAGAIN (Resource temporarily unavailable) setsockopt(4, SOL_SOCKET, SO_ATTACH_FILTER, "\x36\x00\x49\x00\x00\x00\x00\x00\xb0\x82\xbf\x01\x00\x00\x00\x00", 16) = 0 sendto(3, "\x45\x00\x00\x2c\x59\x23\x00\x00\x35\x06\x2e\xa7\x7f\x00\x00\x01\x7f\x00\x00\x01\xeb\xc2\x00\x16\x0f\x66\x60\x1b\x00\x00\x00\x00\x60\x02\x08\x00\x36\xca\x00\x00\x02\x04\x05\xb4", 44, 0, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("127.0.0.1")}, 16) = 44 setsockopt(4, SOL_PACKET, PACKET_RX_RING, {block_size=0, block_nr=0, frame_size=0, frame_nr=0}, 16) = -1 EBUSY (Device or resource busy) Nmap scan report for localhost (127.0.0.1) Host is up (0.00028s latency). PORT STATE SERVICE 22/tcp open ssh Nmap done: 1 IP address (1 host up) scanned in 0.13 secondsWell, you can analyze the whole trace, but the relevant line is this:
sendto(3, "\x45\x00\x00\x2c\x59\x23\x00\x00\x35\x06\x2e\xa7\x7f\x00\x00\x01\x7f\x00\x00\x01\xeb\xc2\x00\x16\x0f\x66\x60\x1b\x00\x00\x00\x00\x60\x02\x08\x00\x36\xca\x00\x00\x02\x04\x05\xb4", 44, 0, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("127.0.0.1")}, 16) = 44This is the one and only packet sent by
nmap
during a SYN scan. You can parse it, or even easier, you can capture it with wireshark and match the contents and you will see that those hex numbers compose a TCP SYN
packet.
The mysterious RST packet
As you can see there is nothing else send out bynmap
after the SYN
packet. So, where does this RST
packet comes from?
Easy. It is generated by the local TCP/IP stack. The default behaviour of the stack is to reply with a RST
packet to anything received that does not make sense (not exactly, but it can be taken as a behaviour baseline). Actually this is abused by other types of scanning techniques that wouldn't work otherwise.
The kernel keeps some internal structures for TCP sockets in order to identify the connection peers, keep buffers, etc... When a TCP packet arrives it has to be matched to one of those structures (unless it is a SYN
packet and therefore there is no kernel structure yet) in order for TCP to do its job. If there is no match, the default behavior of the stack for an unexpected packet is to send back a RST
to tell the other end: Hey! man, this may be a mistake. Just stop bothering me
The conclusion of all this so far is:
- The state of the remote port is known before the
RST
packet even leaves the machine. If the reply isSYN|ACK
port is open, if it isRST
port is closed - The port scanner does not really need to send the
RST
packet and actuallynmap
on a Linux box does not send it. - In normal conditions, the local TCP/IP stack will produce the
RST
packet anyway, so your sniffer and the remote machine will see it.
RST
packet does not really reach the remote machine.
Getting a DoS attack from your scan
If you have been reading about this on the Internet, and even in some books, you will find a text like this: The port scanner has to send aRST
packet back to the victim to close the connection and avoid a potential DoS against the scanning machine.
The basis for this claim is how TCP works. TCP is intended to make sure that the data is reliably transmitted and to achieve this goal it uses the store and resend approach. Let's see what does this mean.
When the remote machine sends out the SYN|ACK
packet in response to the connection attempt (the original SYN
packet), the machine will store that packet in memory until the remote end sends back an ACK
packet saying: "I have received your packet save and sound". If that ACK
nowledge does not come within a certain time, the TCP stack will try to resend it and wait again for the ACK
... just in case it got lost or dropped somewhere in its way.
This process can be finished in three ways:
- A
RST
packet is received indicating thatACK
packet will never be send and the process has to stop. - The
ACK
packet is received and the communication continues normally - An ICMP message is received indicating some problem that prevents the message to be delivered... host/network unreachable...(it you disconnect the wire, there is nothing TCP can do :).
- The
ACK
packet will never come. TCP will retry to re-send the packet a few more timed before giving up
Will we really be DoSed?
To find out if we will be DoSed when we do not send the `RST` packet we have to get a rough idea of the amount of traffic involved in the scanning process. To estimate this we need to know a bit more about how this retry process works. The TCP packet resend process makes use of a system parameter: The number ofSYN|ACK
s retries. These parameter can be checked at /proc/sys/net/ipv4
.
$ cat /proc/sys/net/ipv4/tcp_synack_retries 5Without going in all the details, the re-try algorithm uses an exponential timeout that starts with an increment of 1 second and produces the following sequence:
1 3 6 12 24Taking into account that a
SYN|ACK
packet is 44 bytes (this is the minimum IP + TCP packet size). We will just get five 44 bytes long packets during a period of 24 seconds.
However, the problem will arise when scanning big networks with many hosts up, each one running many services.
A quick analysis shows that this is not really a DoS problem, but a complete waste of resources. Let's see why using some numbers.
Calculations
Let's assume we are using a tool likenmap
, that scans 1000 ports by default, in a /24 network. In other words we are scanning 1000 ports in 255 hosts. Assuming that all hosts are up and no firewall is in place, the scan itself will produce as a minimum:
255 hosts * 1000 ports/host * 44 bytes/port = 11220000 bytes = 10957 KB = 10.7 MB
That's quite some data. And that is just generated whenever you press enter (Note: that scanning all ports on all host and having 255 hosts up is a bit of a extreme case...).
Now, we have to assume that the machine running the scanner can cope with this data without problems... otherwise it will just get DoSed by the fact of kicking off the scanner.
So, what will happen if the RST
packet is not sent at the end of the scanning?. Well, for those 1000 ports on each host that are actually open, we will start getting re-transmissions of the SYN|ACK
packets. Let's assume the worst case (and unrealistic) scenario. All host are up and all 1000 ports are open:
In this case we will just receive, exactly the same amount of data we had already received with our normal scan, 1 second later. Then 3 seconds later. Then 6 seconds later... and after 24 seconds it will just stop.
Overall, the machine doing the scanning will receive around 60MB in 24 seconds. That is quite some data but, for nowadays standard, it is unlikely that such traffic will DoS even a normal Internet connection. In other words, the machine will receive the same traffic that would receive if 5 similar scans were launched in the next 24 secs.
So, the main conclusion of this rough analysis is:
- If not sending the
RST
packet will DoS the attacker machine... then the scan itself will also DoS the machine (of course for a shorter period of time) - In normal conditions the amount of data coming back from the scanned network will hardly suppose a DoS. It is unrealistic that you scan a whole network were all the hosts are up and all of them have 1000 ports open.
- However, not sending the
RST
packet is a dirty solution as well as a waste of resources. Fortunately, the kernel will send the packet for us anyways :). Summing up, you do not have to send theRST
but you should do it.
Conclusions
We have gone into the details of many common claims we found in the Internet regarding SYN scans but that are not usually explained in detail. For me was interesting to see how, something that is mentioned all over the Internet as a trivial thing has some tricky details behind. Of course, I may be wrong on my analysis... so any feedback is appreciated.
Header Image Credits: Martinelle
■
CLICKS: 5509