How to Use Nmap to Scan for Open Ports

22 JULY 2024 • Written by Mehmet Kadir

In previous blog posts we covered what port scanning is, why it’s important, and the technical details around how it works. Building on from this, we can now go into the specifics of how to use Nmap (the most widely used network scanner out there) in order to perform accurate port scans of our assets. The focus of this article will be on identifying open ports, rather than the other features provided by Nmap such as version detection, operating system detection, firewall evasion, the Nmap scripting engine, and so on. The most important and frequently overlooked options that lead to inaccurate or incomplete results will also be detailed. The Nmap reference guide is an excellent resource for further information on any of the topics covered.

If we’re unfamiliar with Nmap, we might run something like this if we’re targeting a single IP address:

nmap 45.33.32.156

Though I love Nmap, I don’t think the documentation makes it easy to understand what exactly this command will or will not do. The defaults are documented, but you have to dig around a bit and know what to look for. I’d like to see a page that lists the most important defaults that may cause inaccurate or incomplete port scan results. Let’s go through the most important options to know, along with defaults.

Host Discovery

Prior to executing a scan, Nmap will perform host discovery in an attempt to determine whether or not the target is actually alive. The idea here is that we don’t want to port scan a target that isn’t online, as this would be a waste of time and bandwidth. By default, Nmap will send the following to the target as part of the host discovery process:

1. ICMP echo request (ping)

2. TCP SYN packet to port 443

3. TCP ACK packet to port 80

4. ICMP timestamp request

If the target does not respond to at least one of these packets, Nmap will consider it to be offline and will not perform further port scanning of this host. Hence, if our target does not respond to ICMP or to the TCP SYN or TCP ACK (as would be the case if we’re blocking ICMP, or do not have services running on port 443 or 80) Nmap will consider the target to be offline even if other ports are actually open. Given that many networks filter out ICMP and that not every asset is a web server, the defaults would potentially skip over targets. If we know with certainty that ICMP is enabled then great, host discovery is beneficial and the default is fine. Otherwise, it’s going to give us inaccurate results and so should be disabled.

Host discovery can be disabled by providing Nmap with the -Pn option. This will ensure that all targets will be port scanned. Though not strictly part of host discovery, disabling DNS resolution is also a good idea as this can slow scans down. The Nmap command to scan our single asset, with host discovery and DNS resolution disabled, would look like this:

nmap -Pn -n 45.33.32.156

Although we’re focusing on Nmap port scans on external assets (since that’s what Syntinul is used for), it’s worth mentioning that scans on local networks do not follow the same host discovery process. Targets on the same local network as your scanner will be discovered through the use of Address Resolution Protocol (ARP), which is usually very reliable in determining whether or not a host is alive.

Port Scanning Techniques

Nmap supports a number of different port scanning techniques, but the two main TCP scanning techniques are the TCP SYN and TCP connect. For UDP scans we have one option, the UDP scan. We’ll briefly describe these different scanning techniques, and refer you to our previous article on how port scanning works if you’re not familiar with the differences between TCP and UDP.

TCP SYN Scan

TCP SYN scans can be enabled by providing Nmap with the -sS option. This scan technique sends a TCP SYN packet to the destination IP address and port; if the target responds with a TCP SYN-ACK the port is considered to be open. The full TCP three-way handshake is never completed, so an actual connection is never established with the target, making this technique faster than a TCP connect scan. The downside of the TCP SYN scan is that it requires that Nmap is run as a privileged user (this is needed to send raw packets). Where Nmap is run by a privileged user, TCP SYN scans are the default. The Nmap command to run a TCP SYN scan would look like this:

nmap -sS 45.33.32.156

TCP Connect Scan

TCP connect scans can be enabled by providing Nmap with the -sT option. This scan technique goes one step further than the TCP SYN scan, in that it completes the TCP three-way handshake. This extra message exchange makes scans slower, and therefore is primarily only used when we’re unable to run Nmap as a privileged user. If Nmap detects it does not have the privileges required to run a TCP SYN scan, it will default to a TCP connect scan. The Nmap command to run a TCP connect scan would look like this:

nmap -sT 45.33.32.156

