
masscanとnmapをラップするPythonラッパーで、内部または外部ネットワーク全体にわたる大規模なポート探索、ホスト探索、バナー取得、NSEベースの脆弱性スキャンを実現します。
このスクリプトは 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.py を実行する代わりに、任意のディレクトリから spoonmap として呼び出せる。PyPI パッケージは存在しない — このプロジェクトは pypi.org に公開されたことがなく、上記のコマンドは代わりに git リポジトリから直接インストールする。上記の完全な git+https://... 形式を使用し、裸の uv tool install spoonmap は使わないこと。PyPI 上でその名前が現在または将来何を指すとしても、それはこのプロジェクトではない。
最新のコミットに更新するには:
uv tool upgrade spoonmap
この方法でインストールしても、SpooNMAP が自己完結型のスキャナになるわけではありません:
masscan と nmap は依然として個別にインストールする必要がある別個のシステムツールです
(上記の「依存関係」を参照)。チェックアウトから実行する場合とまったく同じです —
uv tool install がパッケージ化するのは SpooNMAP 自身の Python コードと
同梱の NSE スクリプトのみであり、外部で呼び出すバイナリは含まれません。
この方法でインストールする前に理解しておく価値があることの一つ: インストールされた
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 に前回のスキャンの出力が検出されると、ツールは 3 つの選択肢を提示します: [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 に対して実行されていました — 古いバグが単にフラグを無視するだけでなく、スコープを黙って変更してしまった唯一のケースです。
プロンプトなしで中断されたスキャンを再開するには、--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 のバナー/スクリプト結果は常に再開されます(既存の 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