Introduction

Since this will be my first ever post on this site, what better tool to cover than NMAP! Other than some basic Linux, this was the first tool that I learned on my quest to learn penetration testing. It will likely be the first tool that you start learning as well. I always enjoy starting up NMAP on a new box or challenge, and waiting to see what juicy tidbits it discovers. Am I going to have a lot of interesting open ports to explore (and maybe a lot of rabbit holes), or will I only have a couple of open ports which funnels my efforts towards these services? This tool is what starts unlocking the mystery of every box. I feel that this guide follows the 80/20 rule. I am probably only providing about 20% of NMAP’s capabilities, but this will likely be the techniques and commands you use 80% of the time. Let’s get started!

What is NMAP?

Straight from the docs.

Nmap (“Network Mapper”) is a free and open source utility for network discovery and security auditing.

Ok, well, neato, what does that mean? For starters, the “network discovery” part simply means that NMAP will help you find devices on the network. A range of IP addresses or DNS names can be scanned and NMAP will attempt to see if each host is online. It’s as simple as that. As for the security auditing portion, NMAP can probe for open ports on live systems and can possibly tell you the exact name and version of a service running on that port. Pretty cool!

Installing

Going in depth on setting up your specific environment is out of the scope of my intended goal of this article, but if you need a little nudge on this, I gotcha covered.

Linux

If you are using a security based Linux distribution such as Kali Linux or Parrot OS, NMAP will already be installed. If not, you can likely use your systems package manager to easily install NMAP.

# For Debian/Ubuntu distros
sudo apt install nmap

# For RedHat based distros
sudo yum install nmap

This should be it! Although these distributions are pretty common, your package management system may be different. If that’s the case, I’ll leave that to you to tinker with.

Mac OS

The easiest way to install this on mac is to set up Homebrew and install with the following command.

brew install nmap

Windows

For Windows, simply download the appropriate executable, install, and you should be on your way! The Winodws version also includes Zenmap, which is a GUI wrapper around NMAP. On top of the Windows executables, this page also has instructions for installing downloaded binaries for other OS’s.

Our First Scan

Ok, enough of the jibber jabber, let’s get our hands dirty and scan something!

NOTE: Please do not run NMAP on any target except a training environment, or one in which you have explicit permission to run NMAP on! This could land you in trouble!

Our target system will be http://scanme.nmap.org/. If you navigate to the site, you can see that it was explicitly set up to run NMAP on. Let’s give it a try! Run the following command and sit back and let it finish, it may take a little while:

NOTE: Many of NMAP options require elevated privileges. It is best to run NMAP in an elevated terminal or use the sudo command.

nmap scanme.nmap.org

After several minutes, we get the following results.

Nmap scan report for scanme.nmap.org (45.33.32.156)
Host is up (0.040s latency).
Not shown: 954 filtered tcp ports (no-response), 44 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 927.16 seconds

Ok, cool, so what did we learn from this? First of all, we see that the domain name scanme.nmap.org resolves to 45.33.32.156. The “Host is up” portion tells us that this site is responding to NMAPs ping requests, confirming that it is online and available for scanning. We next see that we have 954 filtered ports, 44 closed ports, and then the 2 discovered open ports, along with their respective service names. Keep in mind that the listed service is a guess based on the port discovered. A detailed description of port state can be found here. With that said, here is a quick rundown of the states that we discovered.

  • Closed: This port is actively refusing connections.

  • Filtered: NMAP can not determine if port is open or closed.

  • Open: This port is actively accepting connections.

To understand this a bit better, let’s talk about the TCP 3 way handshake. When a client attempts to connect to another computer over TCP, it sends a SYN packet to request a connection. If the service is available on the server, it sends a SYN/ACK packet back to the client. The client will acknowledge receipt of the SYN/ACK packet with a SYN packet.
At this point, the connection between the client and server is established.

Client            Server   
        ----> SYN

        <---- SYN/ACK 

        ----> Ack

Any port responding to a SYN with a SYN/ACK is considered open. However, if the port is not listening, the response will be different.

Client            Server   
        ----> SYN

        <---- RST/ACK 

In this case, our probe reached the server, which replied with RST/ACK packet, basically telling the client that no service is listening on the requested port. Now that we covered open and closed ports, how does NMAP determine if a port is filtered?

Client            Server   
        ----> SYN

We see in this case that a SYN packet is sent from the client to the server but the server completely ignores the request. This is generally due to a firewall that simply blocks the request. Due to this, NMAP can’t determine if the port is open or closed, thus it is labeled as filtered.

There is even more to this, so feel free to read up on it in the link provided above. Here is the link again in case you missed it.

With the basic scan we conducted, NMAP makes a guess as to what service is running on the discovered port based on the nmap-services file. This file will be located at /etc/services on Linux/Mac and C:\windows\system32\drivers\etc\services on Windows.

To view the contents in a terminal, you can type the following commands.

# Linux and Mac
cat /etc/services

# Windows
type C:\windows\system32\drivers\etc\services

Here is an except from the file.

http             80/udp     www www-http # World Wide Web HTTP
http             80/tcp     www www-http # World Wide Web HTTP
ris             180/udp     # Intergraph
ris             180/tcp     # Intergraph
http-mgmt       280/udp     # http-mgmt
http-mgmt       280/tcp     # http-mgmt
is99s           380/udp     # TIA/EIA/IS-99 modem server
is99s           380/tcp     # TIA/EIA/IS-99 modem server
iafdbase        480/udp     # iafdbase
iafdbase        480/tcp     # iafdbase
sntp-heartbeat  580/udp	    # SNTP HEARTBEAT
sntp-heartbeat  580/tcp     # SNTP HEARTBEAT
entrust-aaas	680/udp     # entrust-aaas
entrust-aaas	680/tcp     # entrust-aaas
wpgs	    	780/udp     #
wpgs		    780/tcp     #
socks           1080/udp    # Socks
socks           1080/tcp    # Socks
mc-client       1180/udp    # Millicent Client Proxy
mc-client       1180/tcp    # Millicent Client Proxy
pictrography    1280/udp    # Pictrography

