Nmap for Embedded and IoT Pen Testing: A Field Guide
If you cannot see what a device is exposing, you cannot secure it. Nmap is the first tool I reach for on almost every embedded engagement. It settles the question you have to answer before anything else: what is this thing actually listening on? Here is how I use it against connected products, along with the things that catch people who learned nmap on cloud servers and then bring those habits to hardware.
Why Nmap Still Matters on Embedded Targets
A connected product is just a host on a network: a thermostat, a vehicle gateway, a smart lock controller, a PLC. It has an IP stack, it has services, and every one of those services is attack surface. Nmap maps that surface quickly. The difference with embedded is that the host on the other end is often a microcontroller with a few hundred kilobytes of RAM and a TCP stack that was never stress tested. Scan it the way you would scan a Linux server and you can knock it over. That is its own kind of finding, but rarely the one you set out to produce.
Step 0: Install and Confirm Scope
Nmap ships in every package manager:
# Debian, Ubuntu, Kali sudo apt install nmap # macOS brew install nmap # confirm the install nmap --version
Nmap version 7.95 ( https://nmap.org ) Platform: x86_64-pc-linux-gnu Compiled with: liblua-5.4.6 openssl-3.0.13 libssh2-1.11.0 zlib-1.3 Available nsock engines: epoll poll select
Before a single packet goes out, get the scope in writing. Which IPs, which subnets, what hours, and a clear acknowledgement that a fragile device might reboot or hang. On embedded work that last point is not boilerplate. It is the difference between a finding and an incident.
Step 1: Host Discovery
Start by finding what is alive. A ping sweep across the subnet with no port scan:
# -sn = ping scan, no ports
nmap -sn 192.168.1.0/24
Starting Nmap 7.95 ( https://nmap.org ) at 2026-06-01 09:14 EDT Nmap scan report for 192.168.1.1 Host is up (0.0012s latency). Nmap scan report for 192.168.1.50 Host is up (0.0089s latency). Nmap done: 256 IP addresses (2 hosts up) scanned in 2.74 seconds
Here is the embedded gotcha. Plenty of devices do not answer ICMP echo. A lean stack may ignore ping entirely, or a firewall in front of it drops the request, and nmap then writes the host off as down and never scans it. If you know the device is there, skip discovery and force the scan with -Pn:
# treat the host as online; scan it regardless of ping
nmap -Pn 192.168.1.50
Starting Nmap 7.95 ( https://nmap.org ) at 2026-06-01 09:16 EDT Nmap scan report for 192.168.1.50 Host is up (0.0091s latency). Not shown: 997 closed tcp ports (reset) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 8443/tcp open https-alt Nmap done: 1 IP address (1 host up) scanned in 1.83 seconds
Step 2: Port Scanning With the SYN Scan
The default workhorse is the TCP SYN scan (-sS). It sends a SYN, watches the reply, and never completes the handshake, which makes it fast and relatively gentle. It needs root:
# SYN scan, all 65,535 TCP ports
sudo nmap -sS -p- 192.168.1.50
Starting Nmap 7.95 ( https://nmap.org ) at 2026-06-01 09:20 EDT Nmap scan report for 192.168.1.50 Host is up (0.0090s latency). Not shown: 65531 closed tcp ports (reset) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 8443/tcp open https-alt 9999/tcp open abyss Nmap done: 1 IP address (1 host up) scanned in 78.12 seconds
That -p- matters more on embedded than almost anywhere else. Note the port the full sweep caught that a default scan would miss: 9999. Vendors like to park services on non-standard ports, such as a debug shell on 9999, a proprietary management protocol on 50000, or a forgotten web interface on 8443. The default scan only checks the top 1,000 ports and walks right past them. Scan the full range first, then narrow.

Reading the States Correctly
An open port is live attack surface, and that is where the work is. A closed port means the device is up but nothing is listening on that number. The state that trips people up is filtered. Nmap got no usable reply, which usually means something is dropping the probe rather than that the port is dead. On embedded gear, filtered often just means the device’s thin stack did not answer the way nmap expected, so the right move is a different probe or slower timing rather than a shrug.
Step 3: Service and Version Detection
Knowing port 8080 is open tells you almost nothing. Knowing it is a GoAhead 2.5 embedded web server tells you which CVEs to pull. That is what -sV does:
# probe open ports to fingerprint the service and version nmap -sV 192.168.1.50 # push harder when banners are stubborn (0-9, 9 is most aggressive) nmap -sV --version-intensity 9 192.168.1.50
PORT STATE SERVICE VERSION 22/tcp open ssh Dropbear sshd 2020.81 (protocol 2.0) 80/tcp open http GoAhead WebServer 2.5.0 8443/tcp open ssl/https GoAhead WebServer 2.5.0 9999/tcp open telnet BusyBox telnetd Service Info: Device: embedded Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 12.47 seconds
Embedded services often hand back terse or non-standard banners, so version detection will not always land cleanly. Even a partial fingerprint combined with the open-port pattern is frequently enough to identify the firmware family.

Step 4: The Nmap Scripting Engine (NSE)
NSE is where nmap stops describing and starts probing. The -sC flag runs the default script set, which covers safe, useful enumeration such as TLS configuration, HTTP titles, and default-credential checks:
# default scripts plus version detection in one pass nmap -sC -sV 192.168.1.50 # point a specific category at the target nmap --script vuln 192.168.1.50 # or run a single script, such as enumerating SNMP, common on IoT gear nmap -sU -p 161 --script snmp-info 192.168.1.50
# nmap -sC -sV PORT STATE SERVICE VERSION 80/tcp open http GoAhead WebServer 2.5.0 |_http-title: Device Login | http-auth: | HTTP/1.1 401 Unauthorized |_ Basic realm=Embedded WebServer 8443/tcp open ssl/https GoAhead WebServer 2.5.0 | ssl-cert: Subject: commonName=192.168.1.50 |_Not valid after: 2049-01-01T00:00:00 |_ssl-date: TLS randomness does not represent time # nmap --script vuln | http-slowloris-check: | VULNERABLE: Slowloris DoS attack |_ State: LIKELY VULNERABLE # nmap -sU -p 161 --script snmp-info | snmp-info: | snmpEngineTime: 4d23h11m |_ sysDescr: Linux gateway 4.9.0 #1 SMP armv7l
One caution. Not every NSE script is gentle. The vuln and brute categories can hammer a device hard enough to crash it. Read what a script does before you run it against something fragile, and skip the aggressive -A flag on constrained hardware, since it bundles OS detection, version detection, scripts, and traceroute into one heavy burst.
Step 5: Do Not Forget UDP
IoT lives on UDP: CoAP, SNMP, mDNS, DTLS, and proprietary discovery protocols. TCP-only scanning misses half the picture. UDP scanning is slow, so scope it to the ports that matter:
# top 50 UDP ports, a sane starting point sudo nmap -sU --top-ports 50 192.168.1.50 # or target known IoT UDP services directly sudo nmap -sU -p 53,123,161,5353,5683 192.168.1.50
PORT STATE SERVICE 53/udp open domain 123/udp open ntp 161/udp open snmp 1900/udp open|filtered upnp 5353/udp open mdns Nmap done: 1 IP address (1 host up) scanned in 47.30 seconds
Step 6: Scan Like the Stack Is Fragile
This is the embedded-specific skill. A desktop scan fires probes as fast as the network allows. A microcontroller with one socket buffer and a cooperative scheduler cannot keep up, so it drops packets, which shows up as false filtered results, or it watchdog-reboots in the middle of your scan. Slow down on purpose:
# -T2 = polite timing; pace the probes; cap retries sudo nmap -sS -p- -T2 --scan-delay 100ms --max-retries 1 192.168.1.50 # cap the packet rate explicitly for the most delicate targets sudo nmap -sS --max-rate 50 192.168.1.50
Starting Nmap 7.95 ( https://nmap.org ) at 2026-06-01 10:02 EDT Nmap scan report for 192.168.1.50 Host is up (0.011s latency). PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 8443/tcp open https-alt 9999/tcp open abyss Nmap done: 1 IP address (1 host up) scanned in 642.05 seconds
Same four open ports as the fast scan, but it took 642 seconds instead of 78. That trade is almost always worth it: a scan that returns clean, reproducible results and leaves the device running beats a fast scan that crashes the target. Timing templates run from -T0 (paranoid) through -T5 (insane), and -T2 is a sensible default for hardware you do not fully trust to survive.
Step 7: Save Everything for the Report
Capture output in all formats up front so you never have to re-scan to recover a result:
# -oA writes .nmap (human), .xml (tooling), and .gnmap (grep) at once
sudo nmap -sS -sV -p- -T2 -oA embedded_scan_192.168.1.50 192.168.1.50
Nmap done: 1 IP address (1 host up) scanned in 95.44 seconds $ ls embedded_scan_192.168.1.50.* embedded_scan_192.168.1.50.gnmap embedded_scan_192.168.1.50.nmap embedded_scan_192.168.1.50.xml
Putting It Together
A realistic first-contact sequence against a single device on a bench:
# 1. full TCP sweep, gently, skip ping, save output sudo nmap -Pn -sS -p- -T2 --scan-delay 100ms -oA tcp_full 192.168.1.50 # 2. enumerate just the open ports it found sudo nmap -Pn -sV -sC -p 22,80,8443,9999 -oA tcp_enum 192.168.1.50 # 3. check the usual IoT UDP suspects sudo nmap -Pn -sU --top-ports 50 -oA udp_top 192.168.1.50
# 1. tcp_full -> full SYN sweep Discovered open ports: 22, 80, 8443, 9999/tcp # 2. tcp_enum -> service and default scripts on the open ports 22/tcp open ssh Dropbear sshd 2020.81 80/tcp open http GoAhead WebServer 2.5.0 8443/tcp open ssl/https GoAhead WebServer 2.5.0 9999/tcp open telnet BusyBox telnetd # 3. udp_top -> common IoT UDP services 161/udp open snmp 5353/udp open mdns $ ls *.nmap *.xml *.gnmap # nine result files, three per scan
With those three commands you move from knowing there is a device at .50 to having a documented inventory of every service it exposes. That inventory is the foundation for everything that follows in the assessment.
Where This Fits
Nmap is reconnaissance, not the whole assessment. It tells you where the doors are, not whether the locks hold. Mapping the network surface is the first move in a product security assessment or a penetration test. What comes next is firmware analysis, fault injection, protocol fuzzing, and tracing each finding back to the design decision that allowed it. If you are shipping a connected product and want a clear picture of what it exposes, and what to do about it, that is the kind of work we do at Berkner Tech.