Nmap

Network scanner that discovers hosts, open ports, running services, and OS versions. The absolute first tool you run on every single engagement.

Linux Windows CPTS C Linux (attacker)
LevelBeginner. This is the first tool you run on any engagement, so start here.
Know firstWhat an IP address and a port are, the difference between TCP and UDP, and how to run a command in a Linux terminal.
You will learn toscan a host, say what each port state means, and choose what to enumerate next from the open ports.

What is it?

Nmap (Network Mapper) is a port scanner. It sends packets to a target and analyzes the responses to determine which ports are open, what services are running on them, and often what version of those services are deployed.

Every networked application listens on a port. A web server listens on port 80/443. SSH on 22. SMB on 445. RDP on 3389. When you scan a target with Nmap, you're asking: "Which doors are open on this machine?" Every open port is a potential attack surface.

Nmap does more than just find open ports. It can:

  • Fingerprint services: determine not just "port 80 is open" but "Apache 2.4.51 is running on port 80"
  • Run scripts: Nmap has a scripting engine (NSE) with hundreds of scripts that check for vulnerabilities, enumerate users, brute-force credentials, and more
  • Detect the OS: determine if the target runs Windows Server 2019 or Ubuntu 22.04
  • Map networks: discover which hosts are alive on a subnet

Run this first

If you learn one command, learn this one. Make a folder for results, then scan the target and save the output.

bash: your first scan
# Replace the address with your target
$ mkdir scan
$ nmap -sC -sV -oN scan/first 10.10.10.10
  • -sC runs Nmap's default scripts, which pull out details like page titles and certificate names.
  • -sV asks each open port which program and version is behind it.
  • -oN scan/first saves the result to a file, so you can read it again later.

You get a table with one row per open port: the port, its state, the service, and its version. Each row is something to enumerate next. This command checks the 1,000 most common TCP ports, so it can miss a service on an unusual port. The three-step approach under "How do you use it?" covers that.

What does it do?

Nmap's output tells you the attack surface of a target. Here's what each piece of output means:

Output fieldWhat it tells youWhy it matters
PORTThe port number and protocol (TCP/UDP)Tells you what services to investigate
STATEopen, closed, or filteredOpen = reachable. Filtered = firewall blocking. Closed = nothing listening
SERVICEWhat application is likely runningGuides which tools to use next
VERSIONExact software version (with -sV)Check for known CVEs for that exact version
SCRIPT OUTPUTResults from NSE scripts (with -sC)Can reveal hostnames, shares, users, certs, vulns
The most valuable Nmap output

Beginners focus on the port list. Experienced pentesters read the script output: it often leaks hostnames, domain names, certificate SANs, SMB signing status, and anonymous access. The script output frequently gives you your next three steps.

When do you use it?

Literally always. Nmap is step zero. Before you run any other tool, you need to know what's open. The typical flow:

  1. Quick scan: fast scan of common ports to get an initial picture (30 seconds)
  2. Full port scan: scan all 65535 ports in the background while you work on what the quick scan found
  3. Targeted deep scan: detailed version/script scan on the interesting ports

You also re-run Nmap when:

  • You pivot to a new network segment (scan the new subnet)
  • You suspect a port was missed (try UDP scan)
  • You want to check if a service came online after exploitation (new services sometimes start)

How do you spot it?

You don't "spot when to use Nmap", it's always the first step. What takes practice is reading what the results mean and choosing the next step:

Port → what it means → what to do
  • 21 (FTP) → check anonymous login: ftp <IP> with user anonymous
  • 22 (SSH) → try known creds, check for old versions (libssh auth bypass, etc.)
  • 25/587 (SMTP) → user enumeration with VRFY or RCPT TO
  • 53 (DNS) → zone transfer: dig axfr @<IP> domain.local
  • 80/443 (HTTP/S) → web app testing, directory fuzzing, check the TLS certificate for hostnames
  • 88 (Kerberos) → this is a Domain Controller. AD attacks start here
  • 135 (RPC) → Windows machine, try rpcclient -U '' <IP>
  • 139/445 (SMB) → enum4linux-ng, smbmap, check for shares, check SMB signing
  • 389/636 (LDAP/S) → Domain Controller, ldapsearch, possible anonymous bind
  • 1433 (MSSQL) → try default creds, xp_cmdshell if you get in
  • 3306 (MySQL) → check for remote root login without password
  • 3389 (RDP) → xfreerdp with any creds you find
  • 5985 (WinRM) → evil-winrm with creds or hash
  • 5985 + 88 + 389 + 445 → this is definitely a DC, full AD attack surface

How do you use it?

The standard three-step approach