Although, most of the time these guesses will be correct, this is no guarantee. Just because we find an open port 80 doesn’t mean that HTTP is running on this port. Administrators can and do place services on non-standard ports. On top of this, we are provided the general service that is running but not the exact version.
If we want NMAP to attempt to detect the version of each service, we can add the -sV tag. I am going to run this command in the free NMAP room on TryHackMe.com. As a note, TryHackMe is a great place to start learning cyber-security. There are many free rooms and the paid rooms are well worth it (no affiliate links here, I’m just a fan).

nmap -sV 10.10.83.132

And here are the results.

Nmap scan report for ip-10-10-83-132.eu-west-1.compute.internal (10.10.83.132)
Host is up (0.00056s latency).
Not shown: 995 filtered ports
PORT     STATE SERVICE       VERSION
21/tcp   open  ftp           FileZilla ftpd
53/tcp   open  domain        Microsoft DNS
80/tcp   open  http          Microsoft IIS httpd 10.0
135/tcp  open  msrpc         Microsoft Windows RPC
3389/tcp open  ms-wbt-server Microsoft Terminal Services
MAC Address: 02:46:A5:CE:0C:6B (Unknown)
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 30.78 seconds

To gather this information, NMAP refers to the nmap-service-probes file to send protocol specific probes to talk directly to the service and grab version information. This file is located in your NMAP install under share/nmap/nmap-service-probes.

Here is an example output from the file.

##############################NEXT PROBE##############################
# DTLS Client Hello. Dissection available in nmap-payloads
Probe UDP DTLSSessionReq q|\x16\xfe\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x36\x01\x00\x00\x2a\x00\x00\x00\x00\x00\x00\x00\x2a\xfe\xfd\x00\x00\x00\x00\x7c\x77\x40\x1e\x8a\xc8\x22\xa0\xa0\x18\xff\x93\x08\xca\xac\x0a\x64\x2f\xc9\x22\x64\xbc\x08\xa8\x16\x89\x19\x30\x00\x00\x00\x02\x00\x2f\x01\x00|
rarity 5
ports 443,853,4433,4740,5349,5684,5868,6514,6636,8232,10161,10162,12346,12446,12546,12646,12746,12846,12946,13046

# OpenSSL 1.1.0 s_server -dtls -listen
# HelloVerifyRequest always uses DTLS 1.1 version, per RFC 6347
match dtls m|^\x16\xfe\xff\0\0\0\0\0\0\0\0..\x03...\0\0\0\0\0...\xfe\xff.|
# Except when it doesn't? This was from IKEA's E1526 Trådfri Gateway, but could be anything.
match dtls m|^\x16\xfe\xfd\0\0\0\0\0\0\0\0..\x03...\0\0\0\0\0...\xfe\xfd.|
# ServerHello
match dtls m|^\x16\xfe[\xfd\xff]\0\0\0\0\0\0\0\0..\x02...\0\0\0\0\0...\xfe[\xfd\xff].|

