The Art and Detection of Port Scanning
In this security column, I will investigate the art of port scanning, and what you might be able to do in detecting it.
Why is port scanning so interesting from a security point of view? In most cases a port scan is a prelude to a break-in attempt. In performing a port scan, a potential cracker tries to find an opening in your defenses. So, if you can properly detect a port scan, you have a kind of early warning signal against break-in attempts, and you can take appropriate measures to prevent a real break-in from occurring.
The Art of Port Scanning
What is a port scan all about? During a port scan, someone tries to make connections to all well- and less-known network services. Subsequently, all services to which they could connect will be exploited for known bugs, misconfigurations, or other errors that could grant someone unauthorized access. This is the case for both TCP- and UDP-based services. (Although you cannot really speak of a connection with a UDP-based service, since the UDP protocol is based on datagrams and therefore does not know the concept of a connection.)
Port scans can be performed in many ways, which I will describe later. But before that, I would like to point out that a number of port scan programs are available on the Internet, some very simple, others very sophisticated. Commercial audit programs also have a port scanner on board to perform these functions. The different techniques described below can all be performed with NMAP, a program that is available as a source on the Internet and that was featured in Phrack magazine a while ago.
With a sophisticated port scanner, one can scan both TCP- and UDP-based services. The scanning itself can be performed in several ways, either within the specifications of the TCP/IP protocol suite, or by exploiting omissions in TCP/IP. In the latter case, the reactions of the victim are dependent on the implementation of TCP/IP, but often one can determine whether a service is actually present by looking at the response (or lack thereof) of the victim.
Before describing these techniques, there is one more thing to clarify. The TCP/IP protocol allows a machine to send a response to a client whenever a connection is refused. You can see this if you try to telnet to a port on a machine on which no service is listening. You will get a connection refused error message. This message finds its origin in the connection rejected message generated by the TCP/IP stack. However, most firewalls connected to the Internet are configured to silently discard the incoming connection request without sending the connection rejected (reset) message. Because this message is not sent, a potential cracker does not know whether his request was denied because no service was available, or because his machine was not allowed in.
Scanning within the TCP/IP Protocol
When scanning within the protocol, a TCP-based scan tries to establish a connection to all the specified ports. It does this by sending a SYN packet to the service, and waiting for a SYN/ACK response. If this response is received, it found a "hit" and was able to connect to the service. A good example of such a service might be the SMTP port for receiving email from the Internet. Since everyone should be able to send email to you (well, maybe not everybody), everyone should be able to establish a connection to your SMTP port. If no SYN/ACK response is received, the port scanner will time-out, and the applicable service will be marked unavailable.
A UDP-based scan works differently. In this case, the scanner sends its UDP datagrams to the victim. The scanner hopes for connection reset messages when an unavailable UDP port is contacted, and no response when an available UDP port is contacted.
Before you go off to write your own scanner, please take a look at the usage information of NMAP. You will see that it covers almost every possible scan method. The method I described earlier is covered by the -t and -u options (regular scanning).
nmap V. 1.51 usage: ./nmap [options] [hostname[/mask] . . .]
options (none are required, most can be combined):
-t tcp connect() port scan
-s tcp SYN stealth port scan (must be root)
-U Uriel Maimon (P49-15) style FIN stealth scan.
-P ping "scan". Find which hosts on specified network(s) are up.
-b <ftp_relay_host> ftp "bounce attack" port scan
-u UDP port scan, will use MUCH better version if you are root
-l Do the lamer UDP scan even if root. Less accurate.
-f use tiny fragmented packets for SYN or FIN scan.
-D Don't ping hosts (needed to scan www.microsoft.com and others)
-i Get identd (rfc 1413) info on listening TCP processes.
-p <range> ports: ex: '-p 23' will only try port 23 of the host(s)
'-p 20-30,63000-' scans 20-30 and 63000-65535 default: 1-1024
-F fast scan. Only scans ports in /etc/services, a la strobe(1).
-n Don't DNS resolve anything unless we have to (makes ping scans faster)
-L <num> Number of pings to perform in parallel. Your default is: 52
-o <logfile> Output scan logs to <logfile>.
-R Try to resolve all hosts, even down ones (can take a lot of time)
-r do NOT randomize target port scanning order.
-S If you want to specify the source address of SYN or FYN scan.
-T <seconds> Set the ping and tcp connect() timeout.
-v Verbose. Its use is recommended. Use twice for greater effect.
-h help, print this junk. Also see http://www.dhp.com/~fyodor/nmap/
-V Print version number and exit.
-w <n> delay. n microsecond delay. Not recommended unless needed.
-M <n> maximum number of parallel sockets. Larger isn't always better.
-q quash argv to something benign, currently set to "pine". (deprecated)
Hostnames specified as internet hostname or IP address. Optional
'/mask' specifies subnet. cert.org/24 or 220.127.116.11/24 or
18.104.22.168-255 scan CERT's Class C.
As an example, I have scanned one of our hosts with NMAP, using the -t options:
nefertiti:/usr/local/security/nmap-1.51 # ./nmap -v -v -t ra
Starting nmap V. 1.51 by Fyodor
Host ra.reseau.nl (10.0.0.1) appears to be up ... good.
Initiating TCP connect() scan against ra.reseau.nl (10.0.0.1)
Adding TCP port 13 due to successful 0-byte write!
Adding TCP port 19 due to successful 0-byte write!
Adding TCP port 515 due to successful 0-byte write!
Adding TCP port 513 due to successful 0-byte write!
Adding TCP port 22 due to successful 0-byte write!
Adding TCP port 80 due to successful 0-byte write!
Adding TCP port 23 due to successful 0-byte write!
Adding TCP port 79 due to successful 0-byte write!
Adding TCP port 7 due to successful 0-byte write!
Adding TCP port 110 due to successful 0-byte write!
Adding TCP port 143 due to successful 0-byte write!
Adding TCP port 9 due to successful 0-byte write!
Adding TCP port 514 due to successful 0-byte write!
Adding TCP port 53 due to successful 0-byte write!
Adding TCP port 25 due to successful 0-byte write!
Adding TCP port 139 due to successful 0-byte write!
Adding TCP port 21 due to successful 0-byte write!
Adding TCP port 37 due to successful 0-byte write!
Adding TCP port 512 due to successful 0-byte write!
Adding TCP port 111 due to successful 0-byte write!
Scanned 1024 ports in 1 seconds with 36 parallel sockets.
Open ports on ra.reseau.nl (22.214.171.124):
Port Number Protocol Service
7 tcp echo
9 tcp discard
13 tcp daytime
19 tcp chargen
21 tcp ftp
22 tcp ssh
23 tcp telnet
25 tcp smtp
37 tcp time
53 tcp domain
79 tcp finger
80 tcp www
110 tcp pop3
111 tcp sunrpc
139 tcp netbios-ssn
143 tcp imap2
512 tcp exec
513 tcp login
514 tcp shell
515 tcp printer
As you can see, it has found a number of ports, each of which may be investigated further for exploits and misconfigurations.
Scanning by Abusing the TCP/IP Protocol
However, in most cases a regular scan will only reveal the services you have explicitly enabled for connections from the outside. Your firewall may have more services available, but only for specific clients. This is where the other scanning techniques come into play.
By sending packets that do not conform to the TCP/IP standard, you can sometimes determine these extra available ports. A well-known technique is to send SYN/ACK packets to a machine. Since this is the first packet received, and it does not conform to the three-way handshake (SYN->SYN/ACK->ACK) of the TCP standard, the victim will send back an error message. In most cases, this error message differs between active and inactive ports. By carefully looking at that error message, a port scanner might determine whether a service is active on that port or not. Below is an excerpt from a NMAP stealth scan (-s option).
Possible catch on port 23! Here it is:
TCP packet: 10.0.0.1:23 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1227033039 Ack: 3232493199
Possible catch on port 21! Here it is:
TCP packet: 10.0.0.1:21 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1227971632 Ack: 3970481793
Possible catch on port 80! Here it is:
TCP packet: 10.0.0.1:80 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1228722293 Ack: 1473704597
Possible catch on port 515! Here it is:
TCP packet: 10.0.0.1:515 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1229410451 Ack: 443084619
Possible catch on port 514! Here it is:
TCP packet: 10.0.0.1:514 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1229927695 Ack: 523228299
Possible catch on port 19! Here it is:
TCP packet: 10.0.0.1:19 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1230050193 Ack: 417569634
Possible catch on port 513! Here it is:
TCP packet: 10.0.0.1:513 -> 10.0.0.2:49724 (total: 44 bytes)
Flags: SYN ACK
ttl: 255 Seq: 1230309233 Ack: 1557825411
Possible catch on port 53! Here it is:
TCP packet: 10.0.0.1:53 -> 10.0.0.2:49724 (total: 44 bytes)
In this case, no extra ports were found. When this kind of scan is performed over the Internet (scanning a system that's behind a filtering router), it may reveal extra information.
Apart from the stealth scan, there are a number of other combinations of TCP flags that can be used to scan a machine (FIN for example). All of these scans may yield new results.
Scanning by Abusing ftp
The last way of scanning a machine is by (ab)using the ftp protocol, the so-called ftp bounce attack. As you probably know, transferring data via ftp involves a control connection over which commands and status messages are exchanged, and for each transfer a data connection. Under normal circumstances (non-passive transfer), the client uses the PORT command to tell the server which port on the client machine the server must open to transfer the data. However, when the client does not specify its own IP address and port in the PORT command, but that of a machine it wants to scan, it can indirectly open a port on another machine. This kind of scan is often used to scan machines that are located in a DMZ, behind a firewall. The ftp server is used as a sort of bounce point to the internal network.
Detecting Port Scans
Now that I've described how port scans can be performed, the next step is how to detect them.
A common feature of all port scans is that within a short period of time, a lot of connection requests will be received by the victim on ports that are not available. These requests may not all originate from the same source address, but may have different sources. You cannot assume that all ports will be scanned in ascending or descending order, most port scanners have an option to randomize both the source and destination ports.
So, "all" you have to do is count the number of incoming requests (most of which will be destined for an inactive port), and see if that number exceeds a limit within a certain time period. But how do you gather these connection requests, especially the ones that abuse the TCP/IP protocol and are therefore not processed by the TCP stack?
There are three ways of doing this, ranging from the simple to the complex.
The first way is to use the packet filtering capabilities of your firewall. If it supports transparent proxies you can redirect all traffic that is illegal to one port on your machine. A special detector program will be listening on that port and count the number of packets coming in on that port. If for instance you are using Linux, you can enable the firewalling options and transparent proxy option to redirect all incoming traffic to a special port. You can do this with ipfwadm.
The obvious disadvantage of this method is that it will not detect the protocol abusing scans, and it is quite easy to overflow.
The second option is to open the raw IP device on the machine you want to protect. Under Solaris that would be /dev/init, and under Linux you would open the RAW IP socket. Other UNIX systems will have equivalent devices. (BTW, if someone knows how to do this under NT, please drop me a message at email@example.com, I would be very interested). All IP packets for that particular machine will be available on the device. You will have to disassemble the packet yourself to get hold of the header information, but now you will be able to detect the illegal protocol scans as well. The same technique applies as before, count how many packets are received within a certain time frame, and if that number exceeds a certain limit, you may conclude that a port scan is in progress (especially if these packets are destined for different ports on the same machine).
The disadvantage of this method is that you will only detect scans directed at your machine. If someone is clever and scans the same port on all IP adresses in your range before trying the next one, you may not detect the port scan. (Remember, accessing the raw IP device is not the same as putting the network interface in promiscuous mode).
In the third method, the detection extends to your whole network. By putting the network interface of a machine in promiscuous mode, you will be able to receive all network packets on the wire and therefore also detect port scans destined for other (maybe not even available) machines.
There is code available on the Internet (e.g., watcher, refer to Phrack magazine, available for Linux via the Sunsite archive) and as commercial packages (RealSecure, RIDS) that will help you in detecting a port scan.
Once you know how port scans work, you can develop methods to detect them. And since a port scan is often the first step in a break-in attempt, detecting them will help you in prevent break-ins.
About the Author
Arthur Donkers graduated from the Delft University of Technology with a degree in Electrical Engineering and a major in Computer Architecture. Since then he has worked for a number of major software houses in the Netherlands. His primary field of interest is in datacommunications, especially the security aspects involved. He now is the founder and owner of Le Reseau, a company specializing in security-related issues for UNIX, OpenVMS and Windows NT, and the application of Linux in corporate environments.