bash: step 1: quick scan
# Fast scan of top 1000 ports with version detection + default scripts
$ nmap -sC -sV -oN scan/initial 10.10.10.10

# Flags explained:
# -sC = run default NSE scripts (same as --script=default)
# -sV = version detection (probe services for exact version)
# -oN = save output in normal format to file
bash: step 2: full port scan (background)
# Scan ALL 65535 TCP ports, finds services on non-standard ports
$ nmap -p- --min-rate 1000 -oN scan/allports 10.10.10.10

# -p-         = all ports (1-65535)
# --min-rate  = send at least 1000 packets/sec (speeds up the scan)
# This takes 1-5 minutes. Run it in the background while you work
bash: step 3: targeted deep scan
# Deep scan only the ports found in step 2
$ nmap -sC -sV -p 21,22,80,445,8080 -oN scan/targeted 10.10.10.10

# Only scan the interesting ports with scripts + versions
# Much faster than running -sC -sV on all 65535 ports

Useful scan types

bash
# UDP scan (slow, but finds SNMP, DNS, TFTP that TCP misses)
$ sudo nmap -sU --top-ports 50 -oN scan/udp 10.10.10.10

# Scan a subnet: find all live hosts
$ nmap -sn 10.10.10.0/24 -oN scan/hosts

# Aggressive scan (OS detection + version + scripts + traceroute)
$ nmap -A -oN scan/aggressive 10.10.10.10

# Vulnerability scan using NSE vuln scripts
$ nmap --script vuln -p 445 10.10.10.10

# SMB-specific: check signing, enumerate shares, check for EternalBlue
$ nmap --script smb-os-discovery,smb-security-mode,smb-enum-shares,smb-vuln-ms17-010 -p 445 10.10.10.10

# Check for anonymous LDAP bind
$ nmap --script ldap-rootdse -p 389 10.10.10.10

Host discovery: finding what is alive, and when it lies

Before scanning ports, Nmap checks whether the host is up. A machine that drops those probes looks dead even though it is not, so a scan that "finds nothing" is not proof the host is empty.

bash: host discovery
# Ping sweep only: list live hosts, no port scan
$ nmap -sn 10.10.10.0/24 -oA scan/sweep

# Host looks down but you know it is there? Skip discovery and scan ports anyway
$ nmap -Pn -p- --min-rate 1000 -oA scan/allports 10.10.10.10

# Scan targets from a file, and skip DNS lookups (faster, and no lookup traffic)
$ nmap -n -iL targets.txt -oA scan/targets

# Ask Nmap WHY it thinks a host is up, and watch the packets it sends
$ sudo nmap -sn --reason --packet-trace 10.10.10.10
If a scan finds fewer hosts than you expect

Re-run with -Pn. Windows hosts with the firewall on often ignore ping, so default discovery marks them down and never scans their ports.

Port states: what the output is telling you

Every port is reported in one of six states. They describe what Nmap could determine, which is not always the same as what is true.

StateWhat it meansWhat to do
openAn application is actively accepting connections on the portEnumerate the service
closedReachable and responding, but nothing is listeningConfirms the host is up; revisit later in case something starts
filteredA firewall or filter is stopping the probes, so Nmap cannot tell open from closedExpect slow scans; the port may still be open from another source address
unfilteredReachable, but Nmap cannot tell whether it is open or closed (only the ACK scan reports this)Try another scan type
open|filteredNo response, so it could be open or filtered (typical for UDP)Verify with version detection or another probe
closed|filteredCannot tell closed from filtered (idle scan only)Rare in practice

Scan type, speed and output you can reuse

bash: scan type, timing and output
# SYN scan: the default when you run as root; it never completes the handshake
$ sudo nmap -sS -p- 10.10.10.10

# Connect scan: the default without root; it completes the full handshake
$ nmap -sT -p- 10.10.10.10

# Only the 100 most common ports (fast first look)
$ nmap -F 10.10.10.10

# Timing template 0-5. -T4 is the usual choice on a stable lab network
$ nmap -T4 -p- 10.10.10.10

# Do not retry lost probes forever, and give up on a host that stalls
$ nmap -p- --max-retries 1 --host-timeout 5m 10.10.10.10

# Progress report every 30 seconds on a long scan
$ nmap -p- --stats-every 30s 10.10.10.10

# Show only open ports (much cleaner on big scans)
$ nmap --open -p- 10.10.10.10

# Save normal, XML and grepable output at once, then pull the open ports out
$ nmap -sC -sV -p 22,80,445 -oA scan/targeted 10.10.10.10
$ grep -oP '\d+/open' scan/targeted.gnmap

