Why Nmap Scans Are So Slow and How to Speed Them Up

1 AUGUST 2024 • Written by Mehmet Kadir

A common misconception is that Nmap is an inherently slow network scanner that isn’t suited for scanning large numbers of targets or ranges of ports. For this reason, some people jump straight to scanners such as Unicornscan, ZMap, RustScan and others for their alleged faster scanning capabilities, without necessarily understanding why Nmap is running slow, or why the alternatives are faster. In this article we’ll learn that it is absolutely possible to tune Nmap scans to run just as fast, but also why we have to be careful before doing so. That’s not to say that there may not be instances where we will want to use one tool over another, but it is important to understand the reasons as to why there are performance differences to begin with. Understanding the why helps us appreciate what’s happening under the hood. With this knowledge, we can retune our tools based on our environment and specific use case without compromising the accuracy of our scans or, worse, bringing down a network.

Although we’ll be focusing exclusively on Nmap – as Syntinul uses Nmap for all port scanning activities – the concepts discussed are mostly general networking concepts, and so you should be able to find equivalent tuning options for other tools too. This article is not a comprehensive discussion of all of the performance and timing related options provided by Nmap, but does detail the ones that we would recommend looking at first if your port scans are running slow.

We assume scans are run from a system that has a stable low latency connection, sufficient bandwidth, and is not limited by a slow CPU, low memory, or filtering by firewalls or other security appliances. If your intention is to scan at speed, the systems you’re scanning from should also be whitelisted on anything that may detect, block, or rate-limit port scans.

The Nmap reference guide provides further information on all options discussed here, as well others that may be worth considering depending on your specific context.

Nmap Timing Templates

Nmap is highly configurable, giving us significant control over the various options that will determine how fast scans are run. There are, however, a number of defaults which in many ways makes Nmap slower out of the box. Furthermore, depending on your target environment, these defaults may make Nmap prohibitively slow for scanning larger networks. The defaults are there to try and make Nmap scans accurate regardless of various network specific factors such as bandwidth, packet loss, latency, etc. Nmap timing templates are a good place to start for those wanting to understand Nmap performance. The table below is found in the Nmap reference guide and details the built-in timing templates available:

Nmap Timing Templates

If we do not specify a timing template when running Nmap, the default of T3 will be used. Let’s briefly describe some of the timing variables.

Important Timing Variables

initial-rtt-timeout, min-rtt-timeout, max-rtt-timeout – determines the initial, minimum and maximum amount of time Nmap will wait for a response to a probe. rtt means round-trip time, and is a measure of how long it takes from when Nmap sends a probe to a target to receive a response back from that target.

min-rate, max-rate – determines the minimum and maximum number of probes per second Nmap should send. The rate is applied globally to a scan, rather than to individual targets.

max-retries – determines how many times Nmap will retry if network issues (such as retransmissions) are detected.

min-hostgroup, max-hostgroup – determines the minimum and maximum number of targets Nmap can scan in parallel.

min-parallelism, max-parallelism – determines the minimum and maximum number of probes that may be outstanding (meaning, we haven’t received a response yet) for a host group.

Nmap’s Dynamic Timing

As the initial, min and max options allude to, timing variables are dynamic. Nmap adjusts timing variables based on probe responses. For instance, if we’re running a scan with defaults (T3 timing template) our initial-rtt-timeout is 1 second. If Nmap receives responses within 100ms, it will adjust its timing as needed so as not to wait a whole second for a response in subsequent probes. If network conditions look good, Nmap may increase the scan rate and parallelism. The idea here is to monitor network conditions and adjust timings in such a way that will increase scan performance within the constraints of the network and target. The opposite is also true, if Nmap detects that packets are being dropped, or round-trip times have increased, it will adjust timings to slow things down.

It's important to notice that the algorithms Nmap uses to dynamically adjust timing variables depends on there being some kind of response to work with in the first place. However, we know from our previous article on how port scanning works that we’ll commonly only receive a response to a probe if a port is open. If we’re scanning all 65,536 TCP ports on a target, and that target happens to have a single obscure port open, we may not receive a response until we hit that open port; therefore, Nmap would not adjust timing variables until a response is received. Until a response is received indicating otherwise, Nmap will most likely be scanning at a speed that is significantly slower than what the target network is capable of. We’ve seen this confuse many people, who assume it’s an issue with rate-limiting or some other type of filtering, when in reality, it’s just the way Nmap works. If your targets are running common services, you’re less likely to run into this issue as Nmap scans most common ports first by default, and so would (hopefully) elicit a response early on in the scan and make timing adjustments based on that.

When Dynamic Timing Fails

As has been explained, dynamic timing fails when Nmap doesn’t get feedback from a target. So, what does this mean for our scan performance? Let’s go through a scenario where Nmap is running a TCP SYN scan on ports 0-65535 with the default (T3) timing template and try to understand what would happen if we’re unable to elicit any kind of response from the target:

1. Nmap sends out 10 probes (or 5 in the case of a TCP connect scan, though we can’t find either of these values documented anywhere)

