I had a subnet that I was documenting and needed to see which IP addresses and ports had services responding to requests. Basically, I needed full visibility into what each node on the subnet was exposing. It was a bit of a housekeeping measure to see who had done what over time and forgot to document it (or worse, had no idea that someone or some thing had opened up unwanted communication).
We’ll need to pick our targets and then pick what to scan on those targets. I’m using nmap 6.01 on Mac OS X 10.8 for reference. To start, since I want to scan an entire subnet, there’s no need to create a list of hosts in a file. I can simply pass the subnet and mask to nmap thusly:
10.0.0.0/24. However target specification, while it comes first in the man page for nmap, comes last in the command invocation.
First we have to select the host discovery method to use. On systems that I control fully, I prefer to use
-Pn. What does
-Pn: Treat all hosts as online — skip host discovery
-Pn, an interrogating ping is not sent to the hosts first. Rather, every host in the list is assumed to be up and will have a port scan performed. You never know when someone has misguidedly disabled ICMP echo responses on a device, so it’s best to assume nothing in situations requiring full disclosure of a host’s listening services.
By default, nmap -Pn 10.0.0.0/24 would work pretty well to give you an idea of what’s on the network. However, I want to do a little more. MOAR PACKETS!
Crank it to Elebenty!!
Not only do I want to scan the entire subnet, I want to scan the entire range of possible TCP/IP ports on each IP address, so I’m pulling out the big guns with
-p1-65535 (no space after the
-p). That’s right, sixty-five thousand, five-hundred, and thirty-five ports will be scanned per host. You can’t be too careful. (Actually you can, but to quote Mick Jagger: “Anything worth doing is worth overdoing.”)
While I’m going crazy, I might as well use
--version-all. What does that do? It’s basically an easier to read alias for
--version-intensity 9. There are nine possible intensity levels for determining what is running on a port, and the default level is 7. To summarize using the nmap reference guide: “The higher the number, the more likely it is the service will be correctly identified.” Of course, this is going to take longer than a default intensity would.
And before I get off the crazy train, I’d also be interested in seeing what nmap’s best guess at the endpoint’s OS is. Even if there’s zero documentation about a device, I could potentially track it down by asking “Who knows about a Linux device running kernel 2.4 and open Jabber ports?” Nmap’s OS detection feature is invoked by the
Documenting the Crime
We’re about to commit a crime against network sanity, but like any good “Watch this!” moment, we need someone to film our near-death experience with their iPhone. Nmap’s ability to capture your scan’s output is pretty impressive. We can write to a file using nmap’s normal output with
-oN or we can output to XML with
-oX. We can even output into 1337sp3@|< with
I’m fine with nmap’s regular output, so I’ll simply use
Now would be a good time to talk about the negative side affects of what we’re about to do. This is a pretty intense scan with only default throttling being performed (and by default, a scan can balloon to consume what a network is willing to give it). If this is across slow links, there could be some trouble with hosing the available bandwidth. If there are any systems that are protected proactively, such as with Fail2Ban or if there’s some kind of IDS/IPS system, this is going to make it light up like a gasoline soaked Christmas tree with Claymore mines as ornaments re-entering earth’s atmosphere.
This operation will take a little bandwidth, a little CPU, and make a big splash on any network monitoring systems. If you have a network and/or security team, and you’re not on that team with clearance to do this, they will probably hire a drifter to kill you on your way home. Consider the possible negative consequences to doing this in the larger context of your environment. If you have misgivings, take note of nmap’s timing, performance, evasion, and spoofing features as necessary (or just whitelist the nmap host in your various IDS/IPS/etc. systems if possible).
For me, I’m not going to be the buzzkill in this nmap party. I’ve got very little to worry about so we’re going full throttle, helmets off, and no eye protection.
Except I Don’t Want to be Kicked Out of the Datacenter
This subnet is actually public IP space, and one of the hosts on the subnet is the datacenter’s upstream router. While they don’t care what kind of traffic I put on the network, as long as the invoices get paid, I probably want to exclude their router’s interface from my impending Scan of Madness. I’ll use
--exclude and protect that one crucial IP address.
Assessing the Damage
Okay so the results aren’t exactly catastrophic. The command that I ran ended up looking like this:
nmap -Pn 10.0.0.0/27 -p1-65535 -O --version-all --exclude 10.0.0.1,10.0.0.2 -oN it_wasnt_me.txt
The traffic associated with the scan barely amounted to more than 1Mbps, and that was scattered among many hosts (in fact, at one point it was all 30 hosts if nmap’s documentation is correct). Nmap started off smoothly and ramped up as it detected there was free bandwidth and no packet loss:
Notice that the first big drop in traffic was after the first host had been scanned, then nmap ramped back up. However, after that, the traffic was fairly steady:
The scan of my /27 with two excluded IP addresses (I added a second host to the exclusion list for safety) was just over 27 minutes:
Nmap done: 30 IP addresses (30 hosts up) scanned in 1630.95 seconds 1630.98 real 98.21 user 58.68 sys
So maybe this wasn’t cranked up to eleven like I thought! Let’s… let’s be evil.
No really. Eleven.
I re-ran the invocation of nmap, except with a few tweaks. First,
--min-hostgroup 30. In the words of the nmap reference guide:
By default, Nmap takes a compromise approach to this conflict. It starts out with a group size as low as five so the first results come quickly and then increases the groupsize to as high as 1024.
I decided to force it to start with a hostgroup of 30 which was the number of IP addresses I wanted to scan on my /27. Next up,
--min-parallelism. Once again, in the words of the nmap reference guide:
The ideal probe number slowly rises as the network proves itself worthy. These options place minimum or maximum bounds on that variable. By default, the ideal parallelism can drop to one if the network proves unreliable and rise to several hundred in perfect conditions.
If I had just considered the idea of minimum parallelism without the reference guide, I would have assumed that perfect conditions would render an integer of several thousand or more. So several hundred being considered ideal has set my back on my haunches a little but. After some consideration I somewhat arbitrarily decided to set
--min-parallelism to 200.
With those two options set, I re-ran the command which now looked like this:
nmap -Pn 10.0.0.0/27 -p1-65535 -O --version-all --exclude 10.0.0.1,10.0.0.2 -oN it_wasnt_me.2.txt --min-parallelism 200 --min-hostgroup 30
Interestingly, I got the message “Warning: Your –min-parallelism option is pretty high! This can hurt reliability.”
On my laptop, an 11″ MacBook Air with 1.7GHz i5, nmap was taking up around 10% – 13% CPU. The firewall showed a slight increase in scan traffic. About 1.3 to 1.5 Mbps although a less steady stream.
That one took a little less time:
Nmap done: 30 IP addresses (30 hosts up) scanned in 1546.20 seconds
1546.27 real 100.12 user 56.76 sys
However that’s not really enough to make me think that it could be entirely contributed to the change in parameters. I did see a slight uptick in sustained scanning throughput, however I wanted to try one more option. The
--min-rate option. Once again, to quote the nmap reference guide:
When the –min-rate option is given Nmap will do its best to send packets as fast as or faster than the given rate.[…] Specifying a minimum rate does not keep Nmap from going faster if conditions warrant.
The integer given to the
--min-rate option is packets-per-second. So 1,000 pps would be roughly 11Mbps. Let’s do it:
nmap -Pn 10.0.0.0/27 -p1-65535 -O --version-all --exclude 10.0.0.1,10.0.0.2 -oN it_wasnt_me.3.txt --min-parallelism 200 --min-hostgroup 30 --min-rate 1000
After that command, nmap didn’t seem to be using any more CPU than in the past. Scan traffic to the firewall didn’t appear to be any higher. The command completed in more time than the previous one.
Nmap done: 30 IP addresses (30 hosts up) scanned in 1590.16 seconds
1590.22 real 118.25 user 56.90 sys
You can very clearly see the three separate nmap sessions for the entire subnet as rendered by the pfSense firewall protecting the /27.There is no appreciable difference in bandwidth used by any of the three.
It’s also interesting to note, and thoroughly logical, that the system showed much more CPU usage for the scan than for the other traffic that was approximately have the total throughput. Notice above that the grey outbound traffic continued to grow, unrelated to the nmap scan (some node in the rack was sending data out), and yet that same space of time on the CPU chart showed almost zero usage:
It must be quite a bit less logic to handle traffic that’s consistently over one port than hundreds of thousands of requests rapidly cycling through different ports.
I Fail at Failing but Succeeded at Succeeding
I did what I set out to. I got the small subnet’s public services documented. I didn’t do what I morbidly hoped I could do: knock out the subnet and saturate a 100Mb line with scanning traffic. So there you have it. Now you know how to brute force scan a subnet with no mercy… but really it’s not that bad since apparently you can’t destroy a 100Mb line with nmap using any of the above invocations.
If you’ve got deeper insight into nmap and know how to scan faster and more aggressively, let me know in the comments below.