# Turn the XML into an HTML report you can open in a browser
$ xsltproc scan/targeted.xml -o scan/targeted.html

Without root, Nmap quietly falls back to -sT. Both find the same open ports; -sS is just faster and leaves fewer connections in the target's logs.

Reading the output

output: example nmap result
PORT     STATE SERVICE       VERSION
22/tcp   open  ssh           OpenSSH 8.9p1 Ubuntu 3ubuntu0.4
80/tcp   open  http          Apache httpd 2.4.52
|_http-title: Company Portal                          <-- page title
|_http-server-header: Apache/2.4.52 (Ubuntu)
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos  <-- Domain Controller!
135/tcp  open  msrpc         Microsoft Windows RPC
389/tcp  open  ldap          Microsoft Windows AD LDAP
| ldap-rootdse:
|   domainFunctionality: 7
|   forestFunctionality: 7
|   domainControllerFunctionality: 7
|   rootDomainNamingContext: DC=corp,DC=local         <-- domain name!
445/tcp  open  microsoft-ds
| smb-security-mode:
|   message_signing: required                         <-- SMB signing ON (relay won't work)
3389/tcp open  ms-wts        Microsoft Terminal Services
| ssl-cert:
|   Subject: commonName=DC01.corp.local               <-- hostname!
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0  <-- WinRM (evil-winrm)

From this single scan you've learned: domain name (corp.local), hostname (DC01), it's a Domain Controller (port 88), SMB signing is on (no relay attacks on this host), and WinRM is available (evil-winrm once you have creds).

What do you do with the output?

  • Add hostnames to /etc/hosts: any hostname or domain revealed in the scan
  • Note the OS: Windows or Linux determines your entire tool chain
  • Check SMB signing: message_signing: required = no relay. not required = relay attacks possible
  • Read TLS certificates: SANs often leak internal hostnames and subdomains
  • Port 88 present? → It's a DC. Run BloodHound, certipy, kerbrute
  • Port 445 open? → smbmap, enum4linux-ng, check for null sessions
  • Port 80/443? → Open in browser, start directory fuzzing with ffuf
  • Port 5985? → evil-winrm when you find creds

Common mistakes

Things that go wrong
  • Only scanning top 1000 ports: Services hide on non-standard ports (8080, 8443, 50000). Always do a full -p- scan too
  • Skipping UDP: SNMP (161), TFTP (69), and DNS (53) are UDP-only and often lead to footholds. A -sU --top-ports 50 is worth the wait
  • Not saving output: Always use -oN (normal) or -oA (all formats). You'll refer back to scan results constantly
  • Running -sC -sV -p- together: This is extremely slow. Do a fast -p- first, then a deep -sC -sV on just the found ports
  • Ignoring script output: The text below each port holds the useful detail: hostnames, domain names, certificate details, SMB info. Read all of it
  • Forgetting sudo for SYN scans: Without root, Nmap falls back to TCP connect scans which are slower and noisier. Always sudo nmap
Create a scan directory first

Before you start: mkdir scan. Save all Nmap output there. During CPTS you'll have multiple targets, organize from the start. Naming convention: scan/initial, scan/allports, scan/udp, scan/targeted.

Check yourself

Answer each question out loud or on paper first, then open it. Retrieving the answer teaches you more than rereading the page.

A host you know is up shows as down, and the scan lists no ports. What do you try, and why does it help?
Run with -Pn. Nmap pings a host before scanning it, and a firewall that drops those probes makes the host look dead. -Pn skips the ping and scans the ports anyway.
What is the difference between a closed and a filtered port?
closed means the host answered but nothing is listening, which also proves the host is up. filtered means a firewall or filter blocked the probe, so Nmap cannot tell whether anything is listening.
Why run a fast -p- scan first and -sC -sV only on the ports it finds?
Scripts and version detection send many probes per port, so running them on all 65,535 ports is very slow. The fast scan finds the open ports, and the deeper scan then runs on only those.
You run Nmap without sudo. Which TCP scan does it use, and how does that differ from the default for root?
A connect scan (-sT). Without raw packet privileges Nmap asks the operating system to open a full connection to each port. The man page says it takes longer, needs more packets, and is more likely to be logged by the target than the SYN scan (-sS), which root gets by default.
A UDP scan reports port 161 as open|filtered. What does that mean, and what do you do next?
Nmap got no reply. An open UDP port often stays silent, and a filter dropping the probe looks the same, so the port could be either. Version detection (-sV) helps tell the open ports from the filtered ones.
Which flag saves results in all three formats, and which file do you search for open ports?
-oA basename writes .nmap, .xml and .gnmap. The .gnmap file is the grepable one.