black3dm0nd Research logoblack3dm0nd Research logoblack3dm0ndoffensive security research
InfoPublished

research/nmap-evasion-research/index.mdx

Evasion with Nmap, Minus the Cargo Cult

A practical look at Nmap evasion, timing, scan types, decoys, DNS leaks, version scanning, and matching scan behavior to the target network.

black3dm0ndOct 10, 2026updated Oct 10, 202614 min readNetwork Security
EvasionNetwork ScanningNmapOpsecReconRed Team
CVSS
N/A
Status
Published
Artifacts
1 indexed
Evasion with Nmap, Minus the Cargo Cult cover image
$ cat ./research/nmap-evasion-research/index.mdx --section summary
Loaded sanitized MDX. Rendering public, published research content only.

The fastest way to get a red team burned is nmap -A -T4 -p- scope.txt, then walking off for coffee. Aggressive service detection, every script in the default set, full port range, as fast as the network allows. It lights up every sensor the client owns and hands their SOC a clean timeline of your foothold. I've watched it happen. I've done it, early on, and learned.

Most Nmap "evasion" writeups are a pile of flags copied from the man page with no engagement context. -f, -D, --spoof-mac, done. That's not evasion, that's superstition. Real evasion starts with a decision most people skip, and half the flags in this post are ones I'd tell you not to use.

A reminder before the commands: this is for authorized work, inside an agreed scope, with a rules-of-engagement document you can point to. Evasion that causes an outage or that you can't reproduce in your report is a liability, not a flex. Keep -oA on everything.

First, decide what you're actually doing

Two jobs wear the same clothes and want opposite behavior.

If the objective is testing detection and response, you are not really hiding. You are generating signal on purpose, in a controlled way, and coordinating so blue can grade themselves. Going fully dark here wastes the engagement. You want measured, attributable, documented noise.

If the objective is emulating a stealthy actor who is trying not to get caught, then stealth is the deliverable, and the rules change. Slow down, spread out, come from somewhere that looks normal, and accept that you'll collect less data per hour.

Pick one before you type anything. The flags only make sense once you know which game you're playing.

Map the defenses before you try to beat them

You can't evade what you haven't characterized. Before the real scan, I spend probes learning the perimeter.

bash
1# Is there a stateful firewall, and which ports are filtered vs closed?2nmap -sA -p 1-1024 -n -Pn target        # ACK scan: "filtered" => stateful firewall in path3 4# Window scan can distinguish some firewalls' open/closed on "unfiltered" results5nmap -sW -p 1-1024 -n -Pn target6 7# Is there an inline IDS/IPS that answers packets a host would silently drop?8nmap -sS --badsum -p 80,443 -n -Pn target   # responses to bad-checksum pkts => a middlebox, not the host

-sA tells you where state is enforced. --badsum is the one people forget: a real TCP stack drops a packet with a bogus checksum, so anything that answers is a middlebox in the path. That single result changes your whole approach, because now you know you're dealing with an IPS and not just an ACL.

The lever that actually matters is rate

Timing templates are a blunt instrument. -T0 through -T5 bundle a dozen settings, and the two extreme presets are the only ones I reach for deliberately. What you actually want is direct control of how fast packets leave and how long you wait.

bash
1# Slow, deliberate, low-signature. --max-rate is the real stealth knob.2nmap -sS -p 80,443,22,3389 --max-rate 10 --scan-delay 1s \3     --max-retries 1 -n -Pn -oA slow_sweep target4 5# Spread a full sweep thin over a long window instead of hammering6nmap -sS -p- --max-rate 50 --max-retries 1 --randomize-hosts \7     -n -Pn -oA wide_slow scope.txt

--max-rate 10 with a scan delay is the difference between a spike the SOC can't miss and a trickle that blends into background noise. --max-retries 1 keeps you from retransmitting into rate-limited ports and tripling your footprint. --randomize-hosts stops you from walking the subnet in order, which is one of the most obvious patterns in a flow log. Patience is the strongest evasion technique Nmap has, and it isn't a flag, it's a decision to run the scan over hours or days.

Host discovery is where you leak intent

Default host discovery pings before it scans, and a sweep of ICMP echo plus a couple of TCP probes across a range is a tell on its own. Control it.

bash
1nmap -sS -Pn -n target          # skip discovery entirely; don't ping, don't resolve2nmap -sn -PS443,80 -n scope.txt # if you must sweep, use ports that look like real traffic

-Pn skips the ping and treats the host as up. -n disables reverse DNS, which matters more than people think: default Nmap fires PTR lookups, and those queries hit the target's resolver and sit in their DNS logs with your targets spelled out. Turning off reverse DNS removes an entire paper trail. If you need names, point at a resolver you control with --dns-servers.