2. Nmap waits for 1 second for a response to any probes sent

3. Repeat

At this rate (10 packets per second), it will take Nmap approximately 6553 seconds (218 minutes) to scan all 65536 ports on a single target. Why 218 minutes and not 109? Because if Nmap doesn’t receive a response, it will resend the probe one more time (this behaviour is not tied to the max-retries option, which is only applicable if network issues are detected). This makes the default T3 timing template very slow for targets where Nmap is unable to dynamically determine timing variables. Furthermore, the initial-rtt-timeout is just too long for most modern infrastructure, even those located on the opposite side of the world. For this reason, a good first step in speeding up scans is to consider using the T4 timing template and seeing if that meets your needs. This can cut scan times in half due to the initial-rtt-timeout being half of that of a T3 scan, resulting in approximately 20 packets per second. We would not recommend the T5 timing template for port scans that cover a wide range of ports, as it uses a host-timeout of 15 minutes and therefore will give up on scanning a host if the scan isn’t completed within 15 minutes. The initial-rtt-timeout of 250ms can also sometimes be a little too aggressive for internet scans.

Tuning Nmap for Faster Scans

Now that we have a basic understanding of the default timings and how they work, we can start to customise our Nmap scans to better suit the environment we’re scanning. There is no-one size-fits-all here, and so we will either need to have a good understanding of the hosts and networks we are scanning, or, we will need to make some sensible assumptions. Otherwise, we wouldn’t suggest playing around with these timing variables too aggressively.

In general, we would recommend using the T4 template as a base and making modifications where appropriate. For instance, if we know that our average latency to a target network is 100ms, setting Nmap’s initial-rtt-timeout to somewhere between 200-300ms sounds quite reasonable. We can also consider the bandwidth implications of our timing variables. For example, if we set our min-rate to 100, we can estimate how much bandwidth will be used. If we assume our TCP SYN probe is 58 bytes in length, that gives us 5800 (58 * 100) bytes per second, or 0.0464 megabits per second. If we and our target have even just a 100 megabit per second connection that isn’t saturated, it’s unlikely that scanning at such a rate is going to cause any bandwidth issues. Similar calculations can be made based on parallelism. This idea of controlling how many packets per second or probes are sent is basically how other scanners are achieving faster scans. RustScan, for example, boasts it can scan 65,000 ports in 3 seconds, giving us some idea as to just how many packets per second it’s pushing out (this is rarely appropriate).

It’s important to consider how timing changes will impact our target networks. Sending 1000 packets per second to a single target isn’t the same as sending 1000 packets per second spread out over 256 targets. Hence, if we’re scanning hundreds of targets across a range of ports we may want to increase our min-parallelism and min-hostgroup into the hundreds in order to spread our probes across these targets. In contrast, if we’re scanning a single port across a large network of 65,535 targets, increasing our min timing variables into the tens is likely to be enough. Again, we need to have a good understanding of how many probes we’re expecting to send, available bandwidth, latency, and so on, for this type of fine-grained tuning to be most effective.

We've run a few scans to compare scan duration with Nmap's defaults against scans with some minor tuning. These scans were run on TCP ports 0-1000 against a /27 network (32 targets) in an environment where there is no feedback for Nmap’s dynamic timing to help speed things up.

CommandScan duration
nmap -Pn -n -sS -p T:0-1000 10.0.0.0/276478 seconds (107 minutes)
nmap -Pn -n -sS -p T:0-1000 10.0.0.0/27 -T43350 seconds (55 minutes)
nmap -Pn -n -sS -p T:0-1000 10.0.0.0/27 -T4 --min-hostgroup 32 --min-parallelism 100330 seconds (5.5 minutes)

As should be very clear from the results, tuning Nmap can have a massive influence on how long scans take to complete. We were able to scan almost 20 times faster than the default. The timing variables used even in the fastest scan are very conservative given the environment and number of hosts we’re scanning; we could go much faster without expecting accuracy to be negatively impacted.

Finally, it's important to note that in some cases Nmap tuning may not be sufficient to increase performance to our desired level. There are further limitations to consider other than the ones we have covered in this article. For example, if we intend to execute full TCP port scans on a very large number of hosts, we may also need to look at tuning our network adapters, or make other operating system level changes to support the higher scan rate. This is a complex topic, which we may detail in a future blog post.

Conclusion

In this article we’ve covered why our Nmap scans might be slow, and the default timing variables that could contribute towards this. While some may switch over to alternative network scanners for their alleged superior speed, it’s useful to understand how they work under the hood and how their various defaults might impact our networks and scan accuracy. All network scanners function more or less the same, they mainly just differ on defaults, and assumptions they make about the user’s preference for performance vs accuracy. We’ve seen how we can tune various timing variables in order to meet or exceed the performance of alternative tools. Lastly, we’ve demonstrated why it’s vital to understand the context we’re scanning in and any constraints we’re up against, and how we might make adjustments based on various factors to balance performance and accuracy.