How To

Nmap Cheat Sheet and Scanning Guide for Kali Linux

A flag list is the half of Nmap you can already get from nmap --help. The other half is what a scan prints on a real network: which ports come back filtered instead of closed, why -O guesses MikroTik for a Debian box, or why a full 65,535-port SYN scan took 1.14 seconds while -T2 needed 41 seconds for just 100 ports. This nmap cheat sheet backs every command with the output it produced.

Original content from computingforgeeks.com - post 165784

The quick tables cover target syntax, scan types, discovery, ports, detection, NSE scripts, timing templates T0 to T5, output formats and evasion, and they come as a one-page PDF. The walkthrough below them includes a note on the Nmap release that broke version scripts. Every scan here was run in November 2026 from Kali Linux 2026.3 with Nmap 7.993 against a Debian 13 target in an isolated lab.

Use the Nmap cheat sheet tables

Each table below is grouped by the job you are doing, and every row was run against the lab target at 10.0.1.50 from the Kali box at 10.0.1.20. Commands that send raw packets (SYN, UDP, ACK, OS detection, most discovery probes) need sudo. Run with no scan flag and without root, Nmap quietly falls back to a TCP connect scan, so a scan that looks slower than expected is often just missing sudo. Ask for -sS, -sU or -O without root and it refuses to run at all.

Target specification

CommandWhat it does
nmap 10.0.1.50Scan one host, top 1,000 TCP ports
nmap -sL -n 10.0.1.48/29Expand a CIDR block without sending a packet
nmap -sL -n 10.0.1.44-50Expand a range in the last octet
nmap -iL targets.txtRead targets from a file, one per line
--exclude 10.0.1.45Drop hosts you must not touch

Scan types

CommandWhat it does
sudo nmap -sS 10.0.1.50SYN (half-open) scan, the default as root
nmap -sT 10.0.1.50Full TCP connect, works without root
sudo nmap -sU --top-ports 20 10.0.1.50UDP scan of the 20 most common ports
sudo nmap -sA 10.0.1.50ACK scan: filtered or unfiltered, never open
sudo nmap -sN / -sF / -sXNull, FIN and Xmas scans
sudo nmap -sS -sU -p U:161,T:22,80TCP and UDP in one run

Host discovery

CommandWhat it does
sudo nmap -sn 10.0.1.50Ping sweep only, no port scan
sudo nmap -Pn 10.0.1.50Skip discovery and scan anyway
sudo nmap -sn -PS22,80 -PA80TCP SYN and ACK pings to chosen ports
--disable-arp-pingUse IP probes instead of ARP on a local subnet
sudo nmap -n -F 10.0.1.50No reverse DNS, fast top-100 scan

Port selection

CommandWhat it does
-p 21,22,80,443Scan a list of ports
-p 1-1000Scan a range
-p-All 65,535 TCP ports
--top-ports 100The N most common ports from nmap-services
--openPrint only open (or possibly open) ports
--reasonShow why each port got its state

Service, version and OS detection

CommandWhat it does
sudo nmap -sV 10.0.1.50Probe open ports for product and version
-sV --version-intensity 9Try every probe (0 to 9, default 7)
-sV --version-lightIntensity 2, faster and less thorough
sudo nmap -O 10.0.1.50TCP/IP stack fingerprint of the OS
sudo nmap -A 10.0.1.50-sV, -O, default scripts and traceroute

NSE scripts

CommandWhat it does
sudo nmap -sC 10.0.1.50Run the default script set
--script vulnRun a whole category
--script ftp-anon,http-enumRun named scripts
--script 'default and safe'Boolean expression over categories
--script-args http.useragent='Mozilla/5.0'Pass arguments to scripts
nmap --script-help ftp-anonShow the categories and purpose of a script
sudo nmap --script-updatedbRebuild script.db after adding scripts

Timing templates and rate limits

CommandWhat it does
-T0Paranoid: 5 minutes between probes (10 min for one port)
-T1Sneaky: 15 seconds between probes (30.6 s for one port)
-T2Polite: 0.4 seconds between probes (41 s for 100 ports)
-T3Normal, the default
-T4Aggressive, for fast and reliable networks
-T5Insane, trades accuracy for speed
--min-rate 5000Send at least 5,000 packets per second
--max-rate 100Cap the send rate at 100 packets per second
--max-retries 1Give up on a silent port sooner
--host-timeout 30sAbandon a host that takes too long

Output formats

CommandWhat it does
-oN scan.txtNormal, human-readable text
-oX scan.xmlXML for tools and Metasploit
-oG -Grepable, one line per host and record, to stdout
-oA full-scanAll three formats at once
xsltproc full-scan.xml -o full-scan.htmlTurn XML into an HTML report
-v / -dVerbose progress / debug output

Firewall and IDS evasion