Scan type is an OPSEC choice

bash
1nmap -sS ...   # half-open: no completed handshake, fewer application-layer logs2nmap -sT ...   # full connect: completes the handshake, lands in app logs; use over proxychains3nmap -sI zombie:port -Pn -p- target   # idle scan: your source IP never appears

-sS is quieter at the application layer because the handshake never completes, so services that log connections see less. It does not hide the SYN from a network sensor. If quiet-at-the-app-layer is what you need and you can't send raw packets (you're tunneling through a SOCKS proxy from your C2), you're stuck with -sT.

The idle scan is the only technique in Nmap that genuinely hides your source address. You bounce probes off a zombie with a predictable, incremental IP ID and read the target's responses in the zombie's ID sequence. The target logs the zombie, never you.

bash
1# Find a candidate zombie: idle, and with incremental IPID2nmap -p 80 --script ipidseq target_candidates.txt3nmap -sI 192.0.2.50:80 -Pn -p 1-1024 -n -oA idle target

The catch is that a good zombie is rare now. Modern stacks randomize IP IDs, so most hosts won't work, and the ones that do are often printers and embedded junk. When you find one, it's worth the effort, because nothing else gives you true source obfuscation.

The decoy-and-spoof theater

bash
1nmap -sS -D RND:5 -n -Pn target          # random decoys2nmap -sS -D 198.51.100.7,ME,198.51.100.9 # hand-picked decoys around your real IP3nmap -sS -S 198.51.100.200 -e eth0 ...    # spoof source (you won't see replies unless on-path)4nmap --spoof-mac 0 ...                    # random MAC (LAN only)5nmap -g 53 ...                            # source port 53; abuses lazy "allow DNS" rules

Decoys make the target's logs show several sources, which sounds great until an analyst correlates on the session that actually completed and filters the rest. Against a competent SOC, decoys mostly add noise you have to explain in your report. Worse, firing spoofed sources at an IPS can get all of them blocked, yourself included. Use live, plausible decoys sparingly, and never RND against something with active blocking.

Source spoofing with -S is close to useless unless you're on the path to sniff the replies, or you're doing an idle scan, which already handles source hiding properly. --spoof-mac is real but LAN-only and mostly relevant for dodging NAC or MAC allowlists.

The one in that block that earns its keep on real engagements is -g. Plenty of firewalls still carry a rule that trusts source port 53 or 88 or 20, written by someone who didn't think it through. Scanning from --source-port 53 walks through those. Cheap, occasionally magic.

Fragmentation and the exotic TCP flags: be honest

bash
1nmap -f ...              # fragment into 8-byte pieces2nmap --mtu 16 ...        # custom fragment size (multiple of 8)3nmap -sF / -sN / -sX ... # FIN / NULL / Xmas4nmap --data-length 64 ...# pad packets to change the size signature

I'm including these so I can tell you they're mostly obsolete. Suricata and Snort reassemble fragments, so -f bypasses naive or legacy filtering and little else. FIN, NULL, and Xmas scans rely on the target following the RFC the way old BSD stacks did; against a modern stateful firewall they usually just come back filtered and teach you nothing. They cost almost nothing to try against unknown or clearly ancient infrastructure, and you should know they exist, but if your plan leans on them you're planning to fail against anything current. --data-length to shift packet sizes off a default signature is marginally more defensible, and still marginal.

Version and script scanning will undo all of it

The quietest port scan in the world is pointless if you follow it with -sV -sC and spray a hundred probes plus the entire default script set at every open port.

bash
1nmap -sV --version-intensity 2 -p 443 -n -Pn target     # light banners only2nmap --script "safe and not intrusive" -p 443 target    # curate the scripts, always

Keep version intensity low. Hand-pick scripts instead of taking -sC wholesale, because some default scripts are intrusive and a few are outright loud. And forget Nmap's --proxies as a serious pivoting tool; it only covers connect scans and some NSE. For real pivoting, run -sT -Pn -n through proxychains over your established SOCKS, and accept the connect-scan tradeoff.

The checklist I actually run

  • Confirm scope and ROE. Decide: detection test, or stealth emulation. This governs everything below.
  • Scan from the best position available. A quiet -sT from an internal foothold beats every external evasion trick combined.
  • Characterize the perimeter first: -sA for state, --badsum for inline IPS, note what's filtered.
  • Kill the obvious leaks: -Pn to skip discovery, -n to stop reverse-DNS lookups hitting their logs.
  • Control rate, not just -T: --max-rate, --scan-delay, --max-retries 1. Spread across time windows.
  • Reduce the target set. Fewer ports, known ports first, --randomize-hosts. Scope is stealth.
  • Pick the scan type for the log surface you care about: -sS for fewer app logs, -sI if you have a viable zombie and need to hide your source.
  • Consider -g 53/88/443 against lazy firewall rules before reaching for decoys.
  • Use decoys and spoofing only when you understand the blocking behavior, and never against active IPS.
  • Keep -sV/NSE light and curated. The recon tail is where quiet scans get loud.
  • -oA everything. If it isn't in your artifacts, it didn't happen.

