带报告生成功能的漏洞评估扫描器
一个自动化的漏洞评估平台,编排 86 个开源安全工具,聚合和去重发现结果,运行可选的 OpenAI 兼容 LLM 分析层 用于分诊、聚类和修复,生成 概念验证(PoC)脚本,并产生专业的 Markdown、HTML 和 JSON 报告 —— 全部在单个 BlackArch Linux Docker 镜像中完成。
config.toml / env vars / CLI args ↓ AppConfig (pydantic, 3-layer merge: TOML < env < CLI) ↓ Plugin loader — auto-discovers ./plugins/ + ~/.vuln-scanner/plugins/ ↓ ScanOrchestrator • classify_target() → TargetType • tool.applies_to(target) — skips mismatched pairs • asyncio + ThreadPoolExecutor — parallel (tool × target) tasks • AuthConfig forwarded to every applicable tool ↓ ScanResult[] → Assessment ↓ LLMAnalyzer (optional) • Pass 1: triage + PoC design (threaded, per result) • Pass 2: PoC generation (PocGenerator, host-safe) • Pass 3: mitigation (evidence-informed) • Pass 4: clustering + exec summary ↓ PocRunner (container-only, VS_IN_CONTAINER=1 guard) ↓ ┌────────┬────────┬────────┐ │ .md │ .html │ .json │ (all formats written in parallel) └────────┴────────┴────────┘ ↓ DefectDojo (optional)
所有扫描工具和 PoC 执行都在 **BlackArch Linux** Docker 容器内运行 — 不会在宿主机上安装任何东西。
---
## 工具
按类别组织的 86 个工具。每个工具声明其支持的目标类型;编排器会自动跳过不兼容的组合。
### 网络与端口扫描
| Tool | Notes |
|------|-------|
| `nmap` | 带服务/版本检测的完整端口扫描 |
| `rustscan` | 快速端口扫描器,结果馈送给 nmap |
| `masscan` | 高速 TCP/UDP 扫描器 |
| `naabu` | 带服务检测的端口扫描器 |
| `netdiscover` | 基于 ARP 的主机发现 |
### Web 应用
| Tool | Notes |
|------|-------|
| `nuclei` | 基于模板的漏洞扫描器 |
| `nikto` | Web 服务器错误配置扫描器 |
| `wapiti` | 黑盒 Web 漏洞扫描器 |
| `ffuf` | 快速 Web 模糊测试器(目录、参数、请求头) |
| `feroxbuster` | 支持递归的内容发现 |
| `gobuster` | URI/DNS/vhost 暴力破解器 |
| `wfuzz` | Web 应用模糊测试器 |
| `dalfox` | 带参数分析的 XSS 扫描器 |
| `xsstrike` | 高级 XSS 检测引擎 |
| `commix` | 命令注入利用工具 |
| `sqlmap` | 自动化 SQL 注入与接管 |
| `nosqlmap` | NoSQL 注入扫描器 |
| `httpx` | HTTP 探测与指纹识别 |
| `whatweb` | Web 技术指纹识别器 |
| `wafw00f` | WAF 检测与指纹识别 |
| `wpscan` | WordPress 漏洞扫描器 |
| `acunetix` | Web 漏洞扫描器(基于 API) |
| `arachni` | Web 应用安全扫描器 |
| `zap` | OWASP ZAP DAST 扫描器 |
| `wapiti` | 黑盒漏洞扫描器 |
| `drheader` | HTTP 安全响应头分析器 |
| `humble` | HTTP 响应头安全检查器 |
| `hakrawler` | 快速 Web 爬虫,用于 URL 和端点收集 |
| `katana` | 下一代 Web 爬取框架 |
| `gau` | 已知 URL 收集器(AlienVault、WaybackMachine) |
| `jsluice` | JavaScript 密钥与 URL 提取器 |
| `corscanner` | CORS 错误配置扫描器 |
| `crlfuzz` | CRLF 注入扫描器 |
| `smuggler` | HTTP 请求走私检测器 |
| `linkfinder` | 在 JavaScript/HTML 源码中发现端点 |
| `cariddi` | 带密钥与端点检测的 Web 爬虫 |
### API 与 GraphQL
| Tool | Notes |
|------|-------|
| `kiterunner` | 使用 kite 文件进行 API 路由发现 |
| `graphql_cop` | GraphQL 安全审计器 |
| `restler` | 有状态 REST API 模糊测试器 |
| `apifuzzer` | 基于 OpenAPI/Swagger 的模糊测试器 |
| `cherrybomb` | OpenAPI 规范安全 linter |
| `arjun` | HTTP 参数发现 |
| `paramspider` | 从 wayback/来源挖掘参数 |
### DNS 与侦察
| Tool | Notes |
|------|-------|
| `amass` | 子域名枚举(被动 + 主动) |
| `subfinder` | 快速被动子域名枚举 |
| `dnsx` | DNS 解析与探测工具包 |
| `dnsrecon` | DNS 枚举与区域传输 |
| `fierce` | DNS 侦察与主机发现 |
| `theharvester` | OSINT:邮箱、姓名、主机、子域名 |
| `puredns` | 带通配符过滤的快速子域名暴力破解器 |
| `alterx` | 子域名置换引擎 |
| `waybackurls` | 从 Wayback Machine 收集历史 URL |
| `httprobe` | 存活 HTTP/HTTPS 主机探测工具 |
### TLS / SSL
| Tool | Notes |
|------|-------|
| `testssl` | TLS 配置与密码套件审计 |
| `sslyze` | TLS 扫描器(密码套件、Heartbleed、ROBOT) |
| `sslscan` | SSL/TLS 服务扫描器 |
| `tlsx` | 快速 TLS 探测 |
| `tls_attacker` | TLS 协议攻击工具 |
| `ssh_audit` | SSH 配置与算法审计器 |
### SMB 与网络服务
| Tool | Notes |
|------|-------|
| `smbmap` | SMB 共享枚举与权限检查 |
| `enum4linux` | SMB/NetBIOS 枚举 |
| `crackmapexec` | Active Directory 与 SMB 评估 |
| `openvas` | OpenVAS 漏洞扫描器 |
### SAST 与代码分析
| Tool | Notes |
|------|-------|
| `bandit` | Python SAST — 常见安全反模式 |
| `semgrep` | 多语言 SAST,附带社区规则 |
| `gosec` | Go 安全检查器 |
| `bearer` | 数据流 SAST,带有隐私与安全规则 |
| `horusec` | 多语言 SAST 引擎 |
| `brakeman` | Ruby on Rails SAST 扫描器 |
| `flawfinder` | C/C++ 常见缺陷静态分析 |
| `dependency_check` | OWASP 依赖漏洞扫描器 |
| `pip_audit` | Python 包漏洞检查器 |
### 软件组成分析(SCA)
| Tool | Notes |
|------|-------|
| `osv-scanner` | 开源漏洞数据库扫描器 |
| `npm-audit` | Node.js 包漏洞审计 |
| `govulncheck` | Go 模块漏洞检查器 |
### 密钥检测
| Tool | Notes |
|------|-------|
| `gitleaks` | Git 历史密钥扫描器 |
| `trufflehog` | 基于熵的深度密钥查找器 |
| `secretfinder` | 在 JS 文件与端点中查找密钥 |
| `detect-secrets` | 基于基线的密钥扫描器 |
| `noseyparker` | 带模式规则的高速密钥扫描器 |
### IaC 与配置
| Tool | Notes |
|------|-------|
| `checkov` | Terraform/K8s/Dockerfile IaC 扫描器 |
| `tfsec` | Terraform 静态分析 |
| `terrascan` | 多云 IaC 安全扫描器 |
| `hadolint` | Dockerfile 最佳实践 linter |
### 云基础设施
| Tool | Notes |
|------|-------|
| `prowler` | AWS/GCP/Azure 安全态势评估 |
| `kube-bench` | CIS Kubernetes 基准检查器 |
### 容器与供应链
| Tool | Notes |
|------|-------|
| `trivy` | 容器镜像 + 文件系统漏洞扫描器 |
| `grype` | 容器与包漏洞匹配器 |
---
## 目标类型门控
编排器将每个目标分类为一个或多个类型,并且只运行声明支持该类型的工具。这消除了干扰信息,例如针对 Web URL 运行 SMB 工具。
| Type | Example | Tools that match |
|------|---------|-----------------|
| `HOST` | `example.com` | DNS、SSL、Web、SMB 工具 |
| `IP` | `10.0.0.1` | 网络、端口、SMB 工具 |
| `CIDR` | `10.0.0.0/24` | 网络扫描器 |
| `URL` | `https://app.example.com` | Web、API、SSL 工具 |
| `PATH` | `/src/myapp` | SAST、SCA、密钥、IaC 工具 |
| `REPO` | `https://github.com/org/repo` | 密钥、SAST、SCA 工具 |
| `IMAGE` | `myapp:latest` | 容器扫描器 |
| `CLOUD` | `aws:profile=prod`、`arn:aws:…` | 云态势工具(prowler、kube-bench、terrascan) |
分类是自动的 — 只需传入目标字符串;扫描器会自动判断类型。
已识别的云目标格式:
- AWS ARN:`arn:aws:iam::123456789012:root`
- 命名配置文件简写:`aws:profile=production`
- GCP 项目:`projects/my-project-id`
- Azure 订阅 UUID:`00000000-0000-0000-0000-000000000000`
---
## 扫描模式
| Mode | Description |
|------|-------------|
| `paranoid` | 最大隐蔽性 — 被动探测,最小化足迹 |
| `passive` | 无主动攻击 — 仅枚举和横幅抓取 **(默认)** |
| `active` | 启用标准漏洞检查 |
| `aggressive` | 完整扫描:所有模板、暴力破解、快速时序 |
---
## 认证扫描
凭据会转发给所有适用的 Web 工具(nuclei、ffuf、feroxbuster、gobuster、nikto、sqlmap、dalfox、wpscan、wapiti、katana、hakrawler、arjun、wfuzz、corscanner、kiterunner、httpx)。
### 全局凭据
应用于每个目标,除非存在针对特定目标的覆盖配置。
**通过配置文件:**```toml
[scan.auth]
bearer_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
username = "admin"
password = "secret"
[scan.auth.cookies]
session = "abc123"
[scan.auth.headers]
X-API-Key = "my-api-key"
通过环境变量(仅限全局):```bash VS_AUTH_BEARER_TOKEN=eyJ... VS_AUTH_USERNAME=admin VS_AUTH_PASSWORD=secret
**通过 CLI** (仅全局):```bash
vuln-scanner --targets https://app.example.com \
--auth-bearer eyJ... \
--auth-cookie session=abc123 \
--auth-header X-API-Key=secret
当扫描需要不同凭据的多个目标时,可在 [scan.auth.targets."<target>"] 下定义按目标的覆盖配置。匹配的条目会完全替换该目标的全局配置——不进行合并。按目标的认证仅支持配置文件方式(环境变量和 CLI 标志只能设置全局默认值)。```toml
[scan.auth]
bearer_token = "default-token"
[scan.auth.targets."https://app.example.com"] bearer_token = "app-specific-jwt"
[scan.auth.targets."https://admin.example.com"] [scan.auth.targets."https://admin.example.com".cookies] session = "s%3Aabc123" csrftoken = "xyz789"
[scan.auth.targets."10.0.0.50"] username = "apiuser" password = "s3cret"
[scan.auth.targets."https://legacy.example.com"] login_url = "https://legacy.example.com/login" username = "admin" password = "password123" [scan.auth.targets."https://legacy.example.com".login_data] _token = "csrf-value-here"
**优先级:** `per-target config > global config`
---
## LLM 分析
存在 API 密钥时,LLM 层会自动激活。它对扫描结果执行四轮处理:
| 轮次 | 名称 | 功能说明 |
|------|------|-------------|
| 1 | **分类** | 为每个发现分配 CWE、置信度、误报标记、可利用性摘要,并设计相应的 PoC |
| 2 | **PoC 生成** | 编写自包含的 Python/Bash 脚本,利用容器中已有的工具确认该发现 |
| 3 | **缓解措施** | 生成具体的短期缓解措施和永久修复方案,可选择参考 PoC 证据 |
| 4 | **聚类** | 按根本原因对发现进行分组,编写共享修复方案,并生成执行摘要 |
### 提供商配置
LLM 客户端兼容 OpenAI API——支持 OpenAI、Azure OpenAI、Ollama、vLLM、LM Studio、OpenRouter 以及任何其他兼容端点。```toml
[llm]
enabled = "auto" # "auto" | true | false (auto = on when api_key present)
api_key = "" # or set OPENAI_API_KEY env var
base_url = "" # leave empty for OpenAI; set for Ollama/vLLM/etc.
model = "gpt-4o" # REQUIRED when LLM is active — no default
# Sampling parameters (all OpenAI-compatible)
temperature = 0.2
top_p = 0.95
max_tokens = 4096
# top_k and other non-standard params go in extra_body:
# [llm.extra_body]
# top_k = 40
Ollama 示例:```toml [llm] base_url = "http://localhost:11434/v1" api_key = "ollama" model = "llama3.2"
**vLLM 示例:**```toml
[llm]
base_url = "http://localhost:8000/v1"
api_key = "token-abc123"
model = "meta-llama/Meta-Llama-3-8B-Instruct"
每个 LLM 能力都是一个命名功能,可在全局切换,也可按工具或按类别覆盖。
全局功能配置:```toml [llm.features] generate_poc = true execute_poc = false # enable only inside Docker
[llm.features.tool.bandit] generate_poc = false
[llm.features.category.web] logs_analysis = false
**功能优先级:** `tool override > category override > global`
### 自定义提示词
所有 LLM 提示词均可覆盖:```toml
[llm.prompts]
enrich_system = "You are a senior penetration tester..."
mitigation_user = "Write remediation steps for: {title}..."
# Available placeholders: {title} {severity} {description} {cwe}
# {exploitability} {tool} {target} {cves} {raw_output}
[llm] include_tools = [] # empty = all tools exclude_tools = ["hakrawler", "gau"] include_categories = [] exclude_categories = ["dns"]
## PoC 生成与执行
### 生成(始终对主机安全)
LLM 为每个发现编写自包含的 Python 和/或 Bash 脚本。脚本使用 BlackArch 镜像中已有的工具(`curl`、`sqlmap`、`nuclei`、`dalfox` 等),并写入 `<report>_assets/poc/`。生成过程绝不执行代码——它只写入文件。```toml
[llm.poc]
languages = ["python", "bash"]
only_severities = ["critical", "high", "medium"]
max_pocs = 20
allow_git_clone = false # permit cloning official exploit PoCs from GitHub
PoC 执行受两道独立守卫控制:
[llm.features] 中的 execute_poc = trueVS_IN_CONTAINER=1 环境变量(已内置到 Docker 镜像中)如果缺少任一守卫,运行器都会静默拒绝,因此它无法在主机上执行。静态黑名单会在执行前拒绝包含破坏性模式(rm -rf /、mkfs.、fork 炸弹等)的脚本。```bash
VS_LLM_FEATURE_EXECUTE_POC=true docker compose ... run --rm scanner ...
---
## 插件系统
将定义了一个或多个 `AbstractTool` 子类的 `.py` 文件放入 `./plugins/`(或 `~/.vuln-scanner/plugins/`),它们会在启动时被自动发现——无需修改代码。
**发现顺序**(后面的条目会在名称冲突时覆盖前面的):
1. `./plugins/`(相对于 CWD)
2. `~/.vuln-scanner/plugins/`
3. 通过 `[plugins] dirs` 或 `--plugin-dir` 配置的额外目录
**示例插件**(`plugins/my_scanner.py`):```python
from vuln_scanner.tools.abstract import AbstractTool
from vuln_scanner.tools.enums import Severity, ScanStatus, TargetType
from vuln_scanner.tools.models import Finding, ScanInput, ScanResult
class MyScannerTool(AbstractTool):
name: str = "my-scanner"
category: str = "web"
# Only runs against URL targets — skipped automatically for IPs, paths, etc.
applicable_targets: frozenset[TargetType] = frozenset({TargetType.URL})
def build_command(self, target: str, scan_input: ScanInput) -> list[str]:
return ["my-scanner", "--target", target, "--json"]
def parse_output(self, raw: str, target: str) -> list[Finding]:
...
配置:```toml [plugins] enabled = true dirs = ["/opt/company-scanners"]
**CLI:**```bash
vuln-scanner --plugin-dir /opt/company-scanners --targets https://app.example.com
插件工具是全局注册的,但编排器的类型门控控制每个插件实际会针对哪些目标运行。声明 applicable_targets = frozenset({TargetType.URL}) 的插件绝不会对 IP 或文件系统路径触发。
若要在类型门控之外进一步将插件限制到特定目标字符串(例如,仅针对已知的预发布主机运行),请在 run() 内返回 ScanStatus.SKIPPED:```python
def run(self, target: str, scan_input: ScanInput) -> ScanResult:
if "staging" not in target:
return ScanResult(tool=self.name, target=target, status=ScanStatus.SKIPPED)
return super().run(target, scan_input)
没有配置级别的按目标插件过滤器 — 该逻辑属于插件本身。
---
## 报告格式
三种格式并行生成。选择任意组合:```toml
[report]
formats = ["markdown", "html", "json"]
output_dir = "./reports"
或通过命令行:--formats markdown html json
.md)遵循行业渗透测试规范的专业结构化报告:
多个工具针对同一目标报告相同问题时,发现会被去重,合并为单条记录,并显示所有贡献工具。
.html)自包含的单文件报告(无外部依赖),具有:
.json)Assessment 模型的完整结构化导出 — 发现、LLM 增强信息、聚类、统计、PoC 记录。适用于 CI/CD 流水线导入及下游工具链。
poc.sh 脚本通过一条命令即可启动 DefectDojo、三个易受攻击的目标以及扫描器。
先决条件: docker、docker compose 插件、curl、`python3````bash
./poc.sh
| 步骤 | 操作 |
|------|--------|
| 1 | 检查先决条件 |
| 2 | 加载 `.env`(如果缺失,从 `.env.example` 复制) |
| 3 | 启动 DefectDojo 堆栈 |
| 4 | 等待 DefectDojo API 就绪 |
| 5 | 通过管理员凭据获取 API 令牌 |
| 6 | 启动易受攻击的目标容器 |
| 7 | 等待每个目标可访问 |
| 8 | 构建扫描器 Docker 镜像 |
| 9 | 运行扫描器,生成报告,推送到 DefectDojo |
| 10 | 打印包含 URL 和拆除说明的摘要 |
**使用 LLM 分析:**```bash
# Copy the example env and add your key
cp .env.example .env
# Edit .env: set OPENAI_API_KEY and VS_LLM_MODEL
./poc.sh
覆盖扫描模式:```bash SCAN_MODE=active ./poc.sh
**拆解:**```bash
docker compose down -v
docker compose -f docker-compose.target.yaml down -v
poc.sh 启动)| 应用 | URL | 描述 |
|---|---|---|
| OWASP Juice Shop | http://localhost:3000 | 涵盖 OWASP Top 10 的现代 Node.js 应用 |
由 pentest-ground.com 维护的公开可用、故意易受攻击的系统。无需设置——直接扫描即可验证工具和 PoC 生成。
## scanner.sh — Docker 封装脚本
`scanner.sh` 是日常运行扫描器的推荐界面。它封装了 `docker compose run`,这样你无需手动输入 compose 调用命令——直接传入目标和标志即可。```bash
./scanner.sh [OPTIONS] [-- SCANNER_ARGS...]
-- 之后的所有内容将原样转发给扫描器入口点,绕过所有包装器逻辑。
./scanner.sh
./scanner.sh -t https://app.example.com 192.168.1.0/24 -m active
./scanner.sh -c /path/to/prod.toml
./scanner.sh -t https://app.example.com --llm-model gpt-4o
./scanner.sh -t https://app.example.com --include-tools nuclei,dalfox,ffuf
./scanner.sh --build -t https://app.example.com -m active
./scanner.sh -- --targets https://t.example.com --mode aggressive --formats markdown html json
./scanner.sh --shell ./scanner.sh --build --shell
### 自动完成的操作
- 加载 `.env`(如果缺失则从 `.env.example` 复制)
- 如果不存在配置,则将 `config.example.toml` 复制为 `config.toml`
- 如果不存在,则创建 `vuln_scanner_network` Docker 网络
- 将自定义 `--config` 文件挂载到容器中的 `/app/config.toml`
- 传入 `--build` 时重新构建镜像
---
## 配置
复制带注释的模板:```bash
cp config.example.toml config.toml
完整参考:```toml [scan] targets = ["192.168.1.1", "https://app.example.com", "/src/myapp"] mode = "passive" # paranoid | passive | active | aggressive timeout = 300 # per-tool timeout in seconds rate_limit = null # requests/sec; null = no limit
[scan.auth] bearer_token = "" # Authorization: Bearer username = "" # HTTP Basic username password = "" # HTTP Basic password login_url = "" # Form-based login URL
[tools] exclude = ["nikto"] # skip specific tools by name
[categories] include = ["web", "ssl"] # limit to these categories; empty = all
[plugins] enabled = true
[report] formats = ["markdown", "html", "json"] output_dir = "./reports"
[defectdojo] url = "http://localhost:8080" api_key = "" product_name = "My Product" engagement_name = "Automated Scan"
[llm] enabled = "auto" # "auto" | true | false api_key = "" # or OPENAI_API_KEY env var base_url = "" # leave empty for OpenAI model = "" # required when active, e.g. "gpt-4o" or "llama3.2" temperature = 0.2 top_p = 0.95 max_tokens = 4096
exclude_tools = [] exclude_categories = []
[llm.features] logs_analysis = true enrich = true classify = true cluster = true mitigation = true generate_poc = true execute_poc = false # container-only; set VS_LLM_FEATURE_EXECUTE_POC=true false_positive_filter = true
[llm.features.tool.bandit] generate_poc = false
[llm.features.category.dns] logs_analysis = false
[llm.poc] languages = ["python", "bash"] only_severities = ["critical", "high", "medium"] max_pocs = 20 allow_git_clone = false
**配置合并优先级:** `CLI > env vars > config.toml > defaults`
---
## 环境变量
### 核心
| 变量 | CLI 标志 | 描述 |
|----------|----------|-------------|
| `VS_TARGETS` | `--targets` | 以空格分隔的目标列表 |
| `VS_MODE` | `--mode` | 扫描模式 |
| `VS_TIMEOUT` | `--timeout` | 每工具超时(秒) |
| `VS_RATE_LIMIT` | `--rate-limit` | 速率限制(请求/秒) |
| `VS_MAX_CONCURRENT` | `--max-concurrent` | 并行工具槽位 |
| `VS_INCLUDE_TOOLS` | `--include-tools` | 按名称将工具加入白名单 |
| `VS_EXCLUDE_TOOLS` | `--exclude-tools` | 按名称将工具加入黑名单 |
| `VS_INCLUDE_CATEGORIES` | `--include-categories` | 将类别加入白名单 |
| `VS_EXCLUDE_CATEGORIES` | `--exclude-categories` | 将类别加入黑名单 |
| `VS_OUTPUT_DIR` | `--output-dir` | 报告输出目录 |
### 报告
| 变量 | CLI 标志 | 描述 |
|----------|----------|-------------|
| `VS_FORMATS` | `--formats` | 报告格式:`markdown html json` |
### LLM
| 变量 | CLI 标志 | 描述 |
|----------|----------|-------------|
| `OPENAI_API_KEY` | — | API 密钥(标准环境变量,用作回退) |
| `OPENAI_BASE_URL` | — | 基础 URL 回退(用于非 OpenAI 端点) |
| `VS_LLM_ENABLED` | `--no-llm` | `auto` \| `true` \| `false` |
| `VS_LLM_MODEL` | `--llm-model` | 模型名称(启用时必需) |
| `VS_LLM_TEMPERATURE` | — | 采样温度 |
| `VS_LLM_MAX_TOKENS` | — | 最大输出令牌数 |
| `VS_LLM_FEATURE_<NAME>` | `--llm-feature NAME=on` | 全局功能开关,例如 `VS_LLM_FEATURE_GENERATE_POC=false` |
| `VS_LLM_FEATURE_EXECUTE_POC` | `--llm-poc-execute` | 启用 PoC 执行(仅容器) |
### 认证扫描
| 变量 | CLI 标志 | 描述 |
|----------|----------|-------------|
| `VS_AUTH_BEARER_TOKEN` | `--auth-bearer` | Bearer 令牌(`Authorization: Bearer …`) |
| `VS_AUTH_USERNAME` | `--auth-user` | HTTP Basic 用户名 |
| `VS_AUTH_PASSWORD` | `--auth-pass` | HTTP Basic 密码 |
| `VS_AUTH_LOGIN_URL` | `--auth-login-url` | 基于表单的登录 URL |
Cookie 和额外标头必须通过配置文件或 `--auth-cookie` / `--auth-header` CLI 标志设置。
### 插件
| 变量 | CLI 标志 | 描述 |
|----------|----------|-------------|
| `VS_PLUGINS_ENABLED` | `--no-plugins` | 启用/禁用插件自动发现 |
| `VS_PLUGINS_DIRS` | `--plugin-dir` | 额外的插件目录(以空格分隔) |
### DefectDojo
| 变量 | CLI 标志 | 描述 |
|----------|----------|-------------|
| `VS_DEFECTDOJO_URL` | `--defectdojo-url` | DefectDojo 基础 URL |
| `VS_DEFECTDOJO_API_KEY` | `--defectdojo-api-key` | API 令牌 |
| `VS_DEFECTDOJO_PRODUCT` | — | 产品名称 |
| `VS_DEFECTDOJO_ENGAGEMENT` | — | Engagement 名称 |
---
## 项目结构```
vuln_scanner/
├── config/
│ ├── models.py # AppConfig, AppLLMConfig, PluginsConfig (pydantic)
│ └── loader.py # 3-layer merge: TOML + env (VS_*) + CLI
│
├── tools/
│ ├── enums.py # Severity, Confidence, ScanStatus, ScanMode, TargetType
│ ├── models.py # Finding, ScanInput, ScanResult, AuthConfig (pydantic)
│ ├── target.py # classify_target() — maps target string to TargetType set
│ ├── abstract.py # AbstractTool ABC + subprocess execution helpers
│ ├── __init__.py # TOOL_REGISTRY (86 tools)
│ └── <tool>.py # One file per tool (86 total)
│
├── llm/
│ ├── models.py # LLMConfig, LLMFeatures, PocConfig (pydantic)
│ ├── features.py # resolve_features() — tool > category > global merge
│ ├── client.py # LLMClient — thin openai SDK wrapper
│ ├── analyzer.py # LLMAnalyzer — 4-pass analysis pipeline
│ └── prompts.py # Default prompt templates (all overridable)
│
├── poc/
│ ├── models.py # Poc, PocVerdict
│ ├── generator.py # PocGenerator — writes scripts, never executes (host-safe)
│ └── runner.py # PocRunner — executes scripts (VS_IN_CONTAINER guard)
│
├── reports/
│ ├── base.py # AbstractReporter
│ ├── markdown.py # Professional structured Markdown report
│ ├── html.py # Self-contained HTML with light/dark theme
│ └── json_reporter.py # Full Assessment JSON dump
│
├── defectdojo/
│ └── client.py # DefectDojoClient — push findings via REST API
│
├── plugins.py # Plugin auto-discovery (./plugins/, ~/.vuln-scanner/plugins/)
├── model.py # Assessment, Cluster, AssessmentStats
└── orchestrator.py # ScanOrchestrator — type-gated, async concurrent execution
plugins/ # Drop .py plugin files here (auto-discovered at startup)
main.py # Entry point
config.example.toml # Fully documented configuration template
.env.example # Environment variable reference
Dockerfile # BlackArch-based image; bakes VS_IN_CONTAINER=1
docker-compose.yaml # DefectDojo stack
docker-compose.scanner.yaml # Scanner service
docker-compose.target.yaml # Vulnerable test targets (Juice Shop, WebGoat)
scanner.sh # Convenience wrapper — runs the scanner via docker compose
poc.sh # End-to-end quick-start script (DefectDojo + targets + scanner)
对于一次性或私有工具,请使用插件系统——将 .py 文件放入 ./plugins/ 目录即可,无需更改代码。对于应随项目一起发布的工具:
vuln_scanner/tools/mytool.py:```python
from vuln_scanner.tools.abstract import AbstractTool
from vuln_scanner.tools.enums import Severity, TargetType
from vuln_scanner.tools.models import Finding, ScanInputclass MyTool(AbstractTool): name: str = "mytool" category: str = "web" # Declare which target types this tool supports. # The orchestrator skips mismatched (tool, target) pairs automatically. applicable_targets: frozenset[TargetType] = frozenset({TargetType.URL, TargetType.HOST})
def build_command(self, target: str, scan_input: ScanInput) -> list[str]:
return ["mytool", "--target", target]
def parse_output(self, raw: str, target: str) -> list[Finding]:
findings = []
for line in raw.splitlines():
if "VULN" in line:
findings.append(Finding(
title="Example finding",
severity=Severity.HIGH,
description=line,
tool=self.name,
target=target,
))
return findings
2. 在 `vuln_scanner/tools/__init__.py` 中注册它:```python
from vuln_scanner.tools.mytool import MyTool
TOOL_REGISTRY: dict[str, type[AbstractTool]] = {
...
"mytool": MyTool,
}
Dockerfile:```dockerfile
RUN pacman -Sy --noconfirm mytool**提示:**
- 对于写入文件而非标准输出的工具,请在 `build_command()` 中使用 `OUTPUT_FILE_SENTINEL`,并重写 `run()` 以调用 `self._run_with_tempfile()`。
- 具有 `applicable_targets = frozenset(TargetType)`(默认值)的工具会针对所有目标类型运行 — 仅对真正通用的工具使用此设置。
- 未找到二进制文件 → `ScanStatus.SKIPPED`(从报告中隐藏)。工具错误 → `ScanStatus.FAILED`(显示在附录 A 中)。
---
## 开发```bash
# Install with dev dependencies
uv sync
# Run tests (host-safe only — no real tool execution)
uv run pytest tests/ -v
# Lint
uv run ruff check .
uv run ruff format .
测试类别:
tests/test_config.py — 配置合并与验证tests/test_target_typing.py — classify_target() 与 applies_to()tests/test_orchestrator_gating.py — 使用模拟工具进行类型门控tests/test_llm.py — LLM 功能、模拟客户端、PoC 运行器容器保护tests/test_reports.py — 全部三种报告器(Markdown、HTML、JSON)tests/test_nmap.py — nmap 输出解析器安全规则: 绝不在主机上运行真实的扫描工具。所有工具执行均在 Docker 容器内针对隔离的目标容器进行。PocRunner 强制实施此规则——它会先检查 VS_IN_CONTAINER=1 然后才执行任何 PoC 脚本,而 Docker 镜像已内置该变量。
当配置了 api_key 和 product_name 时,发现结果会自动推送。
获取你的 API 密钥:
admin / admin)手动推送:```bash
VS_DEFECTDOJO_API_KEY=your-key
VS_DEFECTDOJO_PRODUCT="My App"
uv run vuln-scanner --targets 192.168.1.1
| 功能 | 默认值 | 描述 |
|---|
logs_analysis | 开 | 将工具的原始输出提供给 LLM |
enrich | 开 | CWE / 置信度 / 误报 / 可利用性分类 |
classify | 开 | 对发现类型和风险进行分类 |
cluster | 开 | 按根本原因对发现进行分组 |
mitigation | 开 | 生成缓解和修复方案 |
generate_poc | 开 | 将 PoC 脚本编写为报告资产 |
execute_poc | 关 | 在容器内运行 PoC (需要 VS_IN_CONTAINER=1) |
false_positive_filter | 开 | 从报告中抑制可能的误报 |
| http://localhost:8888/WebGoat |
| Java/Spring 故意不安全的应用程序 |
| 系统 | URL | 类型 | 漏洞类型 |
|---|
| DVWA | https://pentest-ground.com:4280 | 经典 Web 应用 | CSRF, XSS, SQLi |
| DVGQL | https://pentest-ground.com:5013 | GraphQL API | CMDi, XSS, SQLi |
| RestFlaw | https://pentest-ground.com:9000 | REST API | SQLi, Code Injection, XXE |
| GuardianLeaks | https://pentest-ground.com:81 | Web 应用 | XSS, SSRF, Code Injection |
| vuln-scanner --targets \ | |||
| https://pentest-ground.com:4280 \ | |||
| https://pentest-ground.com:5013 \ | |||
| https://pentest-ground.com:9000 \ | |||
| https://pentest-ground.com:81 \ | |||
| --mode active |
| 标志 | 描述 |
|---|
-t, --targets HOST... | 一个或多个扫描目标(URL、IP、CIDR、路径、镜像) |
-m, --mode MODE | 扫描模式:passive | active | aggressive | paranoid |
-c, --config FILE | 要挂载的配置文件(默认:./config.toml) |
-f, --formats FMT | 报告格式,逗号分隔:markdown,html,json;可重复 |
--no-llm | 禁用 LLM 增强 |
--llm-model MODEL | LLM 模型覆盖(例如 gpt-4o、claude-sonnet-4-5) |
--llm-min-severity SEV | 启用 LLM 的最低严重级别:info|low|medium|high|critical |
--include-tools TOOLS | 要运行的工具列表,逗号分隔 |
--exclude-tools TOOLS | 要跳过的工具列表,逗号分隔 |
-e, --env KEY=VALUE | 向容器传递额外的环境变量 |
-b, --build | 运行前重新构建 Docker 镜像 |
-n, --no-defectdojo | 跳过 DefectDojo 集成 |
--shell | 在容器内打开交互式 shell,而不是进行扫描 |
-h, --help | 显示帮助 |