Scanning a Target with Nmap: A Step-by-Step First Scan
Your first Nmap scan, walked through step by step: a safe lab target, host discovery, port ranges, service and version detection, scripts, saving output, and what to do with the results.
A good Nmap scan is the first honest look you get at a target, and learning to read one is the difference between guessing and knowing. This walkthrough takes a complete beginner from an empty terminal to a saved, readable map of open ports and the services behind them. We go one flag at a time, explain what each line of output means, and finish by turning that map into a short list of next steps. Follow along on a target you are allowed to touch and you will have the whole workflow in your fingers by the end.
Read it top to bottom the first time, with a terminal open. Everything here runs against your own lab or against scanme.nmap.org, a host the Nmap project puts online specifically so people can practise scanning legally.
Scan only hosts you own or have written permission to test, a lab you built, or scanme.nmap.org, which the Nmap project provides for exactly this kind of practice. Scanning systems you do not control is a crime in most places, even when nothing breaks. Keep everything in this guide inside that line.
01Setting up a safe target to scan
Before your first Nmap scan you need somewhere safe to point it, and you have two easy options. The first is a lab host you control, such as a small Linux virtual machine or the project lab at lab.0xpriv.dev on an internal range like 10.10.10.0/24. The second is scanme.nmap.org, a machine the Nmap authors keep online so newcomers have a legal place to test. Both give you real open ports to find without touching anything you should not.
Install Nmap first. On Debian or Ubuntu that is sudo apt install nmap, on macOS brew install nmap, and on Windows the installer from the official site. Confirm it runs and note the version, because a few features depend on it.
# 0xpriv.dev/labs -- confirm nmap is installed and check the version nmap --version
Run scans as root (or with sudo) when you can. With root, Nmap sends raw packets and defaults to a fast SYN scan (-sS). Without root it falls back to a full TCP connect scan (-sT), which still works but is slower and noisier. The results read the same either way.
02Your very first scan and what the output means
Your very first scan is the simplest command there is: the word nmap followed by a target. No flags, no options. Nmap picks sensible defaults, checks whether the host is up, scans the 1000 most common TCP ports, and prints what it found. That one line teaches you more than any amount of reading.
# the whole command is just the tool and a target
nmap scanme.nmap.org$ nmap scanme.nmap.org Starting Nmap 7.94 ( https://nmap.org ) Nmap scan report for scanme.nmap.org (45.33.32.156) Host is up (0.098s latency). Not shown: 996 closed tcp ports (reset) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 9929/tcp open nping-echo 31337/tcp open Elite Nmap done: 1 IP address (1 host up) scanned in 2.14 seconds
Read it from the top. The host is up line means Nmap's discovery probes got a reply. Not shown: 996 closed tcp ports tells you it checked 1000 ports and most answered "nothing here". The table lists the ports that were interesting. The STATE column is the part that matters most, so it gets its own table.
| State | What it means |
|---|---|
open | A service accepted the connection. This is what you are hunting. |
closed | The host replied but nothing is listening on that port right now. |
filtered | A firewall dropped the probe, so Nmap cannot tell if anything is there. |
open|filtered | Nmap could not decide between open and filtered, common with UDP. |
The SERVICE column is only a guess at this stage. Nmap matched the port number against a name list (22 is usually SSH, 80 usually HTTP), but it has not actually talked to the service yet. Confirming what is really running is a later step.
03How a scan runs under the hood
A single scan is really a short pipeline of phases, and knowing the order helps you read the output and choose flags. Nmap resolves the name to an address, decides whether the host is alive, scans the chosen ports, optionally fingerprints the services, and then prints and saves the result. Each flag you add switches one of these phases on, off, or into a different mode.
Keep this picture in mind for the rest of the guide. Every option we add from here just changes one box.
04Host discovery and when to skip it with -Pn
Host discovery is the phase where Nmap decides whether a target is worth scanning at all. Before touching any ports it sends a small set of probes (an ICMP echo, a TCP SYN to port 443, a TCP ACK to port 80, and an ICMP timestamp when run as root) and marks the host "up" if anything replies. You can run only this phase with -sn, which is the fastest way to find live hosts on a range.
# ping sweep only: list live hosts on an internal range, no port scan nmap -sn 10.10.10.0/24
$ nmap -sn 10.10.10.0/24 Nmap scan report for 10.10.10.5 Host is up (0.0011s latency). Nmap scan report for 10.10.10.12 Host is up (0.0009s latency). Nmap done: 256 IP addresses (2 hosts up) scanned in 2.98 seconds
The catch is that plenty of hosts are configured to ignore those probes. If discovery decides a host is down, Nmap skips it and you see nothing, even when services are listening. That is where -Pn comes in: it tells Nmap to skip discovery entirely and treat every target as online, so it goes straight to the port scan.
# skip host discovery and scan anyway (useful when pings are blocked) nmap -Pn lab.0xpriv.dev
Use -Pn when you are sure the host exists (you were given the address) but a plain scan reports it down. The trade-off is time: Nmap now scans every target in the list whether it is alive or not, so do not throw -Pn at a whole /16 without thinking.
05A top-ports scan versus a full -p- scan
Choosing a port range is a trade between speed and coverage, and Nmap gives you a dial for it. By default it scans the 1000 most common TCP ports, which is a good balance for a first pass. You can narrow that to the top 100 with -F for a quick look, set any count with --top-ports, or go all the way to every port with -p-.
# a fast first look: only the 100 most common ports nmap -F scanme.nmap.org # pick an exact count of the most common ports nmap --top-ports 200 scanme.nmap.org # specific ports or ranges nmap -p 22,80,443,8080 scanme.nmap.org # every one of the 65535 TCP ports (slow, but thorough) nmap -p- scanme.nmap.org
The reason -p- matters is that services hide on odd ports on purpose. An admin panel on 8443, an old app server on 8081, a database bound to 5433: none of those are in the top 1000, so a default scan walks right past them. A real assessment almost always ends with a full port scan, even if it starts with a quick one.
A common rhythm is to run a quick -F scan to get moving, then kick off a slow -p- scan in the background with -T4 to speed up the timing. You start working on the obvious ports while the thorough scan finishes.
06Service and version detection with -sV
Service and version detection is what turns "port 80 is open" into "this is Apache 2.4.x on Ubuntu". The port table alone only guesses from the port number. Add -sV and Nmap actually connects to each open port, reads the banner and probe responses, and matches them against its service database to name the software and, where it can, the exact version.
# probe open ports to identify the service and version behind them nmap -sV scanme.nmap.org # push harder on stubborn services (0 is light, 9 tries everything) nmap -sV --version-intensity 9 lab.0xpriv.dev
Version strings are the single most useful thing a first scan produces, because they tell you what to research next. An old OpenSSH build, a specific web server release, an outdated application version: each one is a thread to pull on. The intensity dial trades speed for certainty, so turn it up only on the handful of ports that refuse to identify themselves.
07Running the default scripts with -sC
The default scripts are a set of safe, useful checks that Nmap can run against each open port automatically. The flag -sC runs everything in the Nmap Scripting Engine's default category: things like grabbing an HTTP title, listing SSH host keys, pulling an SSL certificate, or reading an anonymous FTP banner. None of them are intrusive, and together they often hand you information that would take several manual steps otherwise.
# run the default script set against open ports nmap -sC scanme.nmap.org # the beginner workhorse: version detection + default scripts together nmap -sC -sV scanme.nmap.org # -A rolls in -sV, -sC, OS detection (-O) and traceroute in one go nmap -A scanme.nmap.org
For a first scan, -sC -sV is the combination to memorise. It names the services, versions them, and runs the safe scripts in a single pass. The bigger hammer, -A, adds operating-system guessing and a traceroute on top, which is handy but louder and slower, so save it for when you want the full picture.
The default category is chosen to be non-disruptive, but it is still active probing. On fragile or production-like lab gear, know what a script does before you run it. The --script-help flag prints a description for any script by name.
08Saving output with -oA and why it matters
Saving output is the habit that separates a quick look from real work, and -oA is how you do it. On its own a scan prints to the screen and is gone when you close the terminal. The -oA flag takes a base name and writes three files at once: a human-readable .nmap file, a machine-parsable .xml file, and a line-oriented .gnmap file that you can grep.
# save every format at once under one base name nmap -sC -sV -oA scans/scanme scanme.nmap.org
$ ls scans/ scanme.nmap scanme.gnmap scanme.xml $ grep open scans/scanme.gnmap Host: 45.33.32.156 () Ports: 22/open/tcp//ssh///, 80/open/tcp//http///
Keep those files. The .nmap file is what you reread while you work. The .xml file feeds other tools and report generators. The .gnmap file lets you pull "every host with 445 open" out of a big scan with one grep. If you scan without saving, you will be rescanning an hour later to answer a question you already answered, which is both slow and needlessly loud.
09Turning results into next steps
Turning results into next steps is the point of the whole exercise, and it follows the same short routine every time. A first scan is a map, not a conclusion. You read the open ports, decide which services are worth a closer look, and line up the right follow-up tool for each one. Here is that routine as a checklist you can run on any scan output.
List the open ports
Pull every open port out of the saved output and write them down. These are your only real attack surface; closed and filtered ports are noise for now.
Name the service and version
For each open port, note the -sV result. "OpenSSH 8.2", "Apache 2.4.41", "MySQL 5.7": the version is your search term.
Pick one follow-up per service
Web ports go to a browser and a directory tool, SMB goes to a share enumerator, databases get a login check. One obvious action each, no rabbit holes yet.
Run a full port scan in parallel
While you work the obvious ports, start a -p- scan so nothing on an odd port is missed. Re-read it when it finishes.
# example follow-ups the first scan points you toward curl -I http://lab.0xpriv.dev/ # look at the web server headers nmap -p 445 --script smb-os-discovery 10.10.10.5 # enumerate an SMB host nmap -p- -T4 -oA scans/full lab.0xpriv.dev # the thorough pass, saved
10Reading a real example scan end to end
Reading a full example scan ties every flag above together in one block. Below is a -sC -sV scan of the practice host with output saved. Walk through it the way you would on a real engagement: confirm the host is up, read each open port, note the versions, and skim the script output for anything useful. Your own run will show different versions, because the box gets updated.
$ nmap -sC -sV -oA scans/scanme scanme.nmap.org Starting Nmap 7.94 ( https://nmap.org ) Nmap scan report for scanme.nmap.org (45.33.32.156) Host is up (0.096s latency). Not shown: 996 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.13 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 1024 ac:00:a0:1a:... (DSA) |_ 2048 20:3d:2d:44:... (RSA) 80/tcp open http Apache httpd 2.4.7 ((Ubuntu)) |_http-title: Go ahead and ScanMe! |_http-server-header: Apache/2.4.7 (Ubuntu) 9929/tcp open nping-echo Nping echo 31337/tcp open tcpwrapped Service detection performed. Please report any incorrect results. Nmap done: 1 IP address (1 host up) scanned in 11.03 seconds
Two open ports carry real services here. Port 22 is SSH, and -sC printed the host keys for you. Port 80 is a web server, and the scripts already grabbed the page title and the server header. Right away you have two leads: browse the web server, and note the SSH version to check later. That is a first scan doing its whole job.
11A note on being loud and staying in scope
Being loud is the thing beginners underestimate, so it deserves its own note. A default Nmap scan is not quiet. It opens hundreds of connections in a couple of seconds, which lights up firewall and IDS logs on any monitored network. The timing templates control this: -T0 and -T1 crawl along to stay under the radar, -T3 is the default, and -T4 pushes hard on a network that can take it.
# slow and quiet for a monitored target nmap -T1 -sV lab.0xpriv.dev # fast and loud for a lab you control nmap -T4 -p- lab.0xpriv.dev
The scope rule is simpler than the timing one and matters more. Only scan what you were authorized to scan. A CIDR range in an engagement letter is a boundary, not a suggestion, and scanme.nmap.org is the one public host on earth that invites you to practise. Everything else needs permission in writing. Staying in scope is not just etiquette; it is the line between security testing and a crime.
12Detecting and limiting port scans
Detecting a port scan is the defender's side of this story, and the good news is that scans are noisy by nature. A single source opening connections to many ports in a short window is the textbook signature, and it shows up in firewall logs, in an IDS like Suricata or Snort, and in simple connection-rate alerts. The slow -T0 and -T1 timings exist precisely because the fast ones are so easy to spot. For a defender, the fix is less about catching every scan and more about having little for a scan to find.
13FAQ
Do I need to be root to run an Nmap scan?FAQ
No, but it helps. As a normal user Nmap runs a TCP connect scan (-sT), which is slower and more visible. With root or sudo it sends raw packets and defaults to a faster SYN scan (-sS), and it can also do OS detection and some scripts. The port results are the same; root just makes the scan quicker and quieter.
Why does my scan say the host is down when I know it is up?FAQ
The host is probably configured to ignore Nmap's discovery probes, so the discovery phase marks it down and skips the port scan. Add -Pn to skip discovery and scan it anyway. This is common on hardened hosts and on networks that block ICMP.
How long should a full -p- scan take?FAQ
It depends on the target and timing, from a minute on a fast lab host with -T4 to much longer on a slow or filtered network. Because it checks all 65535 ports, start it early and let it run in the background while you work the common ports a default scan already found.
What is the difference between -sC and -sV?FAQ
-sV identifies the software and version behind each open port by reading banners and probe responses. -sC runs the default Nmap script set, which does extra safe checks like grabbing a page title or SSL certificate. Together, -sC -sV is the standard combination for a thorough first scan.
Is it legal to scan scanme.nmap.org?FAQ
Yes. The Nmap project runs that host specifically so people can learn and test scans legally, and asks only that you do not hammer it with heavy traffic. A handful of normal scans is exactly what it is for. Any other host still needs the owner's permission.
references
Founder of 0xpriv, covering offensive security, web application vulnerabilities, and practical security research through PHP, Python, and hands-on technical analysis.