imrooting/WatchTower
GitHub: imrooting/WatchTower
WatchTower 是一个将 nmap、nuclei、subfinder 等主流安全工具封装到统一 CLI 的 Python 自动化侦察与 OSINT 框架,支持本地和云端集群两种运行模式。
Stars: 0 | Forks: 0
# 🗼 WatchTower
**自动化侦察与 OSINT 框架**
WatchTower 是一个模块化 Python 框架,将行业标准的安全工具封装到统一的 CLI 中。运行网络扫描、子域名枚举、SSL 分析、密钥发现、CVE 查询等 —— 所有输出均为结构化、带时间戳、自文档化的格式。
## 目录
- [工作原理](#how-it-works)
- [环境要求](#requirements)
- [安装](#installation)
- [使用方法](#usage)
- [模块](#modules)
- [输出结构](#output-structure)
- [添加新模块](#adding-a-new-module)
- [技巧与提示](#tips--tricks)
- [故障排除](#troubleshooting)
## 工作原理
WatchTower 有两种类型的模块:
- **Fleet 模块** —— 使用 [axiom](https://github.com/pry0cc/axiom) 将工作分发到云端实例集群。适用于重量级扫描任务(nmap、nuclei、爬虫等),需要跨多个目标快速运行。需要指定 `-f fleet_name`。
- **独立模块** —— 在本地机器上运行。无需云端。适用于 DNS 侦察、OSINT、请求头抓取等。
两种类型产生相同的结构化输出格式。
## 环境要求
**始终需要:**
- Python 3.10 或更高版本
- `curl` —— 大多数 Linux/macOS 系统预装
- `git` —— 用于克隆某些模块使用的仓库
**独立模块** —— 只安装你实际需要的工具:
| 工具 | 使用模块 | 安装方式 |
|---|---|---|
| `dnsrecon` | `dnsrecon` 模块 | `sudo apt install dnsrecon` |
| `spiderfoot` | `spiderfoot`、`formfinder`、`github` | `pip install spiderfoot` |
| `gitleaks` | `gitleaks` 模块 | [下载二进制文件](https://github.com/gitleaks/gitleaks/releases) |
| `jq` | `spidering` 模块 | `sudo apt install jq` |
| `qsreplace` | `spidering` 模块 | `go install github.com/tomnomnom/qsreplace@latest` |
| `asn` | `asn`、`cve` 模块 | 首次运行时自动安装 |
**Fleet 模块** —— 你需要先设置好 axiom。以下工具运行在你的云端集群节点上,而非本地机器。WatchTower 在运行每个模块时会自动在集群上安装它们:
| 工具 | 使用模块 |
|---|---|
| `nmap` | `nmap` |
| `hakrawler` + `gospider` | `spidering` |
| `httpx` | `spidering`、`subdomains`、`httpx` |
| `assetfinder` + `amass` | `subdomains` |
| `nuclei` | `nuclei` |
| `wafw00f` | `waf` |
| `waybackurls` | `waybackurls` |
| `sslscan` | `sslscan`(在集群上从源码构建,自动) |
| `whatweb` | `whatweb`(在集群上通过 apt 安装,自动) |
| `SecretFinder` | `secretfinder`(在集群上克隆,自动) |
| `ffuf` | `ffuf`(在集群上通过 go 安装,自动) |
## 安装
```
# 1. 克隆仓库
git clone https://github.com/yourorg/watchtower.git
cd watchtower
# 2. 创建 Python 虚拟环境
python3 -m venv venv
# 3. 激活它
source venv/bin/activate # Linux / macOS
# venv\Scripts\activate # Windows
# 4. 安装 Python 依赖
pip install xlsxwriter openpyxl
# 5. 使脚本可执行
chmod +x watchtower.py
```
**然后仅从上面的独立模块需求表中安装你需要的工具。** 无需预先安装所有工具。
**Fleet 模块**,安装并配置 axiom:
```
bash <(curl -fsSL https://raw.githubusercontent.com/pry0cc/axiom/master/interact/axiom-configure)
# 启动一个 fleet(5 个节点)
axiom-fleet spawn myfleet -i 5
# 检查它是否正在运行
axiom-ls
```
## 使用方法
```
python3 watchtower.py -m -i [OPTIONS]
```
| 参数 | 描述 |
|---|---|
| `-m` / `--module` | 要运行的模块 **(必填)** |
| `-i` / `--input` | 输入文件 —— 每行一个域名或 URL **(必填)** |
| `-f` / `--fleet` | Axiom 集群名称(Fleet 模块必填) |
| `-e` / `--extension` | `finddocs` 的文件扩展名(如 `pdf`) |
| `-v` / `--verbose` | 打印每条执行的命令 |
| `--version` | 显示版本信息 |
**示例:**
```
# Fleet 模块(需要 -f)
python3 watchtower.py -m nmap -i targets.txt -f myfleet
python3 watchtower.py -m spidering -i domains.txt -f myfleet
python3 watchtower.py -m nuclei -i urls.txt -f myfleet
python3 watchtower.py -m ffuf -i urls.txt -f myfleet
# 独立模块(不需要 -f)
python3 watchtower.py -m dnsrecon -i domains.txt
python3 watchtower.py -m getheaders -i urls.txt
python3 watchtower.py -m asn -i ips.txt
python3 watchtower.py -m finddocs -i urls.txt -e pdf
# 常用标志
python3 watchtower.py -m httpx -i domains.txt -f myfleet -v # verbose
DEBUG=1 python3 watchtower.py -m sslscan -i domains.txt -f myfleet # full traceback
NO_COLOR=1 python3 watchtower.py -m dnsrecon -i domains.txt # no colour
```
## 模块
### Fleet 模块
| 模块 | 功能 | 关键输出 |
|---|---|---|
| `nmap` | 网络扫描,支持交互式选项(TCP/UDP、端口、速度、脚本) | Excel 文件,包含开放端口、主机摘要、漏洞等工作表 |
| `spidering` | 使用 hakrawler + gospider 爬取目标,用 httpx 探测存活 URL | `Final-URL-List.txt`、`Final-JavaScript-URL-List.txt` |
| `sslscan` | 扫描 SSL/TLS —— 发现弱密码套件、协议状态、证书备用名称 | `ssl-tls-status.txt`、`weak-ciphers.txt`、`domains-from-ssl-cert.txt` |
| `secretfinder` | 在 JavaScript 文件中搜索 API 密钥、令牌、机密信息 | `javascript-secrets.txt` |
| `subdomains` | 通过 assetfinder 和/或 amass 枚举子域名,用 httpx 确认存活 | `live-subdomains.txt`、`subdomains-by-domain.txt`、Excel 报告 |
| `whatweb` | Web 技术指纹识别(CMS、框架、服务器版本) | `whatweb-results.txt` |
| `waf` | 通过 wafw00f 检测目标上的 WAF 防护 | `waf-results.txt` |
| `waybackurls` | 从 Wayback Machine 获取历史 URL | `waybackurls.txt` |
| `httpx` | 探测主机列表,仅返回存活的 HTTP/HTTPS 主机 | `httpx-live-hosts.txt` |
| `nuclei` | 对目标运行 Nuclei 漏洞模板 | `nuclei-findings.txt` |
| `ffuf` | 目录/端点暴力破解,支持交互式字典和模式选择 | Excel(按状态码颜色编码)+ 纯文本 |
### 独立模块
| 模块 | 功能 | 关键输出 |
|---|---|---|
| `dnsrecon` | 完整 DNS 侦察 —— A、MX、NS、TXT、SPF、DMARC 记录 | `dnsrecon-all-records.csv`、`spf-records.csv`、`dmarc-records.csv` |
| `getheaders` | 通过 curl 从 URL 列表获取 HTTP 响应头 | `response-headers.xlsx`、`response-headers.txt` |
| `getbody` | 通过 curl 从 URL 列表获取 HTTP 响应体 | `response-bodies.txt` |
| `spiderfoot` | OSINT 收集 —— 邮箱、姓名、电话号码 | `spiderfoot-osint.txt` |
| `formfinder` | 发现目标站点上的 Web 表单 | `forms-found.txt` |
| `asn` | ASN 查询、IP 段信息、每个目标的地理位置 | `asn-results.xlsx` |
| `cve` | 通过 Shodan 获取目标的 CVE/漏洞数据 | `cve-results.xlsx` |
| `github` | 发现与目标关联的公开 GitHub 仓库 | `github-repos.txt`、`github-repos-for-gitleaks.txt` |
| `finddocs` | 按文件扩展名过滤 URL 列表(pdf、docx、xlsx 等) | `-file-urls.txt`、`-files-by-domain.txt` |
| `gitleaks` | 克隆 GitHub 仓库并扫描泄露的密钥 | 每个仓库的 JSON 报告 + `gitleaks-summary.txt` |
## 输出结构
所有输出都存放在 `watchtower-results/` 中。不会写入到你的工作目录。
```
watchtower-results/
├── MANIFEST.txt ← index of every file produced, with timestamps
├── final/
│ ├── nmap/
│ │ ├── nmap-results-20250516T143022.xlsx
│ │ └── nmap-open-ports-20250516T143022.txt
│ ├── ffuf/
│ │ ├── ffuf-findings-20250516T150012.xlsx
│ │ └── ffuf-findings-20250516T150012.txt
│ └── /...
└── debug/
└── / ← raw tool output and temp files
```
**每个输出文件都是自文档化的。** 纯文本文件顶部有一个头部信息块:
```
# ════════════════════════════════════════════════════════════════
# WatchTower Reconnaissance Report
# ────────────────────────────────────────────────────────────────
# Module : nmap
# Description : 通过 Nmap 进行全面的网络扫描
# Generated : 2025-05-16 14:30:22
# Operator : alice @ kali
# Input File : /home/alice/targets.txt
# Fleet : myfleet
# Targets (3):
# 192.168.1.1
# 192.168.1.2
# 10.0.0.1
# ════════════════════════════════════════════════════════════════
```
Excel 文件的第一个工作表是 **Report Info**,包含相同的信息。
## 添加新模块
添加模块始终需要在 `watchtower.py` 中做 **3 处修改**。其他不需要改动 —— 一旦这 3 项就位,模块会自动出现在 `--help`、Tab 补全和模块列表中。
以下是每部分的作用:
```
MODULE_REGISTRY → tells WatchTower the module exists and what flags it needs
run_() → the actual logic: install tools, run the scan, write outputs
DISPATCH → connects the module name string to the function
```
### 模式 A —— 独立模块
当工具**在你的本地机器上运行**时使用。不需要 axiom。
**1. 添加到 `MODULE_REGISTRY`:**
```
MODULE_REGISTRY: dict[str, dict] = {
# ... existing entries ...
"mymodule": {
"desc": "One-line description shown in --help",
"fleet": False, # standalone — no -f flag needed
"ext": False, # set True only if it needs -e like finddocs
},
}
```
**2. 编写函数:**
```
# ══════════════════════════════════════════════
# mymodule
# ══════════════════════════════════════════════
def run_mymodule(input_file: str, verbose: bool = False) -> None:
MODULE = "mymodule"
require_file(input_file)
fin = final_dir(MODULE) # watchtower-results/final/mymodule/ ← analyst outputs go here
dbg = debug_dir(MODULE) # watchtower-results/debug/mymodule/ ← raw/temp files go here
# Check the tool is installed before trying to use it
if not shutil.which("mytool"):
error("mytool not found. Install with: sudo apt install mytool")
sys.exit(1)
# Run the tool — save raw output into debug/ so it doesn't pollute final/
raw_out = str(dbg / "mytool-raw.txt")
run_cmd(f'mytool -i "{input_file}" -o "{raw_out}"', verbose=verbose)
# Write the final clean output to final/ with a metadata header
out_txt = fin / f"mymodule-results-{_SESSION['timestamp']}.txt"
header = _write_text_header(MODULE, "Description of what this file contains")
content = open(raw_out, encoding="utf-8", errors="replace").read()
with open(out_txt, "w", encoding="utf-8") as f:
f.write(header)
f.write(content)
# Register the file in MANIFEST.txt so it shows up in the session index
write_manifest_entry(MODULE, str(out_txt), "Short description for the manifest")
success(f"mymodule complete → {out_txt}")
```
**3. 添加到 `DISPATCH`:**
```
DISPATCH: dict[str, callable] = {
# ... existing entries ...
"mymodule": lambda a: run_mymodule(a.input, a.verbose),
}
```
**运行:**
```
python3 watchtower.py -m mymodule -i targets.txt
```
### 模式 B —— Fleet 模块(axiom-scan)
当工具**有原生 axiom 模块**且可以通过 `axiom-scan -m ` 分发时使用。这是最常见的 Fleet 模式。
**1. 添加到 `MODULE_REGISTRY`:**
```
"mymodule": {
"desc": "One-line description",
"fleet": True, # fleet required — user must pass -f
"ext": False,
},
```
**2. 编写函数:**
```
def run_mymodule(input_file: str, fleet: str, verbose: bool = False) -> None:
MODULE = "mymodule"
require_file(input_file)
require_fleet(fleet, MODULE) # exits cleanly with a message if -f was not passed
fin = final_dir(MODULE)
dbg = debug_dir(MODULE)
# Install the tool on all fleet nodes before scanning.
# The if ! command -v check makes this safe to run every time —
# it skips silently if the tool is already installed.
info(f"Ensuring mytool is on fleet '{fleet}' …")
run_cmd(
"axiom-exec '"
"if ! command -v mytool &>/dev/null; then "
" echo \"[fleet] installing mytool …\" && "
" go install github.com/example/mytool@latest; " # ← your install command
"else "
" echo \"[fleet] mytool already present\"; "
"fi'",
verbose=verbose,
)
# axiom-scan splits your input file across fleet nodes and runs the tool in parallel
raw_out = str(dbg / "mytool-raw.txt")
axiom_scan(input_file, fleet, "mytool-axiom-flag", raw_out, verbose=verbose)
# ↑
# this is the -m flag used by axiom-scan
# check axiom's module list for the exact name
# Write the final output
out_txt = fin / f"mymodule-results-{_SESSION['timestamp']}.txt"
header = _write_text_header(MODULE, "Description of what this file contains")
content = open(raw_out, encoding="utf-8", errors="replace").read() \
if os.path.isfile(raw_out) else ""
with open(out_txt, "w", encoding="utf-8") as f:
f.write(header)
f.write(content)
write_manifest_entry(MODULE, str(out_txt), "mytool findings")
success(f"mymodule complete → {fin}/")
```
**3. 添加到 `DISPATCH`:**
```
"mymodule": lambda a: run_mymodule(a.input, a.fleet, a.verbose),
```
**运行:**
```
python3 watchtower.py -m mymodule -i targets.txt -f myfleet
```
### 模式 C —— Fleet 模块(axiom-exec)
当工具**没有原生 axiom 模块**时使用。你需要构建一个 shell 脚本,推送到集群节点,远程运行,然后拉回结果。`ffuf` 模块使用此模式。
**2. 编写函数**(步骤 1 和 3 与模式 B 相同):
```
def run_mymodule(input_file: str, fleet: str, verbose: bool = False) -> None:
MODULE = "mymodule"
require_file(input_file)
require_fleet(fleet, MODULE)
fin = final_dir(MODULE)
dbg = debug_dir(MODULE)
# Install on fleet nodes (same idempotent pattern as Pattern B)
run_cmd(
"axiom-exec 'if ! command -v mytool &>/dev/null; then "
"; fi'",
verbose=verbose,
)
# Build a shell script that runs the tool against each target
tmp_script = dbg / "run-mytool.sh"
raw_out = dbg / "raw-results"
raw_out.mkdir(parents=True, exist_ok=True)
with open(tmp_script, "w") as sh:
sh.write("#!/usr/bin/env bash\nset -euo pipefail\n\n")
for target in read_lines(input_file):
safe = re.sub(r"[^\w._-]", "", target)[:100]
sh.write(f"mytool -target '{target}' -o ~/recon/mytool-{safe}.json\n")
# Push script → run it on fleet → pull results back locally
run_cmd("axiom-exec 'mkdir -p ~/recon'", verbose=verbose)
run_cmd(f'axiom-scp "{tmp_script}" "~/recon/run-mytool.sh"', verbose=verbose)
run_cmd("axiom-exec 'bash ~/recon/run-mytool.sh'", verbose=verbose)
run_cmd(f'axiom-scp "~/recon/mytool-*.json" "{raw_out}/"', verbose=verbose)
# Parse raw_out/*.json and write final outputs
# ... your parsing logic here ...
success(f"mymodule complete → {fin}/")
```
### 辅助脚本
如果你的模块需要辅助 Python 脚本来解析或合并结果,将其放在 `modules/` 目录中,像这样调用:
```
run_module_script("my-helper.py", arg1, arg2)
```
无论 WatchTower 从哪里运行,它都会被自动找到。
### 快速参考
| 模式 | 使用场景 | 注册表中的 `fleet` | 函数签名 |
|---|---|---|---|
| A —— 独立模块 | 工具在本地运行 | `False` | `(input_file, verbose)` |
| B —— axiom-scan | 工具有原生 axiom 模块 | `True` | `(input_file, fleet, verbose)` |
| C —— axiom-exec | 工具没有 axiom 模块 | `True` | `(input_file, fleet, verbose)` |
## 项目结构
```
watchtower/
├── watchtower.py ← Main script — edit this to add modules
├── requirements.txt ← Python package list (xlsxwriter, openpyxl)
├── README.md
└── modules/ ← Helper scripts — do NOT move or rename these
├── capture-headers.py
├── capture-osint.py
├── clone-repos.py
├── convert-nmap-to-xml.py
├── dnsrecon-merge.py
├── parse_domains_subdomains.py
└── pretty_parse_ssl_alt_names.py
```
## 技巧与提示
- **只安装你需要的工具。** 如果你只使用 `dnsrecon` 和 `getheaders`,只需安装 `dnsrecon`。如果缺少必需的工具,WatchTower 会清晰地报错。
- **Tab 补全** —— 在 `-m` 后按 `Tab` 键循环切换模块名称。
- **输入文件格式** —— 每行一个域名或 URL。运行前删除空行和注释。
- **详细模式**(`-v`)在运行每条 shell 命令前打印出来 —— 有助于了解正在发生的事情。
- **调试模式**(`DEBUG=1`)在意外错误时打印完整的 Python 回溯信息。
- **无颜色模式**(`NO_COLOR=1`)去除所有颜色 —— 适用于记录到文件或 CI 流水线。
- **运行后检查 MANIFEST.txt** —— 它列出了所有生成的文件及其时间戳和描述,涵盖所有会话。
- **调试文件夹**(`watchtower-results/debug//`)包含工具的原始输出,如果你需要检查工具实际返回了什么。
## 故障排除
| 问题 | 解决方案 |
|---|---|
| `Module helper 'X' not found` | 检查 `modules/` 目录是否完好且与 `watchtower.py` 在同一位置 |
| `axiom-scan: command not found` | 安装并配置 axiom,或改用独立模块 |
| `dnsrecon: command not found` | `sudo apt install dnsrecon` |
| `gitleaks: command not found` | 从 [gitleaks releases](https://github.com/gitleaks/gitleaks/releases) 下载 |
| `jq: command not found` | `sudo apt install jq` |
| 输出文件为空 | 使用 `-v` 运行以查看具体命令和任何错误 |
| `Permission denied` | `chmod +x watchtower.py` |
| Python 版本错误 | 升级到 Python 3.10+:使用 `python3 --version` 检查 |
| venv 未激活 | 运行 WatchTower 前先执行 `source venv/bin/activate` |
## 许可证
MIT —— 自由使用,欢迎贡献。
标签:ASN查询, axiom, CISA项目, CVE查询, dnsrecon, DNS侦察, ESC4, GitHub, GitHub信息收集, gitleaks, Go工具链, IP 地址批量处理, LIDS, nuclei, OSINT, Python框架, spiderfoot, Spidering, SSL分析, timestamped输出, TIP, 云存储安全, 云扫描集群, 后渗透, 威胁情报, 子域名枚举, 安全工具集成, 开发者工具, 持续安全扫描, 插件系统, 数据统计, 无线安全, 模块化扫描, 端口扫描, 系统安全, 结构化输出, 网络安全, 网络安全审计, 网络扫描, 自动化侦察, 表单发现, 运行时操纵, 防御绕过, 隐私保护