#DTLS 1.0 alert: Handshake Failure
match dtls m|^\x15\xfe\xff\0\0\0\0\0\0\0\0..\x02\(\0\0\0\0\0|

##############################NEXT PROBE##############################
# Detects iperf3 servers by sending a string longer than the 37-byte test identifer or cookie
# https://github.com/esnet/iperf/wiki/IperfProtocolStates#test-initiation
Probe TCP iperf3 q|0000000000000000000000000000000000000\0\0\0\0|
ports 5201
rarity 9
match iperf3 m|^\t$|

With this scan, we not only see the service as determined by the nmap-services file, but we are aldo provided with version information based on the nmap-service-probes file.
This will help validate the actual service running on the port and can also provide valuable vendor and version information. This will come in handy when developing a plan to attack a system.

Scanning Specific Ports

By default, NMAP will scan the top 1,000 ports when no flags are provided. However, we have a myriad of options on what ports to scan. There is a great chart on the NMAP website that lays out how many top ports in each protocol are required to reach a certain level of effectiveness. In this chart, we can see that we only need to scan the top 576 TCP ports to catch 90% of open ports. If time is of the essence, we have options to reduce the number of scanned ports to speed up the scan and still be relatively effective. On the other hand, we may want to leave no stone unturned to ensure to we don’t miss an obscure or undocumented open port. Furthermore, we may only be interested in scanning for specific services. We can dial in our scan to only search for our desired ports. Here are some examples we can use to add some specificity to our scans.

# Scan the top number of the ports specified in the command.
# In this case, we scan the top 100 tcp ports.
nmap --top-ports 100 10.10.83.132

# Scan a specific port
nmap -p 80 100 10.10.83.132

# Scan a specific protocol
nmap -p ssh 100.10.83.132

# Scan a specific protocol with a wildcard.
# In this case, we scan all services starting with http (http and https).
nmap -p http* 100.10.83.132

# Scan multiple ports
nmap -p 80,443,8080 100.10.83.132

# Scan a range of ports, in this case ports 100 through 200.
nmap -p 100-200 100.10.83.132

# Scan port starting at 1 through a given number, in this case 1-100.
nmap -p-100 100.10.83.132

# Scan all ports 1 through 65,535, all possible ports excluding 0.
nmap -p- 100.10.83.132

# Scan all ports as above, but include 0. 
# This command will cover every possible TCP port
nmap -p0- 100.10.83.132

OS Detection

NMAP has a great OS detection feature where it sends various TCP and UDP packets to the host. The responses may lead to a unique fingerprint of the hosts TCP/IP stack and allow NMAP to identify the running Operating System. If the fingerprint matches an entry in NMAP’s nmap-os-database file, the results will be provided in the scan. The nmap-os-database file is stored in your NMAP’s install location under share/nmap/nmap-os-db. Here is an excerpt from the file.

# SunOS 5.10 Generic_120012-14 i86pc i386 i86pc
Fingerprint Sun Solaris 10
Class Sun | Solaris | 10 | general purpose
CPE cpe:/o☀sunos:5.10 auto
SEQ(SP=8F-99%GCD=1-6%ISR=9F-A9%TI=I%II=I%SS=S%TS=6)
OPS(O1=NNT11M5B4NW0NNS%O2=NNT11M5B4NW0NNS%O3=NNT11M5B4NW0%O4=NNT11M5B4NW0NNS%O5=NNT11M5B4NW0NNS%O6=NNT11M5B4NNS)
WIN(W1=C050%W2=C330%W3=C1CC%W4=C068%W5=C068%W6=C0B7)
ECN(R=Y%DF=Y%T=3B-3D%TG=40%W=C1E8%O=M5B4NW0NNS%CC=Y%Q=)
T1(R=Y%DF=Y%T=3B-3D%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=N)
T4(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=N)
U1(DF=Y%T=FA-104%TG=FF%IPL=70%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)
IE(DFI=Y%T=FA-104%TG=FF%CD=S)

To run OS detection on an NMAP scan, use the -O flag. Let’s try scanning the scanme.nmap.org domain again.

nmap -O 10.10.184.124

Here is the result of the scan.

Nmap scan report for scanme.nmap.org (45.33.32.156)
Host is up (0.042s latency).
Not shown: 944 filtered tcp ports (no-response), 54 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
Aggressive OS guesses: Linux 5.0 - 5.4 (99%), Linux 5.4 (98%), Linux 4.15 - 5.6 (97%), Linux 5.1 (96%), Linux 2.6.32 - 3.13 (96%), Linux 5.0 - 5.3 (95%), Linux 2.6.22 - 2.6.36 (95%), Linux 3.10 - 4.11 (95%), Linux 5.0 (94%), Linux 3.10 (94%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 18 hops

OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 826.98 seconds

We can see in this case, we don’t have quite an exact match, but a high confidence level is given to a Linux operating system, and ranks the likelihood of various kernels. Even though we don’t know the exact Linux distribution running, making the distinction between a Linux and Windows box helps a great deal. Keep in mind that using the OS scan may not always be accurate and may not find any matches at all. You can add service detection to aid with determining what OS may be running. I will run a scan on the following TryHackMe room.

nmap -O -sV 10.10.213.235

This scan added OS detection as well as service detection. Here are the results.

Nmap scan report for ip-10-10-213-235.eu-west-1.compute.internal (10.10.213.235)
Host is up (0.0011s latency).
Not shown: 998 filtered ports
PORT     STATE SERVICE       VERSION
80/tcp   open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
3389/tcp open  ms-wbt-server Microsoft Terminal Services
MAC Address: 02:C9:BF:B4:43:6D (Unknown)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
OS fingerprint not ideal because: Missing a closed TCP port so results incomplete
No OS matches for host
Network Distance: 1 hop
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 46.12 seconds

Here, we can see that there were no matches for the OS on this scan. However, the Service Info provided implies that this is a Windows Box. The service versions detected in the port scan also confirm that this system is running some version of Windows.

NMAP Scripting Engine (NSE) Basics

The NMAP Scripting engine, or NSE, is a very powerful feature that allows a user to write and run scripts within NMAP. NMAP scripts are written in Lua. It is beyond the scope of this guide to cover writing your own scripts, we will cover the basics of using the scripts included with our NMAP install.

To start with, lets look at all the scripts included with NMAP when installed. We can find these in NMAP’s installation directory under share/nmap/scripts. Here is a brief listing when we look at the contents of this folder.

-rw-r--r--@   1 dale  admin   3.8K Sep  1 15:28 acarsd-info.nse
-rw-r--r--@   1 dale  admin   8.5K Sep  1 15:28 address-info.nse
-rw-r--r--@   1 dale  admin   3.3K Sep  1 15:28 afp-brute.nse
-rw-r--r--@   1 dale  admin   6.3K Sep  1 15:28 afp-ls.nse
-rw-r--r--@   1 dale  admin   6.8K Sep  1 15:28 afp-path-vuln.nse
-rw-r--r--@   1 dale  admin   5.5K Sep  1 15:28 afp-serverinfo.nse
-rw-r--r--@   1 dale  admin   2.6K Sep  1 15:28 afp-showmount.nse
-rw-r--r--@   1 dale  admin   2.2K Sep  1 15:28 ajp-auth.nse
-rw-r--r--@   1 dale  admin   2.9K Sep  1 15:28 ajp-brute.nse
-rw-r--r--@   1 dale  admin   1.3K Sep  1 15:28 ajp-headers.nse
-rw-r--r--@   1 dale  admin   2.5K Sep  1 15:28 ajp-methods.nse
-rw-r--r--@   1 dale  admin   3.0K Sep  1 15:28 ajp-request.nse
-rw-r--r--@   1 dale  admin   6.6K Sep  1 15:28 allseeingeye-info.nse
-rw-r--r--@   1 dale  admin   1.6K Sep  1 15:28 amqp-info.nse

As we can see, all nmap scripts end in the .nse file extension. Another interesting file that is located under this same directory is the script.db file. This file contains information regarding the categories each script belongs to. Here is a short excerpt of the file.

Entry { filename = "acarsd-info.nse", categories = { "discovery", "safe", } }
Entry { filename = "address-info.nse", categories = { "default", "safe", } }
Entry { filename = "afp-brute.nse", categories = { "brute", "intrusive", } }
Entry { filename = "afp-ls.nse", categories = { "discovery", "safe", } }
Entry { filename = "afp-path-vuln.nse", categories = { "exploit", "intrusive", "vuln", } }
Entry { filename = "afp-serverinfo.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "afp-showmount.nse", categories = { "discovery", "safe", } }
Entry { filename = "ajp-auth.nse", categories = { "auth", "default", "safe", } }
Entry { filename = "ajp-brute.nse", categories = { "brute", "intrusive", } }
Entry { filename = "ajp-headers.nse", categories = { "discovery", "safe", } }
Entry { filename = "ajp-methods.nse", categories = { "default", "safe", } }
Entry { filename = "ajp-request.nse", categories = { "discovery", "safe", } }
Entry { filename = "allseeingeye-info.nse", categories = { "discovery", "safe", "version", } }
Entry { filename = "amqp-info.nse", categories = { "default", "discovery", "safe", "version", } }
Entry { filename = "asn-query.nse", categories = { "discovery", "external", "safe", } }
Entry { filename = "auth-owners.nse", categories = { "default", "safe", } }
Entry { filename = "auth-spoof.nse", categories = { "malware", "safe", } }

The simplest way to get started is to add the -sC flag to our NMAP scan. This will run all scripts labeled “default” under the script.db file. We can grep out default when listing out this file to see what scripts will run.

Entry { filename = "address-info.nse", categories = { "default", "safe", } }
Entry { filename = "afp-serverinfo.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "ajp-auth.nse", categories = { "auth", "default", "safe", } }
Entry { filename = "ajp-methods.nse", categories = { "default", "safe", } }
Entry { filename = "amqp-info.nse", categories = { "default", "discovery", "safe", "version", } }
Entry { filename = "auth-owners.nse", categories = { "default", "safe", } }
Entry { filename = "backorifice-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "bitcoinrpc-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "cassandra-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "clock-skew.nse", categories = { "default", "safe", } }

Here is the command we will run. The target with be this TryHackMe room.

nmap -sC 10.10.213.235

And here is the result.

Nmap scan report for ip-10-10-213-235.eu-west-1.compute.internal (10.10.213.235)
Host is up (0.00055s latency).
Not shown: 998 filtered ports
PORT     STATE SERVICE
80/tcp   open  http
| http-robots.txt: 4 disallowed entries 
|_/bin/ /config/ /umbraco/ /umbraco_client/
|_http-title: Anthem.com - Welcome to our blog
3389/tcp open  ms-wbt-server
| ssl-cert: Subject: commonName=WIN-LU09299160F
| Not valid before: 2023-02-03T20:22:25
|_Not valid after:  2023-08-05T20:22:25
|_ssl-date: 2023-02-04T22:08:05+00:00; 0s from scanner time.
MAC Address: 02:C9:BF:B4:43:6D (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 18.95 seconds

With this scan, all the scripts with “default” listed as one of their categories will run against the host. In this case, we see that we gathered more information regarding the open port 80 web server and the open 3389 Windows Terminal Server (Remote Desktop) service.

There are several options available to run the scripts that we want. Here are several examples.

Run a Specific Script

Let’s run the http-sitemap-generator script to see what output we get.

nmap --script "http-sitemap-generator" 10.10.213.235

This script attempts to map our the directory structure of the site. Here is an example of the output.

Nmap scan report for ip-10-10-213-235.eu-west-1.compute.internal (10.10.213.235)
Host is up (0.00057s latency).
Not shown: 998 filtered ports
PORT     STATE SERVICE
80/tcp   open  http
| http-sitemap-generator: 
|   Directory structure:
|     /
|       Other: 5; axd: 1
|     /Author/1076/
|       Other: 1
|     /archive/a-cheers-to-our-it-department/
|       Other: 1
|     /archive/we-are-hiring/
|       Other: 1
|     /authors/jane-doe/
|       Other: 1
|     /media/articulate/default/
|       jpg: 1
|     /opensearch/
|       Other: 1
|     /rsd/
|       Other: 1
|     /rss/
|       Other: 1
|     /wlwmanifest/
|       Other: 1
|   Longest directory structure:
|     Depth: 3
|     Dir: /media/articulate/default/
|   Total files found (by extension):
|_    Other: 13; axd: 1; jpg: 1
3389/tcp open  ms-wbt-server
MAC Address: 02:C9:BF:B4:43:6D (Unknown)

Using Wildcards When Running Scripts

We can use wildcards when running scripts as well. Since we have a web server in the above scan, let’s try to run all scripts with “vuln” in their name. We will modify and run the script as follows.

nmap --script "*vuln*" 10.10.254.183

This command will run all scripts with “vuln” somewhere in the name. The * character simply means any character or nothing. Basically, we run a script with a name that can start with anything (or nothing) and ends with anything (or nothing). As long as the script has “vuln” somewhere in the name it will run. We wil run this scan in this TryHackMe Room. Here are the results that are returned.

Nmap scan report for ip-10-10-254-183.eu-west-1.compute.internal (10.10.254.183)
Host is up (0.00048s latency).
Not shown: 991 closed ports
PORT      STATE SERVICE
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
3389/tcp  open  ms-wbt-server
| rdp-vuln-ms12-020: 
|   VULNERABLE:
|   MS12-020 Remote Desktop Protocol Denial Of Service Vulnerability
|     State: VULNERABLE
|     IDs:  CVE:CVE-2012-0152
|     Risk factor: Medium  CVSSv2: 4.3 (MEDIUM) (AV:N/AC:M/Au:N/C:N/I:N/A:P)
|           Remote Desktop Protocol vulnerability that could allow remote attackers to cause a denial of service.
|           
|     Disclosure date: 2012-03-13
|     References:
|       http://technet.microsoft.com/en-us/security/bulletin/ms12-020
|       https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-0152
|   
|   MS12-020 Remote Desktop Protocol Remote Code Execution Vulnerability
|     State: VULNERABLE
|     IDs:  CVE:CVE-2012-0002
|     Risk factor: High  CVSSv2: 9.3 (HIGH) (AV:N/AC:M/Au:N/C:C/I:C/A:C)
|           Remote Desktop Protocol vulnerability that could allow remote attackers to execute arbitrary code on the targeted system.
|           
|     Disclosure date: 2012-03-13
|     References:
|       http://technet.microsoft.com/en-us/security/bulletin/ms12-020
|_      https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-0002
49152/tcp open  unknown
49153/tcp open  unknown
49154/tcp open  unknown
49158/tcp open  unknown
49160/tcp open  unknown
MAC Address: 02:AA:F2:1F:CF:D5 (Unknown)

Host script results:
|_samba-vuln-cve-2012-1182: NT_STATUS_ACCESS_DENIED
|_smb-vuln-ms10-054: false
|_smb-vuln-ms10-061: NT_STATUS_ACCESS_DENIED
| smb-vuln-ms17-010: 
|   VULNERABLE:
|   Remote Code Execution vulnerability in Microsoft SMBv1 servers (ms17-010)
|     State: VULNERABLE
|     IDs:  CVE:CVE-2017-0143
|     Risk factor: HIGH
|       A critical remote code execution vulnerability exists in Microsoft SMBv1
|        servers (ms17-010).
|           
|     Disclosure date: 2017-03-14
|     References:
|       https://blogs.technet.microsoft.com/msrc/2017/05/12/customer-guidance-for-wannacrypt-attacks/
|       https://technet.microsoft.com/en-us/library/security/ms17-010.aspx
|_      https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-0143

Nmap done: 1 IP address (1 host up) scanned in 85.89 seconds

We can see that the scripts returned results for a few possible vulnerabilities the system may have. Booyah!

Running a Specific Script Category

As we saw from the script.db file, all scripts have one or more categories applied to them. The NMAP documentation gives us a list and description of these categories. To run a script in a given category, we simply include the name in the command.

nmap --script discovery 10.10.254.183

Here are the results of the scan.

Nmap scan report for ip-10-10-254-183.eu-west-1.compute.internal (10.10.254.183)
Host is up (0.00052s latency).
Not shown: 991 closed ports
PORT      STATE SERVICE
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
3389/tcp  open  ms-wbt-server
| rdp-enum-encryption: 
|   Security layer
|     CredSSP: SUCCESS
|     Native RDP: SUCCESS
|     SSL: SUCCESS
|   RDP Encryption level: Client Compatible
|     40-bit RC4: SUCCESS
|     56-bit RC4: SUCCESS
|     128-bit RC4: SUCCESS
|_    FIPS 140-1: SUCCESS
| ssl-cert: Subject: commonName=Jon-PC
| Not valid before: 2023-02-03T22:50:27
|_Not valid after:  2023-08-05T22:50:27
|_ssl-date: 2023-02-04T23:00:30+00:00; 0s from scanner time.
| ssl-enum-ciphers: 
|   TLSv1.0: 
|     ciphers: 
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|     compressors: 
|       NULL
|     cipher preference: server
|     warnings: 
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|       Broken cipher RC4 is deprecated by RFC 7465
|       Ciphersuite uses MD5 for message integrity
|       Weak certificate signature: SHA1
|_  least strength: C
49152/tcp open  unknown
49153/tcp open  unknown
49154/tcp open  unknown
49158/tcp open  unknown
49160/tcp open  unknown
MAC Address: 02:AA:F2:1F:CF:D5 (Unknown)

Host script results:
| dns-brute: 
|   DNS Brute-force hostnames: 
|_    ns0.eu-west-1.compute.internal - 172.16.0.23
|_fcrdns: PASS (ip-10-10-254-183.eu-west-1.compute.internal)
|_ipidseq: Unknown
|_msrpc-enum: NT_STATUS_ACCESS_DENIED
|_nbstat: NetBIOS name: JON-PC, NetBIOS user: <unknown>, NetBIOS MAC: 02:aa:f2:1f:cf:d5 (unknown)
|_path-mtu: PMTU == 9001
| qscan: 
| PORT   FAMILY  MEAN (us)  STDDEV   LOSS (%)
| 1      0       484.67     38.07    40.0%
| 135    0       529.25     58.59    60.0%
| 139    0       557.71     160.89   30.0%
| 445    0       476.50     38.53    60.0%
| 3389   0       566.17     115.37   40.0%
| 49152  0       531.25     64.26    60.0%
| 49153  0       2268.60    3936.85  50.0%
| 49154  0       515.20     24.46    50.0%
|_49158  0       509.25     27.28    60.0%
| smb-enum-shares: 
|   note: ERROR: Enumerating shares failed, guessing at common ones (NT_STATUS_ACCESS_DENIED)
|   account_used: <blank>
|   \\10.10.254.183\ADMIN$: 
|     warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED
|     Anonymous access: <none>
|   \\10.10.254.183\C$: 
|     warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED
|     Anonymous access: <none>
|   \\10.10.254.183\IPC$: 
|     warning: Couldn't get details for share: NT_STATUS_ACCESS_DENIED
|_    Anonymous access: READ
| smb-mbenum: 
|   Master Browser
|     JON-PC  6.1  
|   Potential Browser
|     JON-PC  6.1  
|   Server service
|     JON-PC  6.1  
|   Windows NT/2000/XP/2003 server
|     JON-PC  6.1  
|   Workstation
|_    JON-PC  6.1  
| smb-os-discovery: 
|   OS: Windows 7 Professional 7601 Service Pack 1 (Windows 7 Professional 6.1)
|   OS CPE: cpe:/o:microsoft:windows_7::sp1:professional
|   Computer name: Jon-PC
|   NetBIOS computer name: JON-PC\x00
|   Workgroup: WORKGROUP\x00
|_  System time: 2023-02-04T17:00:32-06:00
| smb-protocols: 
|   dialects: 
|     NT LM 0.12 (SMBv1) [dangerous, but default]
|     2.02
|_    2.10
| smb-security-mode: 
|   account_used: <blank>
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-capabilities: 
|   2.02: 
|     Distributed File System
|   2.10: 
|     Distributed File System
|     Leasing
|_    Multi-credit operations
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2023-02-04 23:00:34
|_  start_date: 2023-02-04 22:50:26

Nmap done: 1 IP address (1 host up) scanned in 101.65 seconds

The result of this scan provides a wealth of useful information regarding the target system.

As we can see, there are many options we can use to get extra information about a host. Keep these things in mind. Many of the available scripts ire time-consuming to run, so be patient. Also, many of the scans are intrusive, so be careful where you run them, and NEVER run them on systems you down not own or have permission to scan.

I definitely recommend having a look at the NMAP documentation regarding the NMAP Scripting Engine, as there are even more options available to you.

Running All The Things!

Many of the items we’ve discussed so far are pretty common to run. Luckily, NMAP provides us an option to wrap many of these commands into one flag. By adding the -A flag, we include OS Detection, version detection, default scripts, and add traceroute information all in one go!

nmap -A 10.10.254.183

Here are the results.

Nmap scan report for ip-10-10-254-183.eu-west-1.compute.internal (10.10.254.183)
Host is up (0.0044s latency).
Not shown: 991 closed ports
PORT      STATE SERVICE       VERSION
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds  Windows 7 Professional 7601 Service Pack 1 microsoft-ds (workgroup: WORKGROUP)
3389/tcp  open  ms-wbt-server Microsoft Terminal Service
| ssl-cert: Subject: commonName=Jon-PC
| Not valid before: 2023-02-03T22:50:27
|_Not valid after:  2023-08-05T22:50:27
|_ssl-date: 2023-02-04T23:11:42+00:00; 0s from scanner time.
49152/tcp open  msrpc         Microsoft Windows RPC
49153/tcp open  msrpc         Microsoft Windows RPC
49154/tcp open  msrpc         Microsoft Windows RPC
49158/tcp open  msrpc         Microsoft Windows RPC
49160/tcp open  msrpc         Microsoft Windows RPC
MAC Address: 02:AA:F2:1F:CF:D5 (Unknown)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.60%E=4%D=2/4%OT=135%CT=1%CU=36142%PV=Y%DS=1%DC=D%G=Y%M=02AAF2%T
OS:M=63DEE633%P=x86_64-pc-linux-gnu)SEQ(SP=106%GCD=1%ISR=110%TI=I%CI=I%TS=7
OS:)SEQ(SP=106%GCD=1%ISR=110%TI=I%CI=RD%II=I%SS=S%TS=7)OPS(O1=M2301NW8ST11%
OS:O2=M2301NW8ST11%O3=M2301NW8NNT11%O4=M2301NW8ST11%O5=M2301NW8ST11%O6=M230
OS:1ST11)WIN(W1=2000%W2=2000%W3=2000%W4=2000%W5=2000%W6=2000)ECN(R=Y%DF=Y%T
OS:=80%W=2000%O=M2301NW8NNS%CC=N%Q=)T1(R=Y%DF=Y%T=80%S=O%A=S+%F=AS%RD=0%Q=)
OS:T2(R=Y%DF=Y%T=80%W=0%S=Z%A=S%F=AR%O=%RD=0%Q=)T3(R=Y%DF=Y%T=80%W=0%S=Z%A=
OS:O%F=AR%O=%RD=0%Q=)T4(R=Y%DF=Y%T=80%W=0%S=A%A=O%F=R%O=%RD=0%Q=)T5(R=Y%DF=
OS:Y%T=80%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=80%W=0%S=A%A=O%F=R%O=%
OS:RD=0%Q=)T7(R=Y%DF=Y%T=80%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=80%I
OS:PL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=80%CD=Z)

Network Distance: 1 hop
Service Info: Host: JON-PC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_nbstat: NetBIOS name: JON-PC, NetBIOS user: <unknown>, NetBIOS MAC: 02:aa:f2:1f:cf:d5 (unknown)
| smb-os-discovery:
|   OS: Windows 7 Professional 7601 Service Pack 1 (Windows 7 Professional 6.1)
|   OS CPE: cpe:/o:microsoft:windows_7::sp1:professional
|   Computer name: Jon-PC
|   NetBIOS computer name: JON-PC\x00
|   Workgroup: WORKGROUP\x00
|_  System time: 2023-02-04T17:11:42-06:00
| smb-security-mode:
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-security-mode:
|   2.02:
|_    Message signing enabled but not required
| smb2-time:
|   date: 2023-02-04 23:11:42
|_  start_date: 2023-02-04 22:50:26

TRACEROUTE
HOP RTT     ADDRESS
1   4.38 ms ip-10-10-254-183.eu-west-1.compute.internal (10.10.254.183)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 153.02 seconds

This is the equivalent of running the following command.

nmap -O -sV -sC --traceroute 10.10.254.183

As we can see, the -A flag saves us a few keystrokes and more importantly makes the command much easier to remember.

UDP Scans

Although most services will run on the TCP protocol, there are still protocols that will be listening on the UDP protocol. Some of the more common ones are DNS (port 53), SNMP (ports 161/162), and DHCP (ports 67/68). Unlike TCP, UDP is a connectionless protocol. There is no 3 way handshake with a UDP packet. Basically, the packet is sent, and if received, the service will handle the packet and reply if necessary. Since there is no handshake involved, NMAP will have a more difficult time determining the true status of a UDP port. More on that in a minute, let’s just start a basic UDP scan.

To conduct a UDP scan, just include the -sU flag. Be patient with this one! UDP scans are slow.

nmap -sU 10.10.84.46

Here are the results of the scan.

Nmap scan report for ip-10-10-84-46.eu-west-1.compute.internal (10.10.84.46)
Host is up (0.0060s latency).
Not shown: 995 closed ports
PORT     STATE         SERVICE
137/udp  open          netbios-ns
138/udp  open|filtered netbios-dgm
500/udp  open|filtered isakmp
4500/udp open|filtered nat-t-ike
5355/udp open|filtered llmnr
MAC Address: 02:8B:AA:96:96:25 (Unknown)

NMAP determines port status for the UDP protocol based on the following criteria.

  • Closed: Port receives an ICMP port unreachable error (Type 3, Code 3).

  • Filtered: Other ICMP port unreachable error (Type 3, Code 1, 2, 9, 10, or 13).

  • Open|Filtered: NMAP receives no response from probe.

  • Open: NMAP receives a response from probe.

Based on this chart, we can see that port 137 is definitely up, as we received a response. The open|filtered ports did not respond. Since UDP protocols require a specific messaging format unique to the protocol, an improperly formatted UDP message will not trigger a response. Due to this, we cannot determine if the non-responsive ports are open or filtered.

I definitely recommend reading the NMAP documentation for the lowdown on UDP scans in general.

I am also including a link to the different ICMP codes to help you understand the codes mentioned in the chart above.

To help increase the effectiveness of our NMAP probes, we can add the -sV flag to add service detection. As mentioned in the banner grabbing section, NMAP will use the nmap-service-probes file to handcraft protocol specific packets to increase the odds of a response from the service.

To simplify the flag, we can add it to the UDP flag.

nmap -sUV 10.10.84.46

Since this scan will send specific probes to open|filtered protocols based on the nmap-service-probes file, we may grab version information and thus determine that the port is indeed open.

Dialing In Our Scans

In this section, I will cover a few commands that I use to dial in NMAP scans. I felt that these options didn’t necessarily warrant their own section, but are useful enough to bring up.

Script Timing

We can use the -T flag to lower or increase the speed of our scans. The levels are 0 through 5. Here is an example.

nmap -T5 scanme.nmap.org

This will send packets at the most aggressive level.

Each integer value also has a corresponding noun name: paranoid (0), sneaky (1), polite (2), normal (3), aggressive (4), and insane (5).

So the equivalent of the above command by using the noun name would be as follows.

nmap -T insane scanme.nmap.org

Here are some general points with timing.

  • Level paranoid (0) and sneaky (1) are for IDS evasion.
  • Level polite (2) is generally to slow things down to use less resources on the target system.
  • Level normal (3) is the standard speed when no option is selected, thus there is no need to use this.

I generally use level aggressive (4) when scanning in CTF type boxes. It seems to be the best tradeoff of speed and stability.
Level insane (5) seems to go at a rate where packets can be missed, and increasing the chance that we miss something.

nmap -T4 scanme.nmap.org

There are other timing options available as well. Have a look at the documentation!

Scan Verbosity

When scanning, we do not receive any feedback as to the scan status. We can tap on any key while the scan is running to get a general completion status of the scan. For my taste, I like to know that my tool isn’t hanging as well as to see some useful information when ports are found open so that I can have a look while my scan is still running.

By adding the -v flag, we will get some useful information in our terminal every so often. I prefer to use the -vv option which adds the maximum amount of information.

nmap -vv 10.10.84.46

Here is some example verbose output.

Scanning ip-10-10-84-46.eu-west-1.compute.internal (10.10.84.46) [1000 ports]
Discovered open port 135/tcp on 10.10.84.46
Discovered open port 3389/tcp on 10.10.84.46
Discovered open port 139/tcp on 10.10.84.46
Discovered open port 445/tcp on 10.10.84.46

We can see here that open ports are displayed as soon as discovered. This allows us to go have a look at these services while the scan is still running.

Output To Files

NMAP offers several options for outputting to different file formats. Here is a list.

  • -oN Output the file the same way we see it displayed in the terminal.
  • -oX Output the file in XML format.
  • -oG Output the file in a grep friendly format.
  • -oA Output in all the above formats.

Outputting our input to a file is a great way to keep this information handy to review at a later time and not have to run another scan. I prefer to use the -oA option, and I generally place this flag last in my command.

nmap scanme.nmap.org -oA chosen_file_name

The files will be given the appropriate file extension name for each format with the name you provided in the flag.

Discovery Scan Techniques

In most CTF’s, you will be given the IP address or hostname of the device you are working with, so many of these techniques will not apply in this case. However, if you are in an environment where many devices exist, there are several useful flags to help with discovering what devices are live on the network. This will allow you to limit your port scans to only the online IP’s that you discover. You can also do DNS lookups on an IP range to see if you can gather any juicy DNS information. This is also good for a sanity check to make sure you are scanning the correct IP. Let’s go over a few of these.

Scanning multiple devices

NMAP gives you the flexibility to scan many hosts at once. Here are several examples to provide input for multiple devices.

# Provide multiple IP's/DNS names by separating with a space
nmap 192.168.1.1 192.168.1.2

# Scan IP range in CIDR notation
nmap 192.168.1.0/24

# Scan a range in an octet. 
# The below command will scan IP 192.168.1.10 through 192.168.1.20
nmap 192.168.1.10-20

# You can use the above in any octet. 
# The below will scan 192.168.10.1, 192.168.11.1, and so on through 192.168.20.1
nmap 192.168.10-20.1

# Scan select IP's in an octet. 
# The below will scan 192.168.1.2, 192.168.1.10, and 192.168.1.18
nmap 192.168.1.2,10,18

# Mix and match the above!
nmap 192.168.10-20.1-10,22,55

List Scan

A list scan will run a DNS lookup on provided domains or a reverse DNS lookup on the IP’s provided. We define a List Scan with the -sL flag. Let’s start a List Scan of scanme.nmap.org

nmap -sL scanme.nmap.org
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-25 15:50 PDT
Nmap scan report for scanme.nmap.org (45.33.32.156)
Nmap done: 1 IP address (0 hosts up) scanned in 0.37 seconds

This does a DNS lookup on scanme.nmap.org to give us the IP of 45.33.32.156. Now we can run a List Scan with the entire /24 IP range and see if nmap.org has any other devices. I will abbreviate some of the output since we get a report for all 255 IP addresses.

nmap -sL 45.33.32.0/24
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-25 15:48 PDT

# Abbreviated Output
Nmap scan report for unifi.tonythedeveloper.cloud (45.33.32.150)
Nmap scan report for 45-33-32-151.ip.linodeusercontent.com (45.33.32.151)
Nmap scan report for 45-33-32-152.ip.linodeusercontent.com (45.33.32.152)
Nmap scan report for li982-153.members.linode.com (45.33.32.153)
Nmap scan report for web.discreet-logic.com (45.33.32.154)
Nmap scan report for li982-155.members.linode.com (45.33.32.155)
Nmap scan report for scanme.nmap.org (45.33.32.156)
Nmap scan report for 45-33-32-157.ip.linodeusercontent.com (45.33.32.157)
Nmap scan report for 45-33-32-158.ip.linodeusercontent.com (45.33.32.158)
Nmap scan report for li982-159.members.linode.com (45.33.32.159)
Nmap scan report for iktechcorp.com (45.33.32.160)

We see output from multiple devices, but none have the nmap.org domain name. Keep in mind that this scan is not intrusive and is simply doing a reverse DNS lookup on all IP’s that we provided. This technique could help save your butt if you were given invalid IP’s to scan. For an example of this, checkout this Darknet Diaries episode.

Ping Scan

If we have multiple devices in a network, it might be a good idea to get an idea of what devices are online before we start a full port scan. With NMAP, we can omit the port scan portion of the scan with the -sn flag. This will only determine whether the host is live or not. This is also known as a ping sweep. In the scan below, we will perform a ping sweep on a range of IP’s and store the file for further processing.

# Scan 192.168.0.100 through 192.168.0.200.
# Store the restults as standard format to nmap_live.txt
nmap -sn 192.168.0.100-200 -oN nmap_live.txt

# Abbreviated output
Nmap scan report for 192.168.0.102
Host is up (0.067s latency).
MAC Address: FC:B3:BC:0F:C8:0A (Intel Corporate)
Nmap scan report for 192.168.0.108
Host is up (0.036s latency).
MAC Address: 62:99:6C:BC:BF:87 (Unknown)
Nmap scan report for 192.168.0.111

This scan is useful as it gives you a live IP list that you can further process. Here is a nice bash one liner to process the above file into a valid IP list.

# Get the line of the output with the IP address and remove the rest of the output from the line.
cat nmap_live.txt | grep 'report' | cut -d ' ' -f 5 > live_hosts.txt

# We are left with a list of IP's which are live
cat live_hosts.txt
192.168.0.102
192.168.0.108
192.168.0.111
192.168.0.141
192.168.0.145
192.168.0.161

Provide target input through a file

In the previous section, we created a list of live IP’s and saved them to file. We can further provide this file to NMAP as a target list for scanning. To do this, we simply add the -iL flag and the name of the file.
As a sidenote, if the IP list you created contains your own attack machine IP, you might want to remove it from the list.

# Scan with list as input
nmap -iL live_hosts.txt

My Scan of Choice

With all of this information said, here is the scans I generally fire up when staring a new CTF box.

# TCP Scan
nmap -A -T4 -p0- -vv 10.10.84.46 -oA TCP_10.10.84.46

# UDP Scan
nmap -sUV -T4 -vv 10.10.84.46 -oA UDP_10.10.84.46

For my TCP scans, this will use -A to get OS information, banner grab, and run default scripts. We will go at the fastest speed that returns reliable results with -T4, and we will scan every single port from 0-65,535. We will add verbose reporting with -vv and save a file named TCP_10.10.84.46 with the appropriate extension for nmap/grepable/xml formats.

For our UDP scan, we define the scan and add service detection with -sUV, we add some reliable speed with -T4, and add verbosity to our scan with -vv. I generally stick with the standard top 1,000 ports by adding no option for port selection, since UDP scans go very slow. We then save a file named UDP_10.10.84.46 in nmap/grebable/xml formats.

Parting Notes

This pretty much wraps up my NMAP starter guide and my very first post on this site! I feel that the information provided gets you to 80% of what you need to know with NMAP, at least in my experience so far with using it in a CTF environment. I have some other guides planned that will cover some more specific scanning techniques, but this guide should have everything you need to get started and be relatively proficient with this tool. Ok, time to go forth and find open ports. Remember…scan responsibly!