Smap: Why This Nmap Clone Doesn't Touch Your Target
Hook
What if you could scan 200 hosts per second without sending a single packet to your target? Smap doesn't probe networks—it queries them from a database of 40 billion records.
Context
Traditional network scanning has always been loud. Every time you run Nmap against a target, you're announcing your presence. Firewalls log your connection attempts. IDS systems trigger alerts. Security teams get notifications. For penetration testers, bug bounty hunters, and security researchers, this creates a fundamental dilemma: you need to understand what ports and services are exposed, but the act of scanning itself can burn your reconnaissance phase before you've learned anything useful.
Shodan solved part of this problem by continuously scanning the entire Internet and indexing what it finds. But accessing that data meant learning Shodan's API, parsing JSON responses differently than you would Nmap output, and integrating yet another tool into your workflow. Smap bridges this gap by transforming Shodan into a drop-in Nmap replacement. It parses the same command-line arguments you already know, queries Shodan's free InternetDB API, and outputs data in Nmap's native formats. The result is passive reconnaissance that looks and feels exactly like active scanning, but leaves zero footprint on target systems.
Technical Insight
At its core, Smap is an elegant translation layer written in Go. When you run a command like smap -p 80,443 scanme.nmap.org, Smap doesn't open sockets or craft packets. Instead, it resolves the hostname to an IP address and makes an HTTP GET request to https://internetdb.shodan.io/{ip}. Shodan's InternetDB returns JSON containing historical scan data—ports found open, detected services, CPE identifiers, and even known CVEs associated with that host.
The architecture is remarkably straightforward. Smap's parser transforms Nmap-style arguments into internal data structures, but ignores scanning-specific flags like timing templates or OS detection since those require active probing. It then iterates through target IPs (handling CIDR ranges and host lists), queries InternetDB for each, and transforms the JSON responses into whatever output format you specified—standard Nmap output, XML, or greppable format.
Here's what a typical InternetDB response looks like and how Smap processes it:
// Simplified example of Shodan InternetDB response structure
type ShodanResponse struct {
IP string `json:"ip"`
Ports []int `json:"ports"`
CPEs []string `json:"cpes"`
Vulns []string `json:"vulns"`
Tags []string `json:"tags"`
}
// Smap transforms this into Nmap-compatible output
func formatAsNmap(host string, data ShodanResponse) string {
var output strings.Builder
output.WriteString(fmt.Sprintf("Nmap scan report for %s\n", host))
output.WriteString(fmt.Sprintf("Host is up.\n"))
output.WriteString(fmt.Sprintf("PORT STATE SERVICE\n"))
for _, port := range data.Ports {
service := guessService(port) // Map common ports to service names
output.WriteString(fmt.Sprintf("%d/tcp open %s\n", port, service))
}
if len(data.Vulns) > 0 {
output.WriteString("\nVULNERABILITIES:\n")
for _, cve := range data.Vulns {
output.WriteString(fmt.Sprintf(" %s\n", cve))
}
}
return output.String()
}
The magic is in what Smap doesn't do. There's no packet crafting library, no TCP handshake logic, no service fingerprinting engine. The entire binary is essentially an HTTP client wrapped in an Nmap argument parser and output formatter. This architectural simplicity is why Smap can "scan" 200 hosts per second—it's bound only by HTTP request latency and Shodan's rate limits, not by network timeouts or OS socket limits.
For scenarios where you need verification, Smap includes an --active flag that creates a hybrid workflow. When enabled, Smap first queries Shodan to identify which ports should be open, then shells out to your local Nmap installation to actively scan only those specific ports:
# Passive-then-active hybrid approach
smap --active -p- target.com
# Behind the scenes, Smap:
# 1. Queries Shodan: finds ports 22, 80, 443, 8080 open
# 2. Executes: nmap -p 22,80,443,8080 target.com
# 3. Merges results and formats output
This dramatically reduces scan time versus blind active scanning. Instead of probing all 65,535 ports, you're only verifying the subset that Shodan found in historical scans. For a typical web server with 4-5 open ports, this turns a 20-minute full port scan into a 5-second targeted probe.
The output format compatibility deserves special attention. Smap generates XML that's valid for Nmap parsers, meaning your existing automation—scripts that parse Nmap XML, tools that import scan results, visualization platforms—all work without modification. This is critical for integration into existing security workflows. You're not bolting on a new data format; you're getting the same structured output you've been consuming for years.
Gotcha
The fundamental limitation is data freshness. Shodan scans the Internet continuously, but individual hosts might be scanned anywhere from daily to weekly. The InternetDB API doesn't expose timestamp metadata, so you have no visibility into whether the port data you're seeing is from yesterday or seven days ago. For penetration testing engagements or security audits where you need real-time state, this staleness is unacceptable. A service could have been patched, a port could be closed, or new services could be running that Shodan hasn't discovered yet.
Coverage gaps are equally significant. Shodan only knows about hosts it has scanned, which means anything behind NAT, on private networks, or using IPv6 (currently unsupported by InternetDB) is invisible. If you're assessing an organization's internal infrastructure or newly deployed cloud instances, Smap will return empty results while Nmap would find open ports. The tool also inherits Shodan's detection accuracy—service identification is based on banner grabbing and heuristics, which can misidentify services or miss version details that Nmap's more aggressive probing would catch. I've seen cases where Shodan labeled a custom application server as "http" while Nmap's scripts correctly identified it as a specific framework version with known vulnerabilities.
Verdict
Use if: You're doing OSINT reconnaissance where target alerting is a concern, conducting initial bug bounty enumeration to identify attack surface before deep testing, need to scan large IP ranges quickly for initial triage, or operate in environments where active scanning requires extensive approval processes. Smap excels at answering "what does the Internet think this host looks like?" without tipping your hand. Skip if: You need real-time accuracy for security assessments, must scan internal/private networks or IPv6 infrastructure, require detailed service version fingerprinting for vulnerability assessment, or are working on compliance audits where data freshness is documented. The hybrid active mode is clever but defeats the stealth benefit—if you're going to touch the target anyway, just use Nmap directly. Smap is best deployed as a first-pass reconnaissance tool that informs where you focus expensive active scanning efforts.