Cut the time, and blend into their own space

Two more things that matter more than any single flag.

You rarely need all 65,535 ports. Most engagements live or die on a couple dozen common services, and scanning only those cuts your runtime and your signature by an order of magnitude. Hit what actually gets you somewhere and come back for the long tail later if the objective needs it.

bash
1# the services that usually matter, instead of -p-2-p 21,22,25,53,80,110,135,139,143,443,445,993,995,1433,3306,3389,5985,8080,84433# or let Nmap pick the statistically common ones4--top-ports 100

And before you pick decoys, learn their address space. Pull their ASN and netblocks from whois and BGP data, scrape certificate transparency and DNS for the ranges they actually own. Then seed your decoys from the client's own CIDRs instead of random internet IPs. Traffic that appears to come from their own ranges blends with what a defender expects to see, and against ACLs that trust internal or partner space it can slip past rules that would drop an obvious outsider. Source spoofing from their range plays the same trick, with the usual caveat that you won't see the replies unless you're on-path or running an idle scan.

bash
1# decoys drawn from the client's OWN netblock (203.0.113.0/24 here), not randoms2-D 203.0.113.11,203.0.113.37,ME,203.0.113.52

One operational reality that bites people: a slow evasive scan can run for hours, and it will outlive your SSH session. A dropped VPN should not kill a fourteen-hour scan. Run it inside a terminal multiplexer, or detach it entirely.

bash
1tmux new -s recon          # run the scan here; Ctrl-b d to detach, tmux attach -t recon to return2# or just background it and walk away3nohup sudo nmap ... -oA engagement_evasive scope.txt &>/dev/null &4# and if a scan does die mid-run, you don't start over:5nmap --resume engagement_evasive.gnmap

Put it together and the end-state command looks like this. Slow SYN scan, no discovery or DNS noise, a trusted source port, decoys from the client's own range, common services only, padded packets, fully logged and resumable.

bash
1sudo nmap -sS -Pn -n \2  -p 21,22,25,53,80,110,135,139,143,443,445,993,995,1433,3306,3389,5985,8080,8443 \3  --max-rate 20 --scan-delay 750ms --max-retries 1 --randomize-hosts \4  -g 53 \5  -D 203.0.113.11,203.0.113.37,ME,203.0.113.52 \6  --data-length 32 \7  -oA engagement_evasive scope.txt

Run that inside tmux, point the decoys at ranges they actually own, and tune --max-rate down further if their sensors are sharp. It is slow on purpose. Slow is the point.

Match the scan to the network

There's no universal evasion profile, because evasion is a property of the target, not of Nmap. A flat network behind a tired firewall with no SOC will swallow a fast SYN sweep without blinking. A monitored environment with a tuned IPS and analysts watching flow data will flag a scan you were sure was careful. The flags don't change. The environment decides which ones matter.

So you adjust to the room. Some engagements are time-boxed hard, or the objective is coverage rather than stealth, and you need results today. That's fine. You can scan fast and still refuse to be sloppy. Keep discovery and DNS noise off, curate the ports, use a trusted source port, skip the loud enumeration, and let the rate climb while you drop everything that screams.

bash
1# clock's running, but still shaving every signature you can afford to2sudo nmap -sS -Pn -n --top-ports 200 \3  -g 53 --min-rate 1000 --max-retries 2 --randomize-hosts \4  -oA engagement_fast scope.txt

That isn't a stealth scan. It's a fast scan that doesn't volunteer anything it doesn't have to, which is the right trade when the clock wins.

What actually separates people is knowing which end of that dial to pick, and that only comes from reading the target. Watch how the network answers your early probes. Notice the rate limiting, the resets, the latency that spikes when you push. Feel where the sensors are before you commit to a full run.

The flags are easy. The balance is the job. Know the target, feel their network, and let the environment tell you how quiet you need to be, rather than pasting the same command into every engagement and hoping.

Affected technology

NmapIDSIPSFirewallsNetwork Reconnaissance

Remediation

Use this material only inside authorized scope, keep notes reproducible, and validate every automated finding by hand before reporting.

Disclosure timeline

References

Related posts

No research found

Try a different search or filter set.