Nmap for pentesting: port scanning commands step by step

How to scan a box with nmap like in a pentest: sweep all 65535 ports, versions and NSE scripts, UDP and how to read the output, with Hack The Box examples.

· 6 min read

Every box starts the same way: a port scan. Miss a port and you miss the way in. This guide is the workflow almost every Hack The Box writeup uses (and the one you want for the OSCP): two TCP passes and one UDP pass, always saving the output, with the exact commands and what you should see at each step.

Tip

Practise each step against an easy retired box, for example Nibbles (Linux) or Blue (Windows). Retired machines are legal to attack because they live in the Hack The Box lab, which you reach over VPN. Do not scan anything you do not own or have written permission to test.

Requirements

  • Kali, Parrot or any Linux with nmap (sudo apt install nmap). Use sudo: as root, nmap runs a SYN scan (-sS), which is faster and more reliable than a full connect scan.
  • A connection to the HTB VPN (sudo openvpn lab_user.ovpn) and the box IP, which here is 10.10.10.75.
  • One folder per box to keep the output: mkdir -p nibbles/nmap && cd nibbles.

Step 0: is it up? Linux or Windows?

ping -c 1 10.10.10.75
64 bytes from 10.10.10.75: icmp_seq=1 ttl=63 time=38.2 ms

The TTL hints at the operating system: Linux starts at 64 and Windows at 128, and the HTB VPN takes one hop off. 63 is almost certainly Linux; 127, Windows. If ping gets no answer, that is fine: many Windows boxes block ICMP, which is why the next commands use -Pn.

Step 1: every TCP port, fast

By default nmap only checks the 1000 most common ports. On HTB the way in is often on a high port (an 8808, a 50051...), so the first scan covers all 65535:

sudo nmap -p- --min-rate 5000 -n -Pn -oA nmap/all 10.10.10.75
Option What it does
-p- Every port, 1 to 65535
--min-rate 5000 At least 5000 packets per second: under a minute instead of 15
-n No DNS resolution (faster)
-Pn Skip the host discovery check: scan anyway
-oA nmap/all Save the output in all three formats (.nmap, .gnmap, .xml)

Expected output on Nibbles:

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Warning

A high --min-rate on a slow network can drop ports. If something looks missing (a website that does not show up, a domain without Kerberos on 88), repeat with --min-rate 1000 or without that option.

Step 2: versions and scripts on the open ports only

Now the slow, detailed scan, but only against the ports you found. Pull the list out of the .gnmap file instead of copying it by hand:

ports=$(grep -oP '\d+(?=/open)' nmap/all.gnmap | paste -sd,)
echo $ports        # 22,80
sudo nmap -p$ports -sCV -oA nmap/services 10.10.10.75

-sV detects the service and its exact version, and -sC runs the default NSE scripts (page titles, HTTP methods, SMB null sessions, certificates...). Output (trimmed):

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.18 (Ubuntu)

Step 3: read the output like a pentester

A scan is not a list of ports: it is a list of questions. What you should take from the output above:

  • The exact OS release. The package OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 only ships with Ubuntu 16.04: look it up on Google or Launchpad. Now you know whether a kernel exploit is plausible.
  • Every version goes into searchsploit. searchsploit apache 2.4.18 and searchsploit openssh 7.2. The guide on how to exploit a public CVE covers it.
  • Domain names. If a script shows Did not follow redirect to http://something.htb/, add it to /etc/hosts and look for subdomains (directory and vhost fuzzing).
  • The port combination. 53 + 88 + 389 + 445 is a domain controller (start with Active Directory enumeration); 139 + 445 without 88 is a plain Windows or Samba host (SMB and NFS enumeration).

A quick cheat sheet of what to do with each port:

Port Service First thing to try
21 FTP ftp 10.10.10.75 as anonymous with no password
22 SSH Only with credentials or a key: keep it for later
80, 443, 8080 HTTP Open it in the browser, read the source and start fuzzing
139, 445 SMB nxc smb IP -u '' -p '' --shares
161/udp SNMP snmpwalk -v2c -c public IP (SNMP enumeration)
1433 MSSQL Default credentials and MSSQL attacks
3306 MySQL Only with credentials, except very old versions
5985 WinRM evil-winrm as soon as you have a user

Step 4: UDP, the one everybody skips

UDP scanning is slow (there is no handshake and nmap has to wait for nothing to arrive), so limit the ports:

sudo nmap -sU --top-ports 20 -n -Pn -oA nmap/udp 10.10.10.75

You will see lots of open|filtered: that means "I don't know". The ones that matter show as open. The classic HTB case is 161/udp (SNMP), which can hand you processes with passwords in their arguments, as on Pandora. To confirm a specific port add -sV: sudo nmap -sU -sV -p161 10.10.10.75.

Step 5: specific NSE scripts

Beyond the -sC ones, nmap ships with more than 600 scripts in /usr/share/nmap/scripts. To find the ones for a service and see what one does:

ls /usr/share/nmap/scripts | grep smb
nmap --script-help smb-vuln-ms17-010

The classic example is Blue, a Windows 7 box vulnerable to EternalBlue:

sudo nmap -p445 --script smb-vuln-ms17-010 10.10.10.40
| smb-vuln-ms17-010:
|   VULNERABLE:
|   Remote Code Execution vulnerability in Microsoft SMBv1 servers (ms17-010)
|     State: VULNERABLE

Other useful ones: --script vuln (every vulnerability check, noisy), http-enum (well-known paths on a website) and ssl-cert (domain names in the certificate on a 443).

All together in a script

To run the same workflow on every box without thinking, save this as scan.sh:

#!/bin/bash
# Usage: ./scan.sh 10.10.10.75
ip=$1; mkdir -p nmap
sudo nmap -p- --min-rate 5000 -n -Pn -oA nmap/all "$ip"
ports=$(grep -oP '\d+(?=/open)' nmap/all.gnmap | paste -sd,)
sudo nmap -p"$ports" -sCV -oA nmap/services "$ip"
sudo nmap -sU --top-ports 20 -n -Pn -oA nmap/udp "$ip"

While the UDP scan runs, you can already look at the website.

Common errors

  • Note: Host seems down: the host does not answer ping. Add -Pn.
  • Every port filtered: the VPN dropped or the box has not finished booting. Ping it and scan again after a minute.
  • tcpwrapped: the port accepts the connection and closes it straight away. Usually a service that only talks to certain IPs or needs something specific; try connecting with nc -nv IP port.
  • Ports another writeup sees are missing: almost always a --min-rate that is too high or a box that rebooted. Repeat step 1 more slowly.
  • -sC takes forever: you are running it against all 65535 ports. Only run it on the list from step 2.

What next

Tick each step in the recon checklist, keep the nmap cheat sheet at hand and see the Nmap tool page for more options. If you are just starting, the Zero to OSCP path takes you from this first scan to your first domain, and the list of HTB machines to prepare for the OSCP tells you where to start.

Spotted a mistake or something missing? Tell us