用于大规模端口发现、主机发现、横幅抓取以及跨内部或外部网络的基于NSE的漏洞扫描的masscan和nmap的Python封装。
此脚本是 masscan 和 nmap 的封装。nmap 负责主机发现以及(对于较小规模的扫描)端口发现、服务横幅抓取和 NSE 脚本。Masscan 用于大规模端口发现,此时原始速度至关重要。请从你常用的包管理器或从源码安装两者。
需要 Python 3.8+(pyproject.toml 中的 requires-python;CI 最低为 3.8)。
SpooNMAP 可以直接从代码检出目录运行——无需安装步骤,参见 下文“用法”——也可以使用 uv 安装为独立命令:
uv tool install git+https://github.com/trustedsec/spoonmap
这会将一个 spoonmap 可执行文件放到你的 PATH 中,因此你可以在任意目录下直接调用 spoonmap,而无需克隆仓库并运行 ./spoonmap.py。不存在 PyPI 包——本项目从未发布到 pypi.org,上面的命令是直接从 git 仓库安装的。请使用上面的完整 git+https://... 形式,而不是裸的 uv tool install spoonmap;无论该名称在 PyPI 上解析到什么(现在或将来),都不是本项目。
要更新到最新提交:
uv tool upgrade spoonmap
以这种方式安装并不会让 SpooNMAP 成为自包含的扫描器:masscan 和 nmap 仍然是独立的系统工具,必须单独安装(参见上文“依赖项”),与从代码检出目录运行时完全一样——uv tool install 只会打包 SpooNMAP 自身的 Python 代码及其捆绑的 NSE 脚本,而不会打包它通过 shell 调用的外部二进制文件。
以这种方式安装前,有一点值得理解:已安装的 spoonmap 的 Python 模块位于 uv 放置其托管工具环境的任意位置——而不是你会想到去查找配置文件或扫描输出的目录。这正是下文“文件存放位置”一节所讨论的场景——请阅读该节,了解哪些路径会相对于当前目录解析以及原因;通过 uv tool install 安装并不会改变这条规则,只是让这条规则变得重要,因为不再有代码检出目录可供配置或输出路径习惯性地回退。
直接执行脚本即可,它会提示你输入所有必需的选项。
config.json、目标/排除文件以及扫描输出都会相对于你运行命令时所在的目录解析——如果你的输出不在预期位置,请参阅下文“文件存放位置”,尤其是当你习惯从 SpooNMAP 自身目录之外通过路径调用它时。
如果你使用 uv,则无需单独创建虚拟环境即可运行:
uv run spoonmap.py
如果脚本可执行,也可以直接调用:
# ./spoonmap.py
________ _____ _______ _________________
__ ___/______________________ | / /__ |/ /__ |__ __ \
_____ \___ __ \ __ \ __ \_ |/ /__ /|_/ /__ /| |_ /_/ /
____/ /__ /_/ / /_/ / /_/ / /| / _ / / / _ ___ | ____/
/____/ _ .___/\____/\____//_/ |_/ /_/ /_/ /_/ |_/_/
/_/
Service Categories (comma-separated numbers, default: All)
(1) Web [80, 443, 7001, 7002, 8000, 8080, 8081, 8443, 8888, 9090, 10443]
(2) Database [1433, U:1434, 1521, 3306, 5432, 6379, 9200, 27017]
(3) Remote Management [22, 23, 3389, 5900, 5901, 6129, 1723, 5985, 5986]
(4) Email [25, 110, 143, 465, 587, 993, 995]
(5) LDAP [389, 636]
(6) Network Infrastructure [53, 179, U:500, U:161, U:623, U:631, U:1194, 1194]
(7) File Transfer [21, 111]
(8) SMB [445, 135, 139, U:137]
(9) Specialized [1090, 3300, 4786, 6970, 2375, 4243, 9100, 8530, 8531]
(10) Containers & Debuggers [2377, 10250, 8001, 9229, 2345, 5005, 61616, 8009, 6000]
(11) Local LLM [11434, 1234, 7860, 5000, 5001, 1337, 3000, 8000, 8080]
(12) Full Port Scan [1-65535, TCP only — no UDP]
(c) Custom Port Scan [enter your own comma-separated ports]
(The Full Port Scan number increments automatically with the number of categories.)
**Full Port Scan is TCP only.** It sweeps TCP 1-65535 and runs no UDP discovery at
all, so every `U:` port listed in the categories above — SNMP (U:161), IKE (U:500),
IPMI (U:623), IPP (U:631), OpenVPN (U:1194), NetBIOS (U:137), SQL Browser (U:1434) —
is skipped, along with the NSE scripts and findings that depend on them. It is
*wider* than All on TCP and *narrower* on UDP. For both, run All and Full as two
passes, or use the Custom option with the UDP ports appended
(e.g. `1-65535,U:161,U:500,U:623`).
Which categories would you like to scan (e.g. 1,3 — default: All)?
Would you like to enumerate service banners for any identified services (default: Yes)?
Would you like to run NSE security scripts on identified services (default: No)?
Target Scan
(1) External
(2) Internal
Is this an internal or external scan (default: External)?
How fast would you like to scan (default: 20000 packets/second)?
Please enter the full path for the file containing target hosts (default: /opt/spoonmap/ranges.txt):
Would you like to exclude any hosts? (default: No)
Run host discovery before port scanning (default: Yes)?
Tune advanced settings (nmap threads, masscan batch size, nmap work-unit threshold)? (default: No)
你也可以创建一个 config.json 文件(基于 config.json.sample)来跳过所有提示:
{
"scan_categories": ["Web", "Database", "Remote Management"],
"banner_scan": "True",
"script_scan": "False",
"host_discovery": "True",
"target_scan": "Internal",
"max_rate": "2000",
"target_file": "ranges.txt",
"output_path": "./",
"exclusions_file": "exclusions.txt",
"nmap_threads": 5,
"masscan_batch_size": 5,
"nmap_threshold": 5000000
}
要扫描所有类别,请设置 "scan_categories": "All"。
要扫描全部 65535 个 TCP 端口,请设置 "scan_categories": "Full"——请注意这仅限 TCP,不执行任何 UDP 发现。
如需完全自定义端口列表,请省略 scan_categories,改用 "dest_ports": ["80","443","U:53"]。
UDP 端口使用 U: 前缀指定(例如 "U:53")。
当你回答交互式提示时,所选选项会在扫描开始前写入 config.json。生成的文件会像 config.json.sample 一样记录每个可编辑字段,并带有一个 __generated_by_prompts__ 标记键。这意味着被中断的交互式扫描可以像配置驱动的扫描一样恢复——只需使用 --resume 重新运行,所有提示都会被跳过。
如果在 output_path 中检测到先前扫描的输出,工具会提供三个选项:[d]elete(删除先前的输出并重新开始)、[a]ppend(保留先前的输出但重新运行所有阶段),或 [r]esume(保留先前的输出并跳过已完成的工作,与 --resume 标志的行为完全一致)。
在重新运行时更改选项。 选择 [d]elete 或 [a]ppend 会重新询问每个选项,并将已保存的 config.json 值预填为默认值——因此一路按 Enter 即可复现先前的扫描,你也可以只更改你关心的端口、速率或目标。[r]esume 会跳过提示,因为它是在继续同一次扫描。重新提示仅适用于工具生成的 config.json(即带有 __generated_by_prompts__ 的那个);你手写的配置会保持上述严格跳过所有提示的行为。删除该键即可退出此行为,或完全删除 config.json 以从头开始。
重新回答提示会重写 config.json,并且是合并而非覆盖:你手动添加到文件中的任何键都会被保留。
要在不编辑目标文件的情况下扫描单个地址(或简短列表),请使用 --target:
./spoonmap.py --target 10.0.0.5
./spoonmap.py --target 10.0.0.0/24
./spoonmap.py --target 10.0.0.5,10.0.1.0/24,10.0.2.1-10.0.2.9
该值接受目标文件行所接受的任何内容——裸 IP、CIDR、A-B 范围或 address netmask——以逗号分隔。它在扫描开始前进行验证:格式错误或 IPv6 地址会以非零退出码中止,并指出有问题的条目,而不是在空目标集上顺利运行。
--target 优先于 config.json 的 target_file 和交互式提示,因此它也能在原本完全非交互的运行中工作。地址会写入 output_path 中的 cli_targets.txt;ranges.txt 永远不会被修改,因此你的参与范围文件保持完整,并且磁盘上会记录每次运行实际针对的目标。
--target=10.0.0.5(标志和值之间用 =)现在也能工作,与 --target 10.0.0.5 相同——--cleanup=/path/to/output 也是如此。在此工具迁移到 argparse 之前,--flag=value 形式无法匹配任何手写的 '--flag' in sys.argv 检查,因此 --target=10.0.0.5 会被完全静默忽略,扫描会针对 ranges.txt 运行,而不是你实际请求的地址——这是旧 bug 唯一没有仅仅忽略标志、而是静默改变了范围的情况。
要在没有任何提示的情况下恢复中断的扫描,请使用 --resume 标志:
./spoonmap.py --resume
# or
uv run spoonmap.py --resume
--resume 会复用已完成的 主机发现 和 端口发现 结果(其输出比 resolved_targets.txt 更新),加载已有的存活主机列表,并从上次中断处继续。由于 resolved_targets.txt 仅在解析后的目标集合实际发生变化时才会被重写,因此在 ranges.txt 未变的情况下恢复运行会完全跳过发现阶段(不重新扫描)。如果自上次运行以来 ranges.txt 发生了变化,resolved_targets.txt 会以更新的时间戳被重写,任何现在早于它的发现输出——主机和端口——都会被自动重新运行,以确保新增的网段不会被遗漏。nmap banner/脚本结果始终会被复用(已存在的 nmap_results/portN.xml 文件会被无条件跳过)。恢复运行也可以通过 config.json 中的 "resume": "True" 启用。
要以非交互方式删除扫描数据,请使用 --cleanup 标志:
# Path taken from output_path in config.json
./spoonmap.py --cleanup
# or
uv run spoonmap.py --cleanup
# Or specify the directory explicitly
./spoonmap.py --cleanup /path/to/output
要打印已安装的版本:
spoonmap --version
# -v and -V are accepted as short forms of --version and behave identically
spoonmap -v
spoonmap -V