Most people learn one Nmap command — usually nmap -sV target — and stop there. I did too, for a while. But once I started digging into how TCP actually works at the packet level, I realized Nmap’s different scan types aren’t just flavor variations of the same thing. Each one exploits a different quirk of how operating systems respond to malformed or unusual packets, and choosing the right one can mean the difference between an accurate picture of a target and a firewall silently feeding you garbage.
This article walks through every major scan type Nmap offers, explains the packet mechanics behind each, and tells you exactly when I reach for it.
A Quick TCP Refresher
Before any of this makes sense, you need the three-way handshake in your head:
sequenceDiagram
participant Client
participant Server
Client->>Server: SYN
Server->>Client: SYN-ACK
Client->>Server: ACK
Note over Client,Server: Connection established
Every scan technique below is really just a different way of interacting with — or deliberately breaking — this handshake.
TCP SYN Scan (-sS)
This is Nmap’s default scan and the one I use 95% of the time. It’s often called a “half-open” scan because it never completes the handshake.
sudo nmap -sS 192.168.1.10
How it works: Nmap sends a SYN packet. If the port is open, the target replies SYN-ACK, and instead of completing the handshake with an ACK, Nmap sends a RST to tear down the connection before it’s fully established.
sequenceDiagram
participant Nmap
participant Target
Nmap->>Target: SYN
Target->>Nmap: SYN-ACK (port open)
Nmap->>Target: RST
Why I use it: It’s fast, and because the connection is never fully established, it doesn’t get logged by many basic applications the way a full connection would. It requires raw socket access, which means root or sudo.
Port state interpretation:
- SYN-ACK received → open
- RST received → closed
- No response / ICMP unreachable → filtered
TCP Connect Scan (-sT)
This is the fallback when you don’t have raw socket privileges.
nmap -sT 192.168.1.10
How it works: Nmap completes the full three-way handshake using the operating system’s standard connect() system call, then immediately closes the connection.
sequenceDiagram
participant Nmap
participant Target
Nmap->>Target: SYN
Target->>Nmap: SYN-ACK
Nmap->>Target: ACK
Nmap->>Target: FIN (close)
Why I use it: Any time I’m on a box where I can’t get root — some restricted CI environment, a Windows box without Npcap configured, or a shared account with no sudo access. It’s slower and far more likely to appear in target-side logs than -sS, because it’s a legitimate, fully-formed connection from the OS’s perspective.
UDP Scan (-sU)
UDP is connectionless, so there’s no handshake to abuse — this scan works completely differently.
sudo nmap -sU 192.168.1.10
How it works: Nmap sends a UDP packet with no payload (or a protocol-specific payload for well-known ports). If it gets an ICMP “port unreachable” response, the port is closed. If it gets a UDP response back, the port is open. If it gets nothing, the port is marked open|filtered — because UDP gives no reliable “I’m closed” signal by default.
flowchart TD
A[Send UDP probe] --> B{Response?}
B -->|ICMP port unreachable| C[Closed]
B -->|UDP response| D[Open]
B -->|No response| E[Open or Filtered]
Why it’s slow: Most operating systems rate-limit ICMP responses to a handful per second. Scanning all 65535 UDP ports on a single host can genuinely take hours. I almost always narrow scope:
sudo nmap -sU -p 53,67,68,69,123,161,162,500,514 192.168.1.10
Why I still use it: DNS (53), SNMP (161), NTP (123), and DHCP (67/68) all run over UDP. If you skip UDP scanning entirely, you’re blind to a huge category of misconfigured services — SNMP with default community strings is still shockingly common.
TCP ACK Scan (-sA)
This one doesn’t tell you if a port is open — it tells you whether a firewall is stateful.
sudo nmap -sA 192.168.1.10
How it works: Nmap sends a bare ACK packet, which is invalid outside an existing connection. Any real host replies with RST regardless of whether the port is open. If you get RST, Nmap marks it “unfiltered” (there’s no firewall dropping it). If you get nothing, it’s “filtered” — something is dropping unsolicited packets.
Why I use it: Purely for firewall rule mapping. If I run -sS and everything shows filtered, I follow up with -sA to figure out whether that’s a stateless ACL or a full stateful firewall. It tells me about the firewall, not the service behind it.
TCP FIN Scan (-sF)
A stealth-oriented technique that exploits an RFC 793 quirk.
sudo nmap -sF 192.168.1.10
How it works: Nmap sends a packet with only the FIN flag set — no prior handshake. Per the TCP RFC, a closed port should respond with RST, while an open port should simply ignore the malformed packet and send nothing.
The catch: This behavior only holds on RFC-compliant stacks. Modern Windows systems don’t follow this rule and will respond with RST regardless of port state, making FIN scans unreliable against Windows targets. I mostly use this against older Unix-like systems, or in combination with other scans to cross-check results.
XMAS Scan (-sX)
Named because the packet is “lit up” with flags, like a Christmas tree.
sudo nmap -sX 192.168.1.10
How it works: Sets FIN, PSH, and URG flags simultaneously — a combination that should never occur in normal TCP traffic. Same interpretation logic as FIN scan: no response implies open, RST implies closed.
flowchart LR
A[FIN + PSH + URG set] --> B[Send to target]
B --> C{RST received?}
C -->|Yes| D[Closed]
C -->|No response| E[Open or Filtered]
Same limitation as FIN scanning applies here — modern Windows and many hardened Linux firewalls simply ignore the RFC 793 nuance and respond with RST to everything, making this scan more useful historically than practically today.
NULL Scan (-sN)
The mirror image of XMAS — no flags set at all.
sudo nmap -sN 192.168.1.10
Same detection logic, same limitations. I mostly run FIN, XMAS, and NULL scans together as a set when I’m specifically trying to fingerprint whether a target’s TCP stack behaves in an RFC-compliant way — which itself is a mild OS fingerprinting signal.
TCP Window Scan (-sW)
A less common variant of the ACK scan that examines the TCP window size field in the RST response.
sudo nmap -sW 192.168.1.10
Some operating systems report a nonzero window size for open ports and zero for closed ones, even though both send RST. It’s unreliable across different OS/TCP stack implementations, so I treat this as a supplementary technique rather than a primary one.
Comparison Table
| Scan | Flag | Root Required | Speed | Stealth | Best Use Case |
|---|---|---|---|---|---|
| SYN | -sS | Yes | Fast | High | Default, general purpose |
| Connect | -sT | No | Medium | Low | No root access |
| UDP | -sU | Yes | Very Slow | Medium | DNS, SNMP, NTP checks |
| ACK | -sA | Yes | Fast | High | Firewall rule mapping |
| FIN | -sF | Yes | Fast | High | Legacy Unix stacks |
| XMAS | -sX | Yes | Fast | High | Historical / niche |
| NULL | -sN | Yes | Fast | High | Historical / niche |
| Window | -sW | Yes | Fast | High | Supplementary confirmation |
Practical Example: Combining Scans
On a real target, I don’t rely on one scan type alone. Here’s a workflow I use when a target’s firewall behavior is unclear:
# Step 1: standard SYN scan
sudo nmap -sS -p 1-1000 192.168.1.10 -oN syn_scan.txt
# Step 2: cross-check with ACK to understand firewall statefulness
sudo nmap -sA -p 1-1000 192.168.1.10 -oN ack_scan.txt
# Step 3: check UDP on common service ports
sudo nmap -sU -p 53,123,161 192.168.1.10 -oN udp_scan.txt
Comparing the SYN and ACK results tells me whether “filtered” ports are genuinely blocked by a stateful firewall or just being silently dropped for other reasons.
Python Integration
Automating a multi-scan-type comparison with python-nmap:
import nmap
scanner = nmap.PortScanner()
# SYN scan
scanner.scan('192.168.1.10', '1-1000', arguments='-sS')
syn_results = scanner['192.168.1.10']['tcp']
# ACK scan for firewall mapping
scanner.scan('192.168.1.10', '1-1000', arguments='-sA')
ack_results = scanner['192.168.1.10']['tcp']
for port in syn_results:
syn_state = syn_results[port]['state']
ack_state = ack_results.get(port, {}).get('state', 'unknown')
if syn_state == 'filtered' and ack_state == 'unfiltered':
print(f"Port {port}: likely closed behind a stateless ACL, not a firewall")
Troubleshooting Common Issues
All ports show “filtered” on a SYN scan — this usually means a firewall is dropping packets rather than rejecting them. Follow up with an ACK scan to confirm statefulness.
UDP scan reports everything as “open|filtered” — this is UDP’s default ambiguous state when no response arrives. Narrow to specific ports and increase timeout with --host-timeout if the network is slow.
FIN/XMAS/NULL scans show every port as open — you’re almost certainly scanning a modern Windows host, which doesn’t follow the RFC 793 behavior these scans depend on. Switch to SYN or Connect scan instead.
Connect scan is much slower than SYN scan — expected. Full handshakes take longer than half-open probes, especially across high-latency links.
Limitations
None of these techniques are bulletproof. Modern IDS/IPS systems fingerprint unusual flag combinations (FIN, XMAS, NULL) instantly, and non-RFC-compliant stacks like Windows break the underlying assumptions those scans rely on entirely. UDP scanning is inherently probabilistic due to rate-limiting. Always treat “filtered” as “I genuinely don’t know,” not “closed.”
Security Best Practices
- Default to
-sSfor general assessments — it balances speed, accuracy, and stealth reasonably well. - Never assume a single scan type gives you the full picture; cross-reference SYN and ACK results.
- On production networks, prefer
-sTwith conservative timing over aggressive half-open scanning, since some IDS platforms treat SYN floods as a red flag regardless of intent. - Always scope UDP scans to relevant ports rather than sweeping all 65535 — it’s both faster and less disruptive.
Frequently Asked Questions
Which scan type is the most accurate? SYN scan (-sS) is generally considered the most reliable balance of speed and accuracy on modern systems, since it works consistently across both RFC-compliant and non-compliant TCP stacks.
Why do FIN, XMAS, and NULL scans exist if they’re unreliable on Windows? They predate widespread Windows hardening and are still genuinely useful against older Unix/Linux systems and for specific evasion scenarios against certain older IDS signatures.
Can UDP scanning ever be fast? Only if you scope it to a small number of ports. Full 65535-port UDP scans are almost never practical due to ICMP rate-limiting on the target side.
Do I need root for every scan type? No — Connect scan (-sT) is the only major technique that works without elevated privileges, since it uses the OS’s normal socket API instead of crafting raw packets.
Idle Considerations When Choosing a Scan Type
A question I get asked often: “why not just always use -sS and ignore the rest?” In practice, I’ve found real situations where each technique earns its place:
- On a shared CI/CD runner without root access,
-sTis the only option available at all. - Against a host where SYN packets are silently dropped by an upstream device but the host itself is reachable, switching between SYN and ACK scans quickly tells me whether the block is happening at the firewall layer or the host layer.
- When auditing my own home lab’s DNS resolver, SNMP agent on my managed switch, and NTP daemon, UDP scanning is the only way to actually confirm those services are listening the way I expect.
- During a training exercise recreating older-style intrusion detection evasion for educational purposes, FIN/NULL/XMAS scans against a deliberately vulnerable legacy Linux VM demonstrate RFC 793 behavior in a way that’s hard to understand from documentation alone.
Interpreting Ambiguous Results
One thing that trips up people new to Nmap is treating “filtered” as equivalent to “closed.” They are not the same thing, and conflating them leads to bad conclusions in a report. A closed port means the target actively responded with a RST, confirming nothing is listening. A filtered port means Nmap got no usable signal at all — the packet could have been silently dropped by a firewall, lost to network congestion, or blocked by an intermediate device that has nothing to do with the target host itself.
When I see a large batch of filtered ports, my next move is almost always a follow-up ACK scan rather than assuming the ports are simply closed. That single follow-up step has saved me from writing inaccurate findings more than once.
Wrapping Up
Understanding the packet mechanics behind each scan type turns Nmap from a black box into a precision instrument. I don’t reach for -sS out of habit anymore — I reach for it because I understand exactly what happens on the wire when I do, and I know when a different technique will actually give me better information. That understanding is the difference between running a tool and actually doing reconnaissance.