Josperdo/scanlyne

GitHub: Josperdo/scanlyne

一款轻量级网络变更检测工具,通过定期 nmap 扫描和快照对比来发现网络中的异常变化,并为每个变更提供安全风险提示。

Stars: 0 | Forks: 0

# Scanlyne 具备安全上下文的网络变更检测工具。Scanlyne 运行 nmap 扫描,存储结果,并展示快照间的变更——附带关于为何该变更值得调查的简明英语说明。 ## 快速开始 ### Docker (推荐) 镜像中已包含 nmap。无需本地依赖。 ``` git clone https://github.com/your-username/scanlyne.git cd scanlyne docker compose up --build ``` 打开 `http://localhost:5000`。数据库和扫描输出存储在命名的 Docker 卷中,并在容器重启后保留。 **认证 (可选):** 未设置时应用为开放状态——仅适用于受信任的 LAN 环境。 ``` SECRET_KEY=mysecret SCANLYNE_USERNAME=admin SCANLYNE_PASSWORD=pass docker compose up ``` 或者直接在 `docker-compose.yml` 中设置它们。 **扫描您的 LAN:** 默认情况下,容器在 Docker 的 bridge 网络上运行。要从 Linux 主机访问 LAN 主机,请在 `docker-compose.yml` 中切换到 host 网络: ``` # 替换 ports: 映射为: network_mode: host ``` 不支持 Docker Desktop for Mac 或 Windows——请改用主机的 IP 范围作为扫描目标。 ### 手动设置 **要求:** Python 3.10+, 已安装 nmap 并在 PATH 中。 ``` git clone https://github.com/your-username/scanlyne.git cd scanlyne python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt flask --app app:create_app run # dev server, auto-reloads ``` 打开 `http://localhost:5000`。数据库和扫描输出目录会在首次运行时自动创建。 用于生产环境(后台调度程序需要单个 worker): ``` gunicorn --workers 1 "app:create_app()" ``` 在部署前通过环境变量设置 `SECRET_KEY`: ``` export SECRET_KEY=$(python -c "import secrets; print(secrets.token_hex(32))") export SCANLYNE_USERNAME=admin export SCANLYNE_PASSWORD=yourpassword ``` ## 填补的空白 大多数网络监控工具要么功能过剩,要么功能不足: - **企业级解决方案** (Nessus, Qualys, SolarWinds) 价格昂贵,操作复杂,专为拥有专职安全人员的团队构建。 - **原始 nmap CLI** 提供了一切信息,却没给出答案。一份 500 行的 XML 转储无法告诉您 NAS 上新开放的端口是配置错误还是预期行为。 Scanlyne 介于两者之间。它面向运行自己基础设施的人群——家庭实验室用户、系统管理员、小团队——他们想要一个简单的答案:**“自上次检查以来我的网络发生了什么变化,我需要关注吗?”** ## 适用人群 - **家庭实验室用户**:跟踪虚拟机、容器和设备上的服务蔓延 - **系统管理员**:验证补丁窗口或配置更改没有留下意外的开放端口 - **安全分析师**:想要轻量级的审计跟踪,而无需搭建完整的 SIEM - **学生**:通过动手操作工具学习网络安全概念 ## 功能概览 1. **运行扫描** —— 通过 Web UI 提交目标(IP, CIDR, 主机名)和可选的 nmap 标志。结果存储在 SQLite 中,原始 XML 保留在磁盘上。 2. **保存基线** —— 在扫描反映出已知良好状态后,将其标记为该目标的基线。这是所有未来扫描的比较参考点。 3. **检测变更** —— 运行另一次扫描,然后打开变更检测 (Change Detection)。Scanlyne 对比两次扫描并展示: - **新主机** —— 网络上出现的设备 - **移除的主机** —— 消失的设备 - **变更的主机** —— IP 相同,但端口或服务不同: - 开放或关闭的端口 - 版本或状态发生改变的服务 4. **结合上下文进行分类** —— 每个变更都包含简短的风险提示。不是定论,只是一个起点: ``` [!] New open port: 3306/tcp — MySQL — database, verify intentional exposure [!] Port 4444/tcp opened — Common reverse shell port [~] Service version changed on 443/tcp — may indicate an upgrade or a substitution [✓] Port 8080/tcp closed — previously open, now gone ``` ## 示例:捕捉意外服务 您在周日为家庭服务器建立了基线。周中您更新了一些软件包。您运行另一次扫描并打开变更检测: ``` Target: 192.168.1.10 Baseline: Scan #3 (2024-11-10 14:32) → Current: Scan #7 (2024-11-13 09:15) Changed hosts └── 192.168.1.10 New ports ┌─────────┬──────────┬───────┬────────────────────────────────────────────────────┐ │ Port │ Protocol │ State │ Risk hint │ ├─────────┼──────────┼───────┼────────────────────────────────────────────────────┤ │ 6379 │ tcp │ open │ Redis — often misconfigured with no auth │ └─────────┴──────────┴───────┴────────────────────────────────────────────────────┘ Service changes ┌──────┬──────────┬─────────────────────┬─────────────────────┬──────────────────┐ │ Port │ Protocol │ Old service │ New service │ Risk hint │ ├──────┼──────────┼─────────────────────┼─────────────────────┼──────────────────┤ │ 443 │ tcp │ Apache httpd 2.4.51 │ Apache httpd 2.4.58 │ Version changed │ └──────┴──────────┴─────────────────────┴─────────────────────┴──────────────────┘ ``` Redis 之前并不存在。软件包更新将其作为依赖项拉入,并且它绑定到了所有接口。值得关注。 变更检测视图会自动显示所有基线对——点击即可查看完整的差异: Scanlyne-change-detection ## 工作流程 ``` Run Scan → mark as baseline → Run Scan → Change Detection → review diff ``` 1. **运行扫描** —— 输入目标和标志(例如 `-sV -T4`)。扫描异步运行;详情页面轮询完成状态。 2. **标记为基线** —— 在扫描详情页面上,将已完成的扫描提升为基线状态。添加可选标签(例如 "pre-patch", "post-change")。每个目标支持多个基线。 3. **运行另一次扫描** —— 相同目标,相同或不同的标志。 4. **变更检测** —— 应用自动显示所有基线与最新扫描的配对。点击即可查看差异。 5. **手动比较** —— 比较任意两个已完成的扫描,而不仅仅是基线对。 6. **计划任务** —— 在 `/schedules` 配置定期扫描。应用会在配置的间隔内在后台触发它们。 ## 架构 ``` scanlyne/ ├── app.py # Flask application factory, auth, scheduler startup ├── config.py # Configuration (SECRET_KEY, DB path, scan output dir) ├── models.py # SQLAlchemy models: Scan, Host, Port, Schedule ├── scanner.py # nmap subprocess execution with input validation ├── parser.py # nmap XML → Python dict ├── diff.py # Scan comparison + risk hint generation ├── blueprints/ │ ├── scan.py # Run scans, manage baselines │ ├── results.py # Scan history and detail views │ ├── compare.py # Change detection — the primary view │ └── schedules.py # Recurring scan schedule CRUD ├── templates/ │ ├── base.html │ ├── scan/ │ ├── results/ │ ├── compare/ │ └── schedules/ └── static/ ├── css/style.css └── js/main.js ``` **数据持久化:** 通过 Flask-SQLAlchemy 使用 SQLite。无需外部数据库。扫描结果位于 `instance/scanner.db`。原始 nmap XML 存储在 `scans/` 中,并在数据库中通过路径引用。 **依赖项:** Flask, Flask-SQLAlchemy, APScheduler, gunicorn。无消息队列,无外部服务。APScheduler 在 Flask 进程内运行以进行计划扫描。 ## 安全设计 Scanlyne 将 nmap 作为子进程执行。采取了几项控制措施以防止滥用: - **目标验证** —— 正则表达式允许列表阻止 Shell 元字符(`; | & $ >` 等) - **标志允许列表** —— 仅允许一组固定的 nmap 标志(不允许 `--script`,不允许 `--lua`) - **无 `shell=True`** —— 子进程始终使用参数列表调用 - **可选的 HTTP Basic Auth** —— 设置 `SCANLYNE_USERNAME` 和 `SCANLYNE_PASSWORD` 环境变量以启用。默认关闭;专为受信任的 LAN 使用设计。切勿在未启用认证且未置于 HTTPS 之后的情况下将其暴露在公共互联网上。 ## 已知限制 - **调度程序需要单个 worker。** 如果您使用多个 worker 运行 gunicorn,每个 worker 都会启动自己的调度程序并触发重复扫描。请使用 `--workers 1`。 - **无 HTTPS。** 如果将其暴露在 localhost 之外,请运行在反向代理(nginx, Caddy)之后。 - **仅支持 SQLite。** 适用于家庭实验室规模;不适合高并发多用户部署。
标签:Docker, Flask, HTTP/HTTPS抓包, IT运维, Nmap, Python, Socks5代理, 占用监测, 变更检测, 基线监控, 安全防御评估, 密码管理, 局域网扫描, 开源安全工具, 异常检测, 快照对比, 态势感知, 插件系统, 数据统计, 无后门, 服务发现, 端口扫描, 网络安全, 虚拟驱动器, 请求拦截, 资产管理, 逆向工具, 逆向工程平台, 防御性安全, 防御绕过, 隐私保护