UDP Scan

UDP scans can be enabled by providing Nmap with the -sU option (UDP scanning is not enabled by default!). This scan technique sends a UDP packet to the destination IP address and port; if the target responds with an appropriate UDP packet, the port is considered to be open.

As is also explained in our previous article, UDP scanning can be inaccurate. This is because if we do not send a service-specific payload, we may not receive a response even if there is a service listening on our target port. For common ports, Nmap will send these service-specific payloads, but for others it will not and therefore we’re unlikely to get a response.

Unfortunately, even if our target port is a common port and we send a service-specific payload, that still does not guarantee we will receive a response. Techniques such as version detection are needed in order to further increase UDP scan accuracy, which will be covered next.

Nmap will mark ports where we have not received a response from as open|filtered, meaning it could not determine if the port is open or not. The Nmap command to run a UDP scan would look like this:

nmap -sU 45.33.32.156

Version Detection

Version detection can be enabled by providing Nmap with the -V option. Version detection is first and foremost used to help identify which version of a particular service is running on a target port. For instance, it might help us identify the type and version of the target web server. As this article is concerned with identifying open ports, we won’t be focusing on this aspect of version detection. In the context of identifying open TCP ports, version detection doesn’t help here as we don’t need to look beyond the TCP three-way handshake to determine whether a port is open.

In contrast, for UDP scans, version detection does help identify open ports as it ensures services are probed beyond simple, empty or non-service specific packets. Therefore, to increase the likelihood of UDP ports being correctly identified, we may want to enable version detection. Version detection will ensure Nmap interrogates ports and sends service-specific payloads in an attempt to elicit a response from the target. This technique, though it improves accuracy, also makes running UDP scans take much longer, and so it’s very unlikely we’re going to want to scan the entire port range. Enabling version detection will run version scan intensity at an intensity of 7 (possible options are 0-9, where 9 is the most intense in its interrogation of services, and takes the longest). The Nmap command to enable version detection (as well as UDP scanning) would look like this:

nmap -sUV 45.33.32.156

Default Ports

By default, Nmap will scan the most common 1000 TCP ports. Nmap has a list of ports as well as how common they are in /usr/share/nmap/nmap-services (assuming Unix). For example, if we wanted to build a comma-separated list of the 20 most common TCP ports we could use the following command:

grep -E "[0-9]+/tcp" /usr/share/nmap/nmap-services | sort -rk 3 | grep -m 20 -Eo '[0-9]+/tcp' | cut -d '/' -f1 | paste -s -d ','

Which returns the following output:

80,23,443,21,22,25,3389,110,445,139,143,53,135,3306,8080,1723,111,995,993,5900

We could then pass this into Nmap and scan the 20 most common TCP ports.

By default, Nmap does not perform any UDP scanning at all, and therefore will not detect any UDP services. If UDP scanning is enabled (-sU), Nmap will scan the 1000 most common UDP ports.

We are likely to want control over which TCP and UDP ports are scanned, rather than sticking to just the defaults. We typically recommend that full TCP port scans are performed (that is, ports 0 – 65,535), and at least 1000 of the most common UDP ports. We can do this by using the -p option, combined with specifying the TCP (T:<ports>) and UDP (U:<ports>) ports we want to scan. The Nmap command to do this would look like this:

nmap -sSU -p T:0-65535,U:<top 1000 UDP ports removed for brevity>

Putting It All Together

We now have all the pieces needed to perform highly accurate port scans of our assets. The final Nmap command might look something like this:

nmap -Pn -n -sSUV -p T:0-65535,U:<top 1000 UDP ports removed for brevity> 45.33.32.156

Nmap has many other options that can be tweaked, and so it’s good to familiarise ourselves with the reference guide so we can make adjustments to our options based on our environment, and potential time constraints. The section on timing and performance is of particular importance, as without some adjustments Nmap can be very slow and conservative in its execution of scans. Any performance related tweaks are going to need to be carefully balanced, as scanning too fast can have a negative impact on accuracy.

And of course, if you'd prefer not to have to worry about external port scans and scanner tuning, you can always let Syntinul take care of that for you.