CommandWhat it does
sudo nmap -f 10.0.1.50Fragment probe packets
sudo nmap -D RND:3 10.0.1.50Mix in 3 random decoy source IPs
--source-port 53Send probes from a trusted source port
--data-length 25Pad probes with random bytes

Everything after this point explains those rows with the output they printed. Only scan hosts you own or have written permission to test: a SYN scan of a network that belongs to someone else is easy to spot in their firewall logs, and in many countries it is enough to get you in trouble.

Check your Nmap version first

The Kali repository is behind upstream right now, and that matters because of one bad release. Nmap 7.992 (October 15, 2026) shipped a lazy-loading change to NSE that stopped most scripts in the version category from running, so -sV silently lost the extra detail those scripts add. Issue #3557 reports 7.991 as working and 7.992 as broken, and the Nmap changelog lists the fix under 7.993 (October 23, 2026). The scan still exits 0, which is why nobody notices.

Check what Kali installed and what it offers, because the answer decides whether the rest of this section applies to you. A box that hasn’t been upgraded in months may still sit on 7.99, which predates the change and is fine too.

apt-cache policy nmap | head -3

On Kali 2026.3, kali-rolling carries 7.991, the last release before the regression.

nmap:
  Installed: 7.991+dfsg-1kali1
  Candidate: 7.991+dfsg-1kali1

That package is safe from the bug, so you do not have to do anything if you only use the Kali build. If you installed 7.992 from nmap.org, the Arch testing repos or a source build, move to 7.993 or later. 7.992 itself also carried a batch of NSE hardening fixes for malicious server responses, so the latest upstream release is worth having when you scan machines you don’t trust.

See the 7.992 version-script bug for yourself

The cleanest test is SNMP, because snmp-info is one of the version-category scripts that fills in the VERSION column. We ran the same UDP version scan with a 7.992 build and with 7.993 against the same target.

sudo nmap -sU -sV -p 161 10.0.1.50

7.992 reports only SNMPv1 server (public). 7.993, and the 7.991 Kali package, report SNMPv1 server; net-snmp SNMPv3 server (public), because snmp-info actually ran and identified the agent:

Nmap 7.992 vs 7.993 UDP version scan on Kali Linux showing the missing net-snmp SNMPv3 detail

The debug output shows the cause. Run a version scan with -d and filter for script errors.

sudo nmap -sV -p 80 -d 10.0.1.50 | grep -A2 'threw an error'

On 7.992 six version scripts died on the same nil index inside nmap.version_intensity(), just as the issue describes. The same command on 7.993 printed nothing, and grep -c counted 0 errors:

NSE: vmware-version against 10.0.1.50:80 threw an error!
attempt to index a nil value
stack traceback:
--
NSE: https-redirect against 10.0.1.50:80 threw an error!
attempt to index a nil value
stack traceback:
--
NSE: rpcinfo against 10.0.1.50:80 threw an error!
attempt to index a nil value
stack traceback:
--
NSE: http-trane-info against 10.0.1.50:80 threw an error!
attempt to index a nil value
stack traceback:
--
NSE: hnap-info against 10.0.1.50:80 threw an error!
attempt to index a nil value
stack traceback:
--
NSE: http-server-header against 10.0.1.50:80 threw an error!
attempt to index a nil value
stack traceback:

If you see that pattern, upgrade. The TCP -sV table itself looked identical on both builds in our lab, which is exactly why the bug survived a week: the damage only shows on services where a script adds detail the probes can’t.

Build the latest Nmap from source on Kali

When you need a release newer than the Kali package, build it next to the packaged one. It installs under /usr/local, so apt never overwrites it. Install the build dependencies:

sudo apt install -y build-essential libssl-dev libpcap-dev libssh2-1-dev zlib1g-dev

Read the current release number off the nmap.org download page instead of hardcoding it, so these steps keep working after the next release:

