Nmap is one of the cornerstones of penetration testing. It’s one of, if not the first command you run before you even consider what attack surface to focus on on your target. It’s the way to find out what the server does, how it listens, how it interacts, etc. This is the digital equivalent of walking around the perimeter of a building with a flashlight, shining it in windows and doors, looking for methods of ingress.
And boy does it have its share of command line arguments to custom-tailor your scans.
I am writing this document to have a quick-and-easy way to refer to commands I want to run with nmap without having to look at their reference guide. I’ll run some standard commands I usually run, followed by some parameters I should focus on. For the record however, I will consider the imaginary target of
10.20.30.40. Also note that the default type of scan that nmap performs with TCP is a SYN scan, which is done because it is the least “aggressive” scan. Of course a SYN scan is only performed if the user running it has the capability to sniff packets at a low level (ie the root user), otherwise it will default to a more “layer 7 style” CONNECT scan, which is less accurate since it is assuming the operating system is able to establish a proper connection to determine a valid open port, but I’m getting way too into the weeds here.
Regardless, a default privileged scan will send SYN packets and record which ones reply back with a SYN/ACK as opposed to a REJ or FIN, then press on from there (though nmap will generally tell you if it specifically was rejected on a port, which generally means there is a service listening on that port but it is filtered by a local firewall or some other ACL so you can’t access it from where you are now). I think the original reason for SYN scans being the default is that it is the most covert comparitively speaking since it’s not technically making a connection but simply initiating the handshake, but don’t kid yourselves – any IDS worth its salt will detect an nmap scan from a mile away, even a SYN scan.
$ sudo nmap -sC -sV -oN portscan -v 10.20.30.40
The above will scan the target (on TCP only) on the default “nmap’s most popular 1000 ports”. It will attempt to communicate with each open port and obtain the version of the software listening on it (
-sV). If it successfully connects to a port and determines the running service, it will attempt to run default scripts against it (
-sC), which will do some basic enumeration on it. Say if it were to connect to a web server on port
:80, it will then run simple things like
GET / HTTP/1.1\r\n and return the title of the page. It will then record all output to a file named
portscan in the “nmap” format (
-oN portscan), and finally it will be verbose (
-v). Running this in verbose will inform you the second it finds an open port, so you can attempt your own enumeration on the port before nmap can finish. This is useful if you are in a rush or something I guess. I should note that Ippsec generally uses
-oA <name of server> instead of the above, but it’s generally not necessary on a challenge on HackTheBox or something. Fairly useful on in-the-wild engagements though I suppose.
Finally, I want to stress the concept of running nmap as root. The
sudo command is necessary since nmap utilizes packet capture capabilities when performing scans, which is something only root can do. Sure the nmap binary will still work, but without the ability to perform a SYN scan it will default to a TCP scan, which does not do any packet capturing but rather initiates a TCP connection to each port and attempting to negotiate with it on an application level. This capability restricts nmap’s ability to detect (as I have certainly witnessed before), so SYN scans are generally considered the best option, especially according to nmap’s documentation.
$ sudo nmap -p- -oN allports -v 10.20.30.40
In this scan, I typically run this after the Ippsec Special command. This will check for all open TCP ports ranging from 0-65535. The
-p- is shorthand for the equivalent
-p 0-65535. Also note that I save this to a file called
$ sudo nmap -sC -sV -p 22,25,80,443,5900-5999 -oN portscan 10.20.30.40
Sometimes after scanning all tcp ports I’ll get a huge list of open ports that I haven’t run version and default-script scans on. I can rectify that by specifying what ports to scan. This is usually quick so I don’t need a verbose flag.
$ sudo nmap -sU -oN udp-portscan -v 10.20.30.40
Note that I am not running version and default-script scans, though I can. This will only scan the first 1000 most popular ports (according to nmap). Note that this will take a long time since it’s UDP, and UDP does not have to reply with a response to a port connection if it doesn’t want to. So it will attempt to try to connect to the port, send default connection requests to the port, and wait for a response. If it doesn’t get one it gives up and moves on, so as the psuedo-name implies, UDP really does stand for Unreliable Damn Protocol.
$ sudo nmap -sU -p- -oN udp-im-running-out-of-options -v 10.20.30.40
If I’m ever running this, I am completely out of ideas because this takes forever to finish. This will scan all ports from 0-65535 on UDP, performing the same “connect-and-wait” method as listed above. This takes so long that I usually don’t even bother with this.
$ sudo nmap -Pn --source-port=9090 -f 10.20.30.40
YMMV with the above. This will connect from a specific source port (for potential firewall evasion) as well as fragment packets to fool IDS as well.
$ sudo nmap -p- -T5 --max-retries 0 -v -oA allports --script /usr/share/nmap/scripts/ 10.20.30.40
This will scan the target with “extreme aggression.” Also sets retransmissions to no cap so it will keep banging on the door until someone answers, basically. When they do answer, throw the kitchen sink at them by attempting to run all available scripts against the port, throwing caution to the wind. This is what you run when you want them to know you’re there.
$ sudo nmap -sn 10.20.30.0/24
This will perform an ICMP ECHO (plus some additional similar checks) to all hosts on the 10.20.30.0/24 subnet. It is not uncommon for hosts to block ICMP, so this may not be the definitive way to determine if a host is actually there. On many networks it’s also possible to block ICMP on a firewall if you are traversing networks, so if your network is, say,
10.10.10.0/24 and you are attempting to ping-sweep
22.214.171.124/24, a firewall may prevent ICMP entirely so you will have no joy there. You will have better luck if you are actually on the network you are trying to sweep. That said, nmap does a little bit more than run a ping on all the hosts here, so this is a little better than a standard ping.
Note for anyone running on a virtual machine, specifically VMWare
If you are running this on VMWare in a NAT’d network, run this to “ping-sweep”:
$ sudo nmap -sn --unprivileged 10.20.30.0/24
It’s been brought to my attention that performing a ping sweep in a very specific set of conditions, namely running a virtual machine inside VMWare with your network settings configured to NAT (which is the default), that you may get incorrect output in that all hosts in the subnet will be considered up. The reason for this is because when operating with the
-sn flag, nmap will check a target host is up using the following methods:
- nmap receives ICMP reply to ICMP ECHO_REQUEST packet
- nmap receives ICMP reply to ICMP TIMESTAMP_REQUEST packet
- nmap receives TCP SYN/ACK reply to 443/TCP SYN packet
- nmap receives TCP RST reply to 80/TCP ACK packet
Running nmap from a VMWare machine as stated above, the supplied network can generate a TCP RST reply to all of the 80/TCP ACK packets, which can trick nmap into thinking all hosts are up. Setting the
--unprivileged flag will run nmap assuming you are not a privileged user with the capability of sniffing the wire, so will resort to checking for port 443 connections only. The better solution to this is to run your VM in bridged mode when performing this to achieve more accurate results.
$ sudo nmap -sL 10.20.30.0/24
This isn’t as reliable because it doesn’t send any packets to the target hosts. Just performs nameserver reverse lookups on the IP addresses. Still fairly covert though as you aren’t sending any packets to the individual hosts, just negotiating with a nameserver.
$ sudo nmap -O 10.20.30.40
This performs some fairly low-level inspection to determine the operating system of the target. A bit more detailed than standard TTL differences between Linux and Windows (TTL of packets on Linux start at 64, where Windows starts at 128), also attempts to perform some negotiation with the target to determine TCP Sequence predictability which can be used to fingerprint certain versions of an operating system. Evidently it is also possible to estimate the target’s uptime by viewing the TCP timestamp option, but this is only viewable by adding the
-v verbose flag.
$ sudo nmap --min-rate 10000 10.20.30.40
Use this one lightly. If you want to just blast packets at the target as fast as possible, set the
--min-rate value to something high like 10,000. This will send 10,000 packets at the target per second minimum (potentially faster), so doing it this high will increase false positives (or false negatives). Use only if you know the network isn’t that congested or otherwise has a fair amount of bandwidth. This is unnecessary unless you’re on a time crunch or something. Likewise you can specify
--max-rate 1 to send one packet per second, or
0.1 to send one packet every 10 seconds, etc – to be low and slow.
$ sudo nmap -T 0 10.20.30.40
You can use the
-T flag and choose a number from 0-5 to set a timing template. This is equivalent to setting about 10 different flags to specify speeds of round-trip times, parallelism, scan delays and retries (plus more). A timing template of 0 will be “paranoid”, which will be extremely low and slow, flying under the radar as much as possible at the expense of time, and a template of 5 will be extremely fast and extremely aggressive, potentially causing problems on the target host. It should be cautioned not to use a timing template of 5 unless you’re fine with the potential end result being a complete denial of service, but between you me and the lamppost, if your host falls over after a fast nmap scan then it is my expert opinion that it has no earthly business being available on any network to begin with. For reference, a timing template of 3 is the default scan template.
$ sudo nmap -A 10.20.30.40
This will perform version checking, default script scanning, OS detection and perform a traceroute while it’s at it. Sure you can just use this instead of any of the other stuff I mentioned before, but don’t you want to confuse the script kiddies?
$ sudo nmap -oA portscan 10.20.30.40
There are a few formats you can output to.
-oA outputs to the three major ones, which is normal output (
-oN), grep-able (
-oG), and XML (
-oX). Provide it with a filename and it will create 3 filenames with different extensions. Of course a shoutout goes to
-oS filename which outputs in
S|<rIpt kIddi3 format.
$ sudo nmap -n 10.20.30.40
-n to a scan will choose NOT to perform DNS resolution. Passing
-R will always attempt to resolve.
$ sudo nmap -Pn 10.20.30.40
If you know for a fact that the host is online but isn’t responding to pings, Pass the
-Pn flag to it to skip standard host discovery and attempt to scan the standard way. This will skip the first step of determining if the host is actually up. If you don’t include this, the first thing nmap will do is its standard “are you alive?” checks to determine if the host is up. If it fails those checks it assumes the host is down and will not continue scanning. However, some hosts will straight-up block ICMP packets and only open the ports it needs to. In that case you would add this flag to disable checks and assume the host is up anyway. It will then attempt to connect to the ports it will typically connect to and determine what is listening.
$ sudo nmap -sT --proxy socks4://126.96.36.199:5789 10.20.30.40
Assuming here you have a socks4 proxy listening on
188.8.131.52:5789, this will attempt to funnel all communication through the proxy to hit the remote side. Note that you can only use TCP scans through here as is the nature of proxied traffic. Another option is to use proxychains:
$ sudo proxychains nmap 10.20.30.40
Personally, I don’t find nmap scripts to be that useful, though occasionally they tend to surprise me. I feel like there are better, more flexible tools to accomplish what nmap can do with scripts, but if you have the capability why not learn?
$ sudo nmap -p 22,80,443 --script "vuln and safe" 10.20.30.40
Note that I’m specifying ports. You can run all scripts that are categorized as “Safe” (which generally don’t raise that many red flags), as well as poke at vulnerable services as well (which generally raise red flags). For example, this will not only attempt to perform a version check on the webserver, but also attempt to see if it is vulnerable to something like the Slowloris attack.
$ sudo nmap -p 80 --script http-enum 10.20.30.40
This script works similar to Nikto. Looks for various interesting files that may be on the server. There are better tools out there than this script.
$ sudo nmap -p 139,445 --script smb-enum-users --script-args 'smbusername="admin",smbpassword="password"' 10.20.30.40
The above is fairly neat, admittedly. You can attempt to log into an SMB service and dump users. There may be better tools out there, but it’s a nice one to have. If you leave out the script args it will attempt to log in as a guest user with no password.
Nmap definitely has some halfway-decent ldap enumeration scripts that I’ve used on more than one occasion.
$ sudo nmap -p 389 --script ldap-rootdse 10.20.30.40
The above will attempt to negotiate with the LDAP server and pull the DSE, which is the DSA-Specific Entry (where DSA stands for Directory System Agent). This is useful for finding the default naming context, computer name, and several other interesting things about an LDAP server (such as an AD server).
$ sudo nmap -p 389 --script ldap-search --script-args 'ldap.username="<ldap bind string>",ldap.password="<ldap password>", etc' 10.20.30.40
This will perform an ldap search against the target. This is neat but honestly you’re better using
ldapsearch for this instead. Regardless, you can read up on how to use it here if you’re curious.
Beyond the above, however, there isn’t much reason to use the last one. There is an
ldap-brute script which - you guessed it - brute forces ldap bind authentication. But there are better, more flexible scripts to do exactly that. CrackMapExec is the first one that comes to mind. It does it well, it does it fast, and it does it easier than the nmap script can.
The best thing I can mention here is that nmap is a super useful tool. It has a scripting engine that in my opinion is largely fluff. It’s useful at first but there are always better tools to accomplish what you need. From boot to root, nmap is typically one of the first steps you’d take, but in most occasions it serves as the determination of where to focus next. Super useful at the beginning of an attack, also useful after attempting to move laterally within a network. But the scripts are just meh.