Nmap 使用方式与典型场景
四、使用方式与典型场景
下面按场景给出可直接使用的命令。
示例一,内网资产盘点。先做主机发现建立在线资产清单,再对在线主机做常见的端口与服务识别。限定在授权网段内,用文件方式管理目标范围:
# 第一步:主机发现在线资产
nmap -sn -iL targets.txt -oA assets-alive
# 第二步:对在线主机做常见端口的服务识别
nmap -sS -sV -p 22,80,443,3389,8080 --open --reason \
-iL targets.txt -oA assets-services
# 第三步:只对确认在线的关键主机做全端口扫描
nmap -sS -p- -T4 --min-rate 500 --open \
192.168.10.10 192.168.10.11 -oA key-hosts-fullport
示例二,用 NSE 的安全脚本做合规检查。使用 safe 与 discovery 类脚本,避免任何侵入性操作,并明确指定脚本分类而不是用 default 全开:
nmap -sS -sV -p 80,443,8080 \
--script "safe and discovery" \
--script-timeout 60s \
--open \
192.168.10.0/24 -oA nmap-safe-check
针对特定服务的合规检测,可以指定具体脚本并限制参数。例如检查 HTTPS 站点的证书信息与常见配置问题:
nmap -p 443 --script ssl-cert,ssl-enum-ciphers \
192.168.10.20 -oA tls-check
示例三,扫描结果的处理与分析。XML 输出便于写脚本做资产比对,下面这段 Python 从 XML 中提取每台主机的开放端口与服务,输出成便于比对的表格式文本:
import xml.etree.ElementTree as ET
tree = ET.parse("assets-services.xml")
for host in tree.getroot().findall("host"):
addr = host.find("address").get("addr")
status = host.find("status").get("state")
if status != "up":
continue
print("主机", addr)
for port in host.findall("./ports/port"):
state = port.find("state")
if state is None or state.get("state") != "open":
continue
svc = port.find("service")
name = svc.get("name") if svc is not None else "unknown"
product = svc.get("product", "") if svc is not None else ""
version = svc.get("version", "") if svc is not None else ""
print(" %s/%s %s %s %s" % (
port.get("portid"), port.get("protocol"), name, product, version))
把两次扫描的 XML 做差集比对,就能得到"新开放了哪些端口"的清单,这是资产变化监控的核心逻辑:
import xml.etree.ElementTree as ET
def load(path):
out = {}
for host in ET.parse(path).getroot().findall("host"):
addr = host.find("address").get("addr")
ports = set()
for port in host.findall("./ports/port"):
st = port.find("state")
if st is not None and st.get("state") == "open":
ports.add(port.get("portid") + "/" + port.get("protocol"))
out[addr] = ports
return out
old = load("assets-services-before.xml")
new = load("assets-services-after.xml")
for addr in sorted(set(old) | set(new)):
added = new.get(addr, set()) - old.get(addr, set())
removed = old.get(addr, set()) - new.get(addr, set())
if added or removed:
print(addr, "新增:", sorted(added), "消失:", sorted(removed))
适用与不适用场景对照。
| 场景 | 是否合适 | 说明 |
|---|---|---|
| 自有网络的资产盘点 | 非常合适 | 最典型的合法用途 |
| 获得书面授权的渗透测试 | 合适 | 需严格遵守范围与时间窗口 |
| 合规审计中的暴露面核查 | 合适 | 建议只使用 safe 与 discovery 类脚本 |
| 内部资产变更监控 | 合适 | 定期扫描加 XML 比对,效果很好 |
| 未授权的任何目标 | 绝对不允许 | 违法,且扫描源容易被溯源 |
| 对生产关键设备做高强度扫描 | 需评估 | 版本探测与脚本可能影响老旧服务 |
| 大网段的全端口扫描 | 需谨慎 | 耗时与带宽消耗大,建议分片分批 |