NMAP_VER=$(curl -s https://nmap.org/dist/ | grep -oP "latest Nmap release is version \K[0-9]+(\.[0-9]+)+")
echo "$NMAP_VER"

It should print a bare version string. If it prints nothing, the download page changed its wording, so open https://nmap.org/dist/ in a browser and set NMAP_VER by hand before you continue:

7.993

Download, unpack, configure and compile. Zenmap and Ndiff are skipped because they pull in Python packaging you do not need for scanning.

curl -LO https://nmap.org/dist/nmap-${NMAP_VER}.tar.bz2
tar xjf nmap-${NMAP_VER}.tar.bz2
cd nmap-${NMAP_VER}
./configure --without-zenmap --without-ndiff
make -j$(nproc)
sudo make install

The end of the ./configure run lists what will be built. NSE needs lua and openssl in that first line.

Configured with: nping openssl zlib libssh2 lua ncat
Configured without: localdirs ndiff zenmap
Type make (or gmake on some *BSD machines) to compile.

There is one Kali-specific catch. The stock /etc/sudoers on Kali sets secure_path without /usr/local/bin, so sudo nmap keeps running the old package even though plain nmap runs the new build. Add a drop-in that puts /usr/local/bin first. Anything else you install there will also win under sudo, so if you’d rather not change that, call sudo /usr/local/bin/nmap by its full path instead:

echo 'Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' | sudo tee /etc/sudoers.d/local-path
sudo chmod 440 /etc/sudoers.d/local-path
sudo visudo -c

visudo -c must report /etc/sudoers.d/local-path: parsed OK before you close the shell, because a broken sudoers file locks you out of sudo. Now both paths resolve to the new build:

sudo nmap --version on Kali Linux showing the source build next to the packaged 7.991 and a 7.992 build

The Compiled with line confirms the bundled Lua 5.4.9 that NSE uses and the system libpcap for raw scans. The two extra lines come from our lab: /usr/bin/nmap is still the 7.991 Kali package, and /opt/nmap-7.992 is the separate 7.992 build we kept only to reproduce the bug above, so you won’t have that path. If you’d rather start from a clean Kali VM for this, the Kali Linux install walkthrough covers the installer, the things to do after installing Kali list covers the first updates and tools, and the Proxmox pentest lab guide shows the isolated network we scanned on.

Find live hosts with a ping sweep

Discovery comes first because port-scanning dead addresses wastes most of your time on a large range. -sn runs discovery only. On a local subnet, Nmap as root uses ARP, which a host cannot ignore, so the answer is fast and includes the MAC vendor:

sudo nmap -sn 10.0.1.50

The vendor line tells you the target is a Proxmox VM before you have scanned a single port. On a client network that same line separates printers, phones and hypervisors, so you can decide where the slow scans are worth running before you start them.

Starting Nmap 7.993 ( https://nmap.org ) at 2026-11-01 05:15 -0500
Nmap scan report for 10.0.1.50
Host is up (0.00026s latency).
MAC Address: BC:24:11:5A:10:50 (Proxmox Server Solutions GmbH)
Nmap done: 1 IP address (1 host up) scanned in 0.57 seconds

Before you sweep a whole range, check what Nmap thinks the range is. -sL lists the targets without sending any packets, and -n skips reverse DNS, so it’s free:

nmap -sL -n 10.0.1.44-50 --exclude 10.0.1.45

Six addresses remain, and .45 is gone. That is the habit that keeps a gateway or a production box out of a scan you were only authorised to run on part of a subnet, because a typo in a range is the easiest way to break a pentest scope. Run the list first, then the real scan with the same target string:

Starting Nmap 7.993 ( https://nmap.org ) at 2026-11-01 05:23 -0500
Nmap scan report for 10.0.1.44
Nmap scan report for 10.0.1.46
Nmap scan report for 10.0.1.47
Nmap scan report for 10.0.1.48
Nmap scan report for 10.0.1.49
Nmap scan report for 10.0.1.50
Nmap done: 6 IP addresses (0 hosts up) scanned in 0.00 seconds

Across a router, ARP isn’t available and Nmap falls back to an ICMP echo, a TCP SYN to 443, a TCP ACK to 80 and an ICMP timestamp request. When those are blocked, pick your own probes with -PS and -PA, aimed at ports the target is likely to answer on. --disable-arp-ping forces that behaviour on a local subnet, which is how we tested it:

sudo nmap -sn -PS22,80 -PA80 --disable-arp-ping 10.0.1.50

The host came back up in 0.60 seconds without ARP discovery. For long target lists, put one address or range per line in a file and pass it with -iL targets.txt; the file accepts the same CIDR, range and hostname syntax as the command line.

Pick the right Nmap scan type

Run as root with no flags, Nmap does a SYN scan of the 1,000 most common TCP ports. It sends a SYN, reads the reply and never completes the handshake, which is why it’s fast and why many applications never log it:

sudo nmap 10.0.1.50

Six open ports, and the other 994 answered with a RST, which is what closed means.

Nmap scan report for 10.0.1.50
Host is up (0.000077s latency).
Not shown: 994 closed tcp ports (reset)
PORT     STATE SERVICE
21/tcp   open  ftp
22/tcp   open  ssh
80/tcp   open  http
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
3306/tcp open  mysql
MAC Address: BC:24:11:5A:10:50 (Proxmox Server Solutions GmbH)

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

The SERVICE column is a lookup in nmap-services, not a detection. Port 3306 says mysql because that’s what usually lives there; only -sV tells you it’s MariaDB. Without root, use -sT, which completes the full handshake through the normal socket API. It found the same ports and also showed 443 as closed:

nmap -sT -p 21,22,80,443 10.0.1.50

A connect scan is noisier because each open port sees a real connection that the application can log. That is the trade for not needing raw sockets.

PORT    STATE  SERVICE
21/tcp  open   ftp
22/tcp  open   ssh
80/tcp  open   http
443/tcp closed https

The ACK scan answers a different question. It never says open; it tells you whether a firewall sits in front of a port. With no firewall on the target, all three ports came back unfiltered, which you’ll see turn into filtered in the troubleshooting section once nftables is switched on:

sudo nmap -sA -p 22,80,443 10.0.1.50

Null (-sN), FIN (-sF) and Xmas (-sX) scans rely on an RFC 793 quirk: a closed port answers an odd flag combination with a RST, and an open port stays silent. Against the Debian target, all three printed the same thing:

sudo nmap -sF -p 22,80,443 10.0.1.50

Open ports read open|filtered because silence can’t be told apart from a firewall drop. These scans took 1.83 seconds against 0.63 for an ACK scan of the same three ports, since Nmap has to wait out the silence, and Windows hosts reply with RSTs on every port, which makes all ports look closed. Use them to slip past simple stateless filters, not as a default:

PORT    STATE         SERVICE
22/tcp  open|filtered ssh
80/tcp  open|filtered http
443/tcp closed        https

The Xmas scan printed the identical table, and so did the Null scan, so against a Linux target one of the three tells you everything the others would.

Scan UDP ports

UDP is where people skip a step and miss SNMP, NetBIOS or DHCP. There’s no handshake, so a port that doesn’t answer could be open or filtered, and closed ports are slowed down by ICMP rate limiting in the kernel. Keep the port list short, because every extra closed port adds waiting time.

sudo nmap -sU --top-ports 20 10.0.1.50

Twenty ports took 15.7 seconds, against 0.64 seconds for 1,000 TCP ports. SNMP and NetBIOS name service answered with real UDP data, so they’re plain open. The two open|filtered ports sent nothing back at all.

PORT      STATE         SERVICE
53/udp    closed        domain
67/udp    closed        dhcps
68/udp    open|filtered dhcpc
69/udp    closed        tftp
123/udp   closed        ntp
135/udp   closed        msrpc
137/udp   open          netbios-ns
138/udp   open|filtered netbios-dgm
139/udp   closed        netbios-ssn
161/udp   open          snmp
162/udp   closed        snmptrap
445/udp   closed        microsoft-ds
500/udp   closed        isakmp
514/udp   closed        syslog
520/udp   closed        route
631/udp   closed        ipp
1434/udp  closed        ms-sql-m
1900/udp  closed        upnp
4500/udp  closed        nat-t-ike
49152/udp closed        unknown
MAC Address: BC:24:11:5A:10:50 (Proxmox Server Solutions GmbH)

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

You can combine UDP and TCP in one run with protocol prefixes on -p, which is handy when you already know the two or three UDP services you care about: sudo nmap -sS -sU -p U:161,T:22,80 10.0.1.50 returned 22/tcp, 80/tcp and 161/udp as open in 0.71 seconds.

Choose which ports to scan

The top 1,000 ports miss anything on a high or unusual port, and on a LAN a full scan costs almost nothing, so scan everything on the hosts that matter:

sudo nmap -p- --min-rate 5000 10.0.1.50

All 65,535 ports finished in 1.14 seconds, and the full scan found a seventh port the default scan never looked at. Port 5355 is the LLMNR listener of systemd-resolved, enabled by default on this Debian cloud image, and it is precisely the kind of service an attacker uses for name poisoning:

Not shown: 65528 closed tcp ports (reset)
PORT     STATE SERVICE
21/tcp   open  ftp
22/tcp   open  ssh
80/tcp   open  http
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
3306/tcp open  mysql
5355/tcp open  llmnr
MAC Address: BC:24:11:5A:10:50 (Proxmox Server Solutions GmbH)

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

Narrow the list when you scan many hosts or a slow link. These are the forms we use most:

  • -p 22,80,443 for a known service list
  • -p 1-1000 for a range
  • --top-ports 100 or -F for a quick first look
  • --open to hide closed and filtered ports in the report

--reason is the flag to add when a result surprises you. It prints the packet that decided each state, so you can see a syn-ack on open ports and a reset on closed ones, and the TTL of 64 confirms you’re talking to a Linux host one hop away:

sudo nmap --reason -p 21,22,80,443 10.0.1.50

The REASON column is the evidence behind each state. A port that reads filtered with no-response is a firewall drop, while admin-prohibited means a router or host sent an ICMP reject, so the column also tells you what kind of filter you hit:

Host is up, received arp-response (0.00022s latency).

PORT    STATE  SERVICE REASON
21/tcp  open   ftp     syn-ack ttl 64
22/tcp  open   ssh     syn-ack ttl 64
80/tcp  open   http    syn-ack ttl 64
443/tcp closed https   reset ttl 64

Every state here came from a direct reply, because nothing filters traffic between the two lab VMs yet.

Detect services, versions and the OS

Open ports are only a list of doors. -sV talks to each one and matches the replies against nmap-service-probes, which turns mysql into a product and version you can check against CVEs:

sudo nmap -sV 10.0.1.50

Version detection took 11.7 seconds here, about 18 times the plain scan, which is why you run it on the open ports you found rather than on a whole subnet. Pass the open ports from the first scan with -p, because then it only probes what is actually listening. The full run against the target looked like this:

nmap -sV service and version detection output on Kali Linux against a Debian 13 target

Read the VERSION column critically. OpenSSH and Apache come back with the exact Debian package strings, which is as good as it gets. MariaDB reads 10.3.23 or earlier (unauthorized) because the server refused our address instead of sending its normal greeting, so Nmap fell back to a guess. The target actually runs MariaDB 11.8 from Debian 13. A version string with “or earlier” is a floor, not a fact, so confirm it another way before you put it in a report.

--version-intensity runs from 0 to 9 (default 7) and controls how many probes Nmap tries per port. Intensity 9 on SSH returned the same string in 0.71 seconds, because the SSH banner already gives everything away. Raise it for stubborn services on odd ports, and drop to --version-light (intensity 2) when you want fewer probes per port. Don’t expect miracles from it: the top 100 ports with --version-light took 11.73 seconds, the same as the full default run, because one slow service set the pace either way. It still named every service.

Fingerprint the operating system

-O sends a set of TCP, UDP and ICMP probes and compares the replies (window sizes, options order, IP ID behaviour) against nmap-os-db. It needs at least one open and one closed port to be reliable:

sudo nmap -O 10.0.1.50

The target runs kernel 6.12, but the best match is a range that ends at 5.19.

Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.19
Network Distance: 1 hop

That’s normal. The Linux TCP stack hasn’t changed enough between 5.x and 6.x for the fingerprint to tell them apart, and the -A run below listed MikroTik RouterOS and OpenWrt next to it, both of which are Linux underneath. Treat -O as “it’s Linux, one hop away” and get the distribution from -sV: the SSH banner said Debian 7+deb13u2, which pins Debian 13 exactly.

Run the aggressive scan on one target

-A turns on version detection, OS detection, the default NSE scripts and traceroute in one flag. It’s the scan to run on a single host you’ve already decided is interesting, and the one to avoid on a whole /24 because of the time and the noise:

sudo nmap -A 10.0.1.50

In 14 seconds the default scripts found anonymous FTP enabled, a /backup/ path in robots.txt, the NetBIOS name TARGET01 and SMB signing not required, each of which is a finding on its own.

nmap -A aggressive scan output on Kali Linux with ftp-anon, http-robots.txt and smb2-security-mode results

Look at the ftp-syst block: it reports Logged in as ftp, which means the script logged in anonymously to collect that status. -A isn’t passive, and every one of those logins lands in the FTP server log. Once you have this output, the Metasploit Framework can import the same scan as XML, which the output section below covers.

Run Nmap NSE scripts

The Nmap Scripting Engine runs Lua scripts against hosts and ports, and that’s where Nmap goes from port scanner to enumeration tool. Our 7.993 build ships 619 scripts. Each one belongs to one or more categories, and the categories are how you decide what is safe to run:

  • default: what -sC and -A run
  • safe: won’t crash services or brute-force anything
  • version: extends -sV (the category 7.992 broke)
  • vuln: checks for known vulnerabilities, 105 scripts here
  • auth, brute, intrusive, exploit: get written permission first

Before you run an unfamiliar script, ask Nmap what it is. Anything tagged intrusive or brute can lock accounts or crash a fragile service, so the check is worth the two seconds it takes. The help prints its categories and the NSEDoc link:

nmap --script-help ftp-anon

ftp-anon is in default auth safe, so it is fine on any authorised target.

ftp-anon
Categories: default auth safe
https://nmap.org/nsedoc/scripts/ftp-anon.html
  Checks if an FTP server allows anonymous logins.

  If anonymous is allowed, gets a directory listing of the root directory
  and highlights writeable files.

Name scripts with --script and scope them with -p, so only the ports that matter get probed. A script without -p runs against every matching port the scan finds, which on a busy host means many more connections in the target logs. Here ftp-anon and http-enum each finished in about a second:

sudo nmap --script ftp-anon -p 21 10.0.1.50
sudo nmap --script http-enum -p 80 10.0.1.50

http-enum walked its fingerprint list and found the /admin/ folder and the /backup/ directory with listing enabled, which a default scan only hinted at through robots.txt.

Nmap NSE ftp-anon and http-enum script output on Kali Linux

SNMP with the default public community is the other easy win on Linux servers. Two scripts against UDP 161 pulled the engine details and the full kernel string, which is more precise than anything -O managed:

sudo nmap -sU -p 161 --script snmp-info,snmp-sysdescr 10.0.1.50

The snmp-sysdescr line is the exact Debian kernel build:

PORT    STATE SERVICE
161/udp open  snmp
| snmp-info:
|   enterprise: net-snmp
|   engineIDFormat: unknown
|   engineIDData: 5f760912fb0ce76a00000000
|   snmpEngineBoots: 2
|_  snmpEngineTime: 18m56s
| snmp-sysdescr: Linux target01 6.12.74+deb13+1-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.74-2 (2026-03-08) x86_64
|_  System uptime: 18m55.81s (113581 timeticks)

For SSH, ssh2-enum-algos lists every key exchange, cipher and MAC the server offers, which is the quickest way to audit a hardening change. Run it before and after you edit sshd_config; the SSH commands cheat sheet covers the client side of the same settings:

sudo nmap --script ssh2-enum-algos -p 22 10.0.1.50

These 10 MACs are the OpenSSH compiled-in defaults, which means a stock Debian 13 server still offers hmac-sha1 and umac-64.

|   mac_algorithms: (10)
|       [email protected]
|       [email protected]
|       [email protected]
|       [email protected]
|       [email protected]
|       [email protected]
|       [email protected]
|       hmac-sha2-256
|       hmac-sha2-512
|       hmac-sha1

The SHA-1 and 64-bit tag options are what an audit flags first, and a MACs line in sshd_config that lists only the algorithms you keep removes them. Re-run the script afterwards to confirm the list shrank.

Combine categories and pass script arguments

--script accepts boolean expressions, so you can run only what’s in two categories at once. 'default and safe' on port 80 ran http-title and http-robots.txt and left out anything intrusive. nmap --script-help 'vuln and safe' counts 34 scripts in that overlap, which is a sensible vulnerability check for a production host:

sudo nmap --script 'default and safe' -p 80 10.0.1.50

Scripts take options through --script-args. The most common one changes the HTTP user agent, because the default Nmap agent string announces “Nmap Scripting Engine” and is the first thing a WAF blocks.

sudo nmap --script http-title --script-args http.useragent='Mozilla/5.0' -p 80 10.0.1.50

The whole vuln category is heavier. Scoped to four ports it took 30.4 seconds, and the honest result is mostly “nothing found”, plus the http-enum paths again and SMB scripts that couldn’t negotiate:

sudo nmap --script vuln -p 21,22,80,445 10.0.1.50

Those SMB errors are a protocol mismatch, not a scanner fault. The SMB troubleshooting entry at the end shows how to tell the difference:

80/tcp  open  http
|_http-stored-xss: Couldn't find any stored XSS vulnerabilities.
|_http-dombased-xss: Couldn't find any DOM based XSS.
|_http-csrf: Couldn't find any CSRF vulnerabilities.
| http-enum:
|   /admin/: Possible admin folder
|   /admin/index.html: Possible admin folder
|   /backup/: Backup folder w/ directory listing
|_  /robots.txt: Robots file
445/tcp open  microsoft-ds

Host script results:
|_smb-vuln-ms10-054: false
|_samba-vuln-cve-2012-1182: Could not negotiate a connection:SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [9]
|_smb-vuln-ms10-061: Could not negotiate a connection:SMB: ERROR: Server returned less data than it was supposed to (one or more fields are missing); aborting [9]

An empty vuln run doesn’t mean the host is safe. These scripts check for a fixed list of known flaws, mostly old ones, so treat them as a quick screen and use a real vulnerability scanner for coverage. For the web findings in particular, such as the /backup/ listing http-enum turned up, the web application security books we recommend go well past what NSE can test. After you drop a new .nse file into the scripts directory (/usr/share/nmap/scripts/ for the Kali package, /usr/local/share/nmap/scripts/ for a source build), run sudo nmap --script-updatedb so category selection picks it up.

Tune timing templates T0 to T5

The -T templates bundle timeouts, retries, parallelism and the delay between probes. The timing chapter of the Nmap book lists the exact values. What matters in practice is that T0 to T2 add a fixed delay between probes and T3 to T5 don’t. We timed each template against the lab target:

TemplateScanOpen LAN targetFirewalled target (999 ports dropped)
-T01 port600.70 snot run
-T11 port30.61 snot run
-T2top 100 ports41.09 snot run
-T3all 65,535 / 1,0001.13 s4.86 s
-T4all 65,535 / 1,0001.12 s5.34 s
-T5all 65,535 / 1,0001.18 s3.26 s
-T4 --min-rate 1000 --max-retries 11,000not run2.72 s

On a quiet LAN where every port answers with SYN-ACK or RST, T3, T4 and T5 run at the same speed, because the Nmap congestion control is already running at full rate and the template has nothing to tune. The templates only separate once packets go missing: against the firewalled target T5 was fastest because it gives up on silent ports after fewer retries and shorter timeouts. The other number is T2. Polite mode spent 41 seconds on 100 ports, so at that pace a full 65,535-port T2 scan of one host would run for about seven and a half hours:

Nmap timing templates -T2 vs -T5 scan times on Kali Linux

Our rule: use T4 for internal networks and anything you own, T3 across the internet, and reach for --min-rate and --max-retries when you need speed against filtered hosts, since they beat T5 there (2.72 against 3.26 seconds) without the shorter T5 timeouts. T0 and T1 exist for IDS evasion, and they cost exactly what the delay says: T1 took 30 seconds to check a single port, and T0 took 600.7 seconds, ten full minutes, for that same port.

The rate flags are the precise controls under the templates:

  • --min-rate 5000 kept the full 65,535-port scan at 1.14 seconds
  • --max-rate 100 stretched 1,000 ports to 10.59 seconds, useful on fragile links
  • --max-retries 1 stops Nmap resending to silent ports
  • --host-timeout 30s skips hosts that would hold up a subnet scan

A fast, practical sweep of an internal /24 we own combines them: sudo nmap -sS -T4 --min-rate 5000 --max-retries 3 -p- 10.0.1.0/24 -oA network-scan. Keep --max-retries at 3 or above on Wi-Fi, where dropped probes are common and a lower value turns open ports into false filtered results.

Save scan output in every format

Always save scans to a file, because you will want to diff them later, import them into another tool, or prove what you scanned and when. -oA writes the three main formats in one go.

sudo nmap -sV -p 21,22,80 10.0.1.50 -oA full-scan

That gives you .nmap (the normal text you see on screen), .xml and .gnmap. The grepable file puts all of a host’s ports on a single Ports: line, so one grep pulls the open ports out of hundreds of hosts. That matters on a /24, where the normal output runs to thousands of lines:

grep -oP '\d+/open/tcp//[^/]+' full-scan.gnmap

Each match is a port and its service name, ready for a spreadsheet or a loop. The capture below shows the -oA run, the three files it wrote and that grep:

nmap -oA output files and grepable format parsed with grep on Kali Linux

The XML holds the most detail, including the CPE identifiers that vulnerability tools match against, so it is the one to keep if you only keep one. This is the SSH entry from full-scan.xml.

<port protocol="tcp" portid="22"><state state="open" reason="syn-ack" reason_ttl="64"/><service name="ssh" product="OpenSSH" version="10.0p2 Debian 7+deb13u2" extrainfo="protocol 2.0" ostype="Linux" method="probed" conf="10"><cpe>cpe:/a:openbsd:openssh:10.0p2</cpe><cpe>cpe:/o:linux:linux_kernel</cpe></service></port>

Nmap embeds a stylesheet reference in every XML file, so you can turn a scan into an HTML report for someone who doesn’t read terminals. Kali ships xsltproc:

xsltproc full-scan.xml -o full-scan.html

It wrote an 8,956-byte full-scan.html. If you only need one format, the single flags work the same way: -oN scan.txt, -oX scan.xml and -oG scan.gnmap, and a dash as the filename (-oG -) sends that format to stdout so you can pipe it. In Metasploit, db_import full-scan.xml loads the hosts and services straight into the workspace.

Get past firewalls and IDS

The evasion flags change what your packets look like, not what they can reach, so they help against simple packet filters and signature IDS rules and do nothing against a stateful firewall that drops the port. Each of these found the same three open ports against our target, which proves the flags work but says nothing about whether they would beat the IDS on a client network.

  • -f splits probes into small IP fragments (0.62 s)
  • -D RND:3 adds three random decoy source addresses (0.64 s)
  • --source-port 53 sends from the DNS port that lazy rules trust (0.64 s)
  • --data-length 25 pads probes so their size doesn’t match signatures (0.63 s)

Combined with a slow template, they make one quiet scan. The cost shows up in time rather than in results, so save it for networks where someone is actually watching the alerts:

sudo nmap -sS -T2 -f --source-port 53 --data-length 25 -D RND:2 -p 21,22,80 10.0.1.50

It finished in 2.19 seconds with 21, 22 and 80 open. Decoys only work when the decoy addresses are hosts that could plausibly be scanning: random addresses that don’t exist on the network stand out in a flow log. Source address spoofing with -S is the extreme version, and since replies go to the spoofed address you won’t see them unless you can sniff that traffic, so it’s for testing IDS rules, not for finding ports.

Compare Nmap with Masscan, RustScan and ZMap

Nmap is not the fastest port finder, and on huge ranges you will often pair it with one that is. The common split is a fast tool for “which ports are open” and Nmap for “what is behind them”.

FeatureNmapMasscanRustScanZMap
Port discovery speedModerateVery fastVery fast (hands off to Nmap)Very fast
Service and version detectionYes (-sV)Banners onlyThrough NmapNo
OS detectionYes (-O)NoThrough NmapNo
ScriptingNSE, 619 scriptsNoIts own scripts plus NSEProbe modules
Best forEverything after discoveryLarge rangesFast CTF and lab scansInternet-wide research

On a single LAN host none of them saves you anything, because Nmap already did all 65,535 ports in 1.14 seconds. They earn their place on /16 networks and internet ranges. If you’re choosing a distribution for this toolkit, the ParrotOS vs Kali comparison lists what each ships by default, and the Kali Linux books, penetration testing and red team books and cybersecurity books round-ups cover recon in more depth than any cheat sheet. After recon, the usual next step on a Linux foothold is privilege escalation.

More printable references for Linux admins live on the cheat sheets page.

Troubleshooting

Every error below came from the lab. For the firewall cases we switched on an nftables policy on the target that drops everything except SSH and SNMP.

Ports show “filtered” on a host you know is up

filtered means no reply at all: a firewall dropped the probe. closed means the host answered with a RST. Once the target policy changed to drop, the FTP, HTTP and MySQL ports switched from open to filtered, and an ACK scan confirmed which port the firewall lets through:

Nmap filtered ports and ACK scan unfiltered result against an nftables firewall on Kali Linux

Port 22 is unfiltered to the ACK scan and port 80 is filtered, so the rule set allows 22 and drops 80. From the outside, that’s your firewall map. A service behind a filtered port may still be running; you just can’t reach it from where you’re scanning.

“Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn”

With the drop policy in place and ARP disabled, the discovery probes got no answer and Nmap gave up after 3.05 seconds:

sudo nmap -sn --disable-arp-ping 10.0.1.50

This is the message you will see against most cloud instances and hardened servers.

Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 3.05 seconds

-Pn skips discovery and scans anyway. The same host then showed 22 open and 80 filtered in 1.78 seconds:

sudo nmap -Pn --disable-arp-ping -p 22,80 10.0.1.50

Use -Pn on specific hosts, not on whole subnets: Nmap then treats every address as up and port-scans the empty ones too, which turns a one-minute sweep into hours. A targeted -PS22,443 discovery probe is usually the better fix when you know which ports the hosts expose.

“Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port”

Behind the drop policy there were no closed ports left, only open and filtered, and -O fell back to guessing:

Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|router|storage-misc
Running (JUST GUESSING): Linux 4.X|5.X|6.X|2.6.X|3.X (93%), MikroTik RouterOS 7.X (93%), Synology DiskStation Manager 5.X (85%)
No exact OS matches for host (test conditions non-ideal).

Scanning more ports (-p-) sometimes turns up a closed one. When the firewall drops everything that isn’t allowed, it won’t, and you’re better off reading the OS from -sV banners or SNMP as shown above.

smb-os-discovery and smb-enum-shares return nothing

Against the Debian 13 Samba server both scripts printed the port and nothing else, while the smb2-time and smb2-security-mode scripts in the -A run worked. Samba on Debian defaults to server min protocol = SMB2_02. When we set it to NT1 (SMB1) on the target and re-ran the same command, both scripts filled in the OS, the computer name and four shares, and Nmap reported anonymous READ/WRITE access on public:

sudo nmap --script smb-os-discovery,smb-enum-shares -p 445 10.0.1.50

So an empty result from these two means the server won’t speak SMB1, which on a modern host is good news. Use the smb2-* scripts there, and treat any server where smb-os-discovery does answer as one that still accepts SMB1.

nmap -sV not running version scripts

If -sV output looks thinner than it used to, or -d shows NSE: ... threw an error! attempt to index a nil value from nmap.version_intensity, you’re on Nmap 7.992. Upgrade to 7.993 or later, or use the 7.991 Kali package, as covered in the version section above.

UDP scans take forever

Linux limits ICMP port-unreachable replies, and Nmap slows down to match, so every closed UDP port costs time: 20 ports took 15.7 seconds here. Scan only the UDP ports you care about, add --max-retries 1, and pair -sU with -sV when ports stay open|filtered, because version probes give silent services another chance to answer. SNMP and NetBIOS answered the plain UDP scan here only because Nmap already sends protocol payloads to those well-known ports.

Keep reading

UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Security UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 PHP2Shell (CVE-2026-109618, CVE-2026-109619): Check and Patch PHP Php PHP2Shell (CVE-2026-109618, CVE-2026-109619): Check and Patch PHP PHP2Shell on End-of-Life PHP 8.1, 8.0 and 7.4 (WHMCS, ionCube) Php PHP2Shell on End-of-Life PHP 8.1, 8.0 and 7.4 (WHMCS, ionCube) Homelab and Sysadmin Gifts by Budget: $25, $50, $100 and $250+ Networking Homelab and Sysadmin Gifts by Budget: $25, $50, $100 and $250+ Best Pentesting Hardware for Kali Linux in 2026 Security Best Pentesting Hardware for Kali Linux in 2026 How To Generate Let’s Encrypt Wildcard SSL Certificate Security How To Generate Let’s Encrypt Wildcard SSL Certificate

Leave a Comment

Press ESC to close