thousaba/NetScanner

GitHub: thousaba/NetScanner

一款基于 Python 和 Scapy 的轻量级终端局域网扫描工具,通过 ARP 发现、端口扫描、多层指纹识别和被动嗅探,一条命令即可完成局域网设备的全面发现与资产梳理。

Stars: 0 | Forks: 0

# 网络扫描器 一款基于 Python 和 Scapy 构建的轻量级终端局域网发现工具。只需一个命令,即可发现局域网上的设备、识别开放端口、获取服务指纹、通过 TTL 特征推测操作系统,并从 MAC 地址解析出制造商名称。 ## 功能特性 - **基于 ARP 的主机发现** — 可靠的设备检测,可绕过防火墙(在局域网中 ARP 无法被阻止) - **服务探测** — 针对特定端口发送载荷(FTP HELP、Redis INFO、SMTP EHLO 等),以唤醒没有提示就不响应的服务 - **端口扫描与指纹获取** — 默认扫描 26 个常见端口,获取服务指纹(SSH、HTTP、FTP 等) - **多层操作系统指纹识别** — 三阶段检测:指纹关键字分析 → 端口特征匹配 → TTL 回退。端口 445+3389 开放 = Windows,端口 62078 = iPhone 等 - **离线 MAC 厂商查询** — 使用 Wireshark OUI 数据库通过 `manuf` 从 MAC 地址解析设备制造商,无需调用 API - **mDNS 设备发现** — 通过 Bonjour/Zeroconf 广播识别设备,适用于随机化 MAC 地址的设备(如 iPhone) - **三层主机名解析** — mDNS (Apple/Android) → NBNS/NetBIOS (Windows) → 反向 DNS 回退,全部并行解析 - **监控模式** — 持续监控网络,并在设备加入或离开时发出警报 - **混合被动模式 (`--passive`)** — 在每次主动扫描之后,在间隔期间嗅探 ARP、DHCP 和 mDNS 流量——在休眠设备唤醒的瞬间捕获它们,而无需发送任何数据包 - **并行扫描** — 设备和端口并发扫描(最多同时扫描 20 台设备 × 50 个端口) - **自定义端口目标** — 使用 `--ports` 覆盖默认端口列表 - **JSON 输出** — 用于脚本编写和管道操作的机器可读输出 - **ARP 欺骗检测** — 标记不同 IP 间的重复 MAC 地址,这是 ARP 缓存中毒 / MITM 攻击的可靠指标 - **精美的终端 UI** — 通过 `rich` 实现精美的表格、加载动画和彩色输出 ## 安装 ``` # Clone repository git clone https://github.com/thousaba/NetScanner.git cd NetScanner # 创建 virtual environment (推荐) python -m venv venv source venv/bin/activate # Linux/Mac venv\Scripts\activate # Windows # 安装 dependencies pip install -r requirements.txt ``` ## 用法 ### 基本扫描 ``` # Linux/Mac sudo python app.py --subnet 192.168.1.0/24 # Windows (以管理员身份运行 terminal) python app.py --subnet 192.168.1.0/24 ``` ### 输出示例 ``` Network Scan Results (192.168.1.0/24) ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓ ┃ IP Address ┃ MAC Address ┃ Hostname ┃ Vendor ┃ OS ┃ Open Ports & Banner ┃ Status ┃ ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩ │ 192.168.1.1 │ aa:bb:cc:dd:ee:ff │ router.local │ TP-Link │ Windows │ 80 [HTTP/1.1 200 OK..], │ OK │ │ │ │ │ │ │ 443 │ │ │ 192.168.1.42 │ 11:22:33:44:55:66 │ macbook.lan │ Apple Inc. │ Linux/Mac/ │ 22 [SSH-2.0-OpenSSH..], │ OK │ │ │ │ │ │ Mobile │ 8080 │ │ │ 192.168.1.100 │ de:ad:be:ef:00:01 │ - │ Dell │ Windows │ 3389, 445 │ OK │ └───────────────┴───────────────────┴──────────────┴──────────────┴────────────────┴─────────────────────────┴────────────┘ ``` 当检测到 ARP 欺骗时: ``` ⚠ ARP SPOOFING DETECTED! The following MAC addresses appear on multiple IPs: MAC aa:bb:cc:dd:ee:ff → 192.168.1.1, 192.168.1.254 ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓ ┃ IP Address ┃ MAC Address ┃ Hostname ┃ Vendor ┃ OS ┃ Open Ports ┃ Status ┃ ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩ │ 192.168.1.1 │ aa:bb:cc:dd:ee:ff │ router.local │ TP-Link │ Windows │ 80, 443 │ ⚠ ARP SPOOF │ │ 192.168.1.254 │ aa:bb:cc:dd:ee:ff │ - │ TP-Link │ Windows │ 80, 443 │ ⚠ ARP SPOOF │ └───────────────┴───────────────────┴──────────────┴─────────┴─────────┴─────────────┴──────────────┘ ``` ### 所有选项 ``` Usage: app.py [options] Options: -s, --subnet Target subnet to scan (required) e.g. 192.168.1.0/24 -t, --timeout ARP scan timeout in seconds default: 2 -p, --ports Custom port list (comma-separated) e.g. 22,80,443,3306 --json Output results as JSON --watch Continuously monitor the network for new devices --interval Seconds between scans in watch mode default: 30 --passive Hybrid mode: active scan + passive ARP/DHCP/mDNS sniffing between rounds --iface Network interface to sniff on (default: auto-detect via Scapy) ``` ### 监控模式 监控网络并在设备**加入或离开**时发出警报。每次扫描都使用集合算法将当前设备集合与上一次的进行比较——因此,手机切换 WiFi 时,断开和重新连接都会被捕获。 ``` python app.py --subnet 192.168.1.0/24 --watch --interval 15 ``` ``` 👀 WATCH MODE ACTIVE! Scanning 192.168.1.0/24 every 15 seconds... Press CTRL+C to stop. 🚨 ALERT! NEW DEVICE(S) JOINED THE NETWORK! [table with newly detected devices] 👋 DEVICE(S) LEFT THE NETWORK: ab:cd:ef:12:34:56 No new activity detected... (14:32:30) ``` ### 被动混合模式 结合主动扫描与被动嗅探。在每次主动 ARP 扫描之后,工具不会休眠,而是在网络接口上监听整个间隔期间的唤醒信号。能够捕获在主动扫描期间处于休眠状态的设备——在它们产生任何流量的瞬间就会被检测到。 ``` python app.py --subnet 192.168.1.0/24 --watch --passive # Manual interface (在 Windows 上很有用,因为 auto-detect 有时会选错 adapter) python app.py --subnet 192.168.1.0/24 --watch --passive --iface "Wi-Fi" ``` ``` 👀 WATCH MODE ACTIVE! Scanning 192.168.1.0/24 every 20s (active + passive sniffing on Wi-Fi)... 🔍 PASSIVE CAPTURE! Device(s) detected without active scan: IP: 192.168.1.77 MAC: ab:cd:ef:12:34:56 Vendor: Apple Inc. ``` 在被动窗口期间会监听三种信号: | 信号 | 端口/协议 | 触发条件 | |---|---|---| | Gratuitous ARP | Layer 2 | 设备加入或重新声明其 IP | | DHCP Request | UDP 67/68 | 设备唤醒并续订 IP 租约 | | mDNS announcement | UDP 5353 | Apple/Android 设备解锁并广播服务 | BPF 过滤器被精确设置为 `arp or (udp and (port 67 or port 68 or port 5353))`——没有泛洪式的通用 UDP 数据包,只有这三种协议。即使 AP 上启用了**客户端隔离**,这同样有效,因为 DHCP 和 mDNS 是广播/组播的,可以绕过客户端到客户端的过滤。 ### JSON 输出 ``` python app.py --subnet 192.168.1.0/24 --json ``` ``` [ { "ip": "192.168.1.1", "mac": "aa:bb:cc:dd:ee:ff", "hostname": "router.local", "vendor": "TP-Link", "os": "Windows", "open_ports": "80 [HTTP/1.1 200 OK..], 443", "mdns_name": "-", "arp_spoof": false } ] ``` ### 自定义端口 ``` # 仅扫描 database ports python app.py --subnet 10.0.0.0/24 --ports 3306,5432,27017,6379,1433 # 仅扫描 web-related ports python app.py --subnet 10.0.0.0/24 --ports 80,443,8080,8443,3000,5000 ``` ## 默认端口列表 | 端口 | 服务 | |-------|----------------------| | 21 | FTP | | 22 | SSH | | 23 | Telnet | | 25 | SMTP | | 53 | DNS | | 80 | HTTP | | 110 | POP3 | | 143 | IMAP | | 443 | HTTPS | | 445 | SMB | | 1433 | MSSQL | | 2222 | Alt SSH | | 3000 | Dev Server (React) | | 3306 | MySQL | | 3389 | RDP | | 5000 | Dev Server (Flask) | | 5432 | PostgreSQL | | 5900 | VNC | | 6379 | Redis | | 8000 | Dev Server (Django) | | 8080 | HTTP Proxy | | 8443 | HTTPS Alt | | 27017 | MongoDB | | 548 | AFP (macOS file sharing) | | 631 | CUPS (Linux printing) | | 62078 | iOS lockdownd | ## 工作原理 1. **ARP 扫描** — 在子网内广播 ARP 请求。每个响应的设备都会显示其 IP 和 MAC 地址。这比 ICMP ping 更可靠,因为 ARP 工作在二层,无法被软件防火墙阻止。 2. **厂商查询** — 将每个 MAC 地址的前 3 个八位字节与 Wireshark OUI 数据库(通过 `manuf`)进行匹配,以识别设备制造商。完全离线,无需调用 API。 3. **端口扫描 + 操作系统指纹识别** — 所有设备并行进行端口扫描,同时主机名解析在后台并发运行。 4. **主机名解析(三层,并行)** — 端口扫描完成后,NBNS 和 mDNS 查询并发运行: - **mDNS** — 监听 Bonjour/Zeroconf 广播 3 秒。Apple 和 Android 设备通过 `info.server` 显示其主机名(例如 `Ileris-iPhone`)。服务实例名称(例如 `iPhone (2)`)单独显示在“厂商”列中。 - **NBNS** — 并行向每个发现的 IP 发送 NetBIOS 节点状态请求 (UDP 137)。Windows 机器会在约 1 秒内响应其计算机名(例如 `DESKTOP-MJ170VE`)。 - **反向 DNS** — 对于在 mDNS 和 NBNS 之后仍未解析的任何设备,会在线程池中调用 `gethostbyaddr`。在家庭局域网中很少使用,但作为最后的手段保留。 反向 DNS 过去是按设备顺序运行的(每个无响应的主机需要 2-5 秒)。现在这三层全部并行运行,因此最坏情况下的延迟受限于 mDNS 窗口(3 秒),而不是设备的数量。 5. **端口扫描** — 所有发现的设备并行扫描(`ThreadPoolExecutor`,最多同时扫描 20 台设备)。每台设备的端口也并发扫描(最多 50 个线程),从而产生最大约 1000 个并发连接。带有指纹获取的完整 TCP 连接扫描。在超时时间内没有响应的端口被标记为 `[Filtered]`——以区分防火墙的 DROP 和显式 REJECT。 6. **服务探测** — 在读取指纹之前,会向每个端口发送一个符合协议规范的载荷。SSH 和 MySQL 在连接时自我声明;Redis、FTP、SMTP 等在收到探测前保持静默(`INFO`、`HELP`、`EHLO` 等)。 7. **指纹获取** — 读取开放端口返回的前 1024 个字节以识别运行的服务。HTTP 响应会解析 `Server:` 头,而不是状态行。 8. **操作系统指纹识别** — 三层检测,按优先级顺序尝试: - **指纹分析**:扫描服务指纹以查找操作系统关键字(`openssh` → Linux,`IIS` → Windows,`darwin` → macOS 等)。当多个指纹给出冲突信号时,使用投票系统做出决定。 - **端口特征**:特定的开放端口组合对于某些操作系统是独一无二的。`{445, 3389}` → Windows,`{62078}` → iOS,`{548}` → macOS 等。 - **TTL 回退**:在没有指纹或端口线索时,将 ICMP Echo Request 作为最后手段。≤64 → Linux/Mac,≤128 → Windows,≤255 → 网络设备。 - “操作系统”列还会显示产生结果所使用的方法(`via banner`、`via ports`、`via ttl`)。 9. **ARP 欺骗检测** — 收集所有设备后,检查重复的 MAC(同一 MAC 对应多个 IP)和重复的 IP(同一 IP 对应多个 MAC)。两者都会在状态列中被标记。 单次扫描的时间线:ARP 扫描 → 并行端口扫描 → NBNS + mDNS 并发 → 剩余的并行反向 DNS → 表格输出。 ## 技术说明 ### 为什么主机发现使用 ARP 而不是 ICMP ping? 大多数教程使用 ICMP ping (`ping 192.168.1.x`) 来发现设备。问题在于:防火墙可以而且经常阻止 ICMP。开启了防火墙的 Windows 机器不会响应 ping——但它会始终响应 ARP 请求,因为 ARP 工作在二层(数据链路层),完全位于 IP 协议栈之下。没有任何防火墙能在不破坏网络本身的情况下阻止本地网络上的 ARP。这就是为什么在局域网中 ARP 能提供更完整结果的原因。 ### 基于 TTL 的操作系统指纹识别是如何工作的? 每个 IP 数据包都带有一个 TTL (Time To Live) 值——这是一个在每个路由器跳转时递减 1 的整数,用于防止无限循环。操作系统在发送数据包时设置不同的**初始 TTL 值**: | 初始 TTL | 操作系统 | |-------------|---------------------------| | 64 | Linux, macOS, Android/iOS | | 128 | Windows | | 255 | Cisco 路由器,网络设备 | 当 ICMP Echo Reply 到达时,TTL 已经根据目标与我们之间的跳数进行了递减。在局域网中通常是 0-1 跳,因此接收到的 TTL 非常接近初始值。该工具使用 `≤64`、`≤128`、`≤255` 阈值而不是精确匹配,以考虑到这些跳数造成的损耗。 **局限性:** Linux 和 macOS 都使用 TTL 64,因此无法仅通过 TTL 区分它们。现代智能手机也使用 64。这就是为什么该工具将 `Linux/Mac/Mobile` 作为一个组报告,而不是假装比数据所允许的了解得更多。厂商列(来自 MAC OUI 查询)有助于进一步缩小范围——如果厂商是 `Apple Inc.`,则几乎可以肯定是 macOS 或 iOS。 ### 为什么操作系统指纹识别需要三层? 仅靠 TTL 是一个微弱的信号——Linux、macOS 和所有智能手机都使用 TTL 64,使得它们无法区分。该工具现在按优先级顺序使用三层: **第一层 — 指纹分析**最为精确。服务指纹通常包含明确的操作系统标识符:`SSH-2.0-OpenSSH_8.9p1 Ubuntu` 可立即将该主机识别为 Linux Ubuntu。该工具会扫描所有捕获的指纹,查找涵盖 Linux 发行版、Windows IIS、macOS Darwin、网络设备供应商以及 IoT 服务器等约 25 个关键字。当多个指纹给出冲突信号时,投票系统会选出胜出者。 **第二层 — 端口特征**利用了特定端口组合对某些操作系统是独一无二的这一事实。没有其他操作系统默认运行 SMB (445) + RDP (3389)——这种组合就是 Windows。端口 62078 是 iOS 的 `lockdownd` 服务,仅存在于 iPhone 和 iPad 上。特征分为 `strong`(确定性)和 `hint`(可能性),只有在找不到强匹配时,工具才会回退到提示。 **第三层 — TTL 回退**作为没有开放端口或无法识别指纹的主机的最后手段。它开销很小(一个 ICMP 数据包),有时也是唯一可用的信号。 表格中的“操作系统”列还会显示产生结果所使用的方法(`via banner`、`via ports`、`via ttl`),以便您一眼就能判断可信度。 ### 为什么 MAC 厂商查询使用 `manuf` 而不是 API? 此工具的早期版本使用外部 API 来解析 MAC 厂商。问题在于:每发现一台设备都会产生延迟、存在速率限制,并且在离线/隔离环境中会失效。`manuf` 附带了与 Wireshark 相同的 OUI 数据库,因此查询是即时的,并且无需互联网连接即可工作。之前的依赖项 (`mac-vendor-lookup`) 被替换了,因为其围绕异步核心的同步包装器会产生虚假的 `RuntimeWarning coroutine was never awaited` 警告——`manuf` 是完全同步的,没有此类问题。 ### 为什么主机名解析需要三层? `socket.gethostbyaddr()`(反向 DNS / PTR 查询)是显而易见的选择,但它几乎从不在家庭网络中起作用——消费级路由器不会为 DHCP 客户端维护 PTR 记录。该工具首先使用两个更快、更可靠的来源: **第一层 — mDNS** 最适用于 Apple 和 Android 设备。当手机解锁时,它会通过 Bonjour 广播其服务。zeroconf 响应中的 `info.server` 包含实际的主机名(`Ileris-iPhone`),而服务实例名(`iPhone (2)`)则单独保留在“厂商”列中。 **第二层 — NBNS (NetBIOS Name Service)** 覆盖了 Windows 机器。Windows 在 UDP 端口 137 上广播其计算机名,因此一个节点状态请求(单个 UDP 数据包)就能立即获得带有机器名的响应(例如 `DESKTOP-MJ170VE`)。这就是为什么 Windows 主机名在没有任何 DNS 配置的情况下也能可靠显示的原因。 **第三层 — 反向 DNS** 作为最后手段被保留。它在剩余未解析的 IP 上并行执行,因此 30 个无法解析的主机不会增加 60–150 秒的扫描时间。 ### 为什么端口扫描使用 ThreadPoolExecutor 而不是 asyncio? 端口扫描属于 I/O 密集型——瓶颈在于等待 TCP 连接超时,而不是 CPU。线程和异步协程在这里都能很好地工作。选择 `ThreadPoolExecutor` 是因为它能与现有的同步 `socket` 调用自然集成,而无需完全重写为异步代码。每个线程独立地阻塞在 `connect_ex()` 上,因此 50 个端口实际上是并行扫描的。将线程数上限设为 50 是为了避免耗尽 Windows 上的 OS socket 描述符限制(默认为每个进程 512 个)。 ### ARP 欺骗检测是如何工作的? 在正常的网络中,每个 MAC 地址属于一个物理设备,这意味着它映射到一个确切的 IP。ARP 欺骗(又名 ARP 缓存中毒)是一种经典的 MITM 技术,攻击者发送伪造的 ARP 应答以诱骗其他设备将流量路由通过它们。攻击者的机器最终拥有与网关(或其他目标)相同的 MAC,因此两个不同的 IP 指向同一个硬件。 检测逻辑有意保持简单:收集所有 ARP 响应后,构建一个 `{mac → [ip1, ip2, ...]}` 映射,并标记任何出现多次的 MAC。这是一种被动、零噪声的检查——不发送额外的数据包,并且在正常情况下几乎不可能出现误报(真实局域网上的 MAC 冲突需要硬件故障,而不是配置错误)。 **局限性:** 这只能捕获在扫描窗口期间处于活动状态的欺骗。在两次扫描之间完成的打完就跑式欺骗将无法被检测到。监控模式 (`--watch`) 通过重复扫描减少了这个窗口期。 ### 指纹获取:为什么 HTTP 使用 HEAD? 对于大多数端口,工具只需打开一个连接并读取服务首先发送的任何内容(SSH 发送其版本字符串,FTP 发送问候语等)。HTTP 服务器在客户端首先发话之前不会发送任何内容。发送 `HEAD / HTTP/1.0\r\n\r\n` 仅请求响应头——没有正文——这会触发服务器响应其 `Server:` 头(例如 `Apache/2.4.54`、`nginx/1.23.1`),而无需传输任何实际内容。这保持了扫描的快速,并避免了触发请求正文大小限制。 ### 为什么被动嗅探能捕获 ARP 遗漏的休眠设备 主动 ARP 扫描通过广播“谁拥有此 IP?”请求来工作。处于深度休眠且关闭了 WiFi 无线电的设备永远不会收到请求,因此也不会响应——它对扫描是不可见的。 被动嗅探翻转了模型:它不是询问,而是监听。当休眠设备唤醒时——由推送通知、闹钟或用户解锁屏幕触发——它会在下一次主动扫描之前立即生成网络流量: - **DHCP Request**:设备检查其 IP 租约是否仍然有效。这是一个广播数据包,在局域网上始终可见。 - **mDNS announcement**:Apple 和 Android 设备在解锁时向本地网络广播其可用服务 (AirPlay、Cast 等)。 - **Gratuitous ARP**:设备声明其 IP 到 MAC 的映射以更新邻近的 ARP 缓存。 被动窗口取代了主动扫描之间的 `time.sleep()`。结果是:在主动扫描完成 5 秒后唤醒的设备仍会在同一周期中被捕获,而不必等待长达 `--interval` 秒直到下一次轮询。 ### 为什么监控模式使用集合差集而不是已见列表? 早期版本跟踪一个只会不断增长的 `known_macs` 集合。加入、离开然后重新加入的设备只会在第一次加入时触发警报——因为它的 MAC 已经在集合中了。修复方法是跟踪 `previous_macs`(来自上一次扫描的状态,而不是全部历史记录)并进行比较: ``` new_macs = current_macs - previous_macs # appeared this round dropped_macs = previous_macs - current_macs # disappeared this round ``` 这使得监控模式在轮次之间是无状态的——每次扫描只与前一次扫描进行比较,因此在设备上切换 WiFi 会可靠地同时触发“离开”和“加入”警报。 ## 技术栈 - **[Scapy](https://scapy.net/)** — 数据包构造、ARP 扫描、被动嗅探、操作系统指纹识别 - **[Rich](https://github.com/Textualize/rich)** — 终端表格、加载动画和样式化输出 - **[manuf](https://github.com/coolbho3k/manuf)** — 使用 Wireshark 的 OUI 数据库进行离线 MAC 到厂商的解析 - **[zeroconf](https://pypi.org/project/zeroconf/)** — mDNS/Bonjour 设备发现和主机名解析 - **Python stdlib** — `socket` (TCP 扫描、NBNS 查询、反向 DNS)、`concurrent.futures`、`argparse`、`json` ## 免责声明 本工具仅用于**授权的网络审计和教育目的**。请仅扫描您拥有或获得明确许可扫描的网络。未经授权的网络扫描可能会违反当地法律法规。 ## 许可证 MIT License
标签:API安全, ARP扫描, ARP欺骗检测, Banner抓取, JSON输出, MAC地址查厂商, Maven构建, mDNS, NetBIOS, OS指纹识别, Python, Scapy, Snort++, TTL指纹, Zeroconf, 内网资产探测, 实时处理, 局域网扫描, 插件系统, 数据统计, 无后门, 端口扫描, 网络发现, 网络安全, 网络设备发现, 被动扫描, 逆向工具, 隐私保护