GOLEMWORKS/port_scanner

GitHub: GOLEMWORKS/port_scanner

一款支持 SYN 隐蔽扫描、服务版本探测与 banner 抓取的高性能多线程端口扫描工具,并提供 C 共享库与 JSON 导出能力。

Stars: 0 | Forks: 0

# 端口扫描器 v2.0 (MVP) 一款支持 SYN scan、version detection、banner grabbing 以及导出为 JSON 的渗透测试工具。 ## 功能特性 - **TCP Connect Scan** — 通过 connect() 进行标准扫描 - **SYN Scan** — 通过 raw sockets 进行隐蔽扫描(需要 root/CAP_NET_RAW 权限) - **Version Detection** — 识别服务版本(SSH、FTP、SMTP、HTTP、Memcached 等) - **Banner Grabbing** — 抓取服务 banner - **SSL/TLS Detection** — 自动识别 SSL 端口 - **JSON Export** — 将结果导出为 JSON(无外部依赖) - **Graceful Degradation** — 如果 SYN 不可用,自动回退到 connect scan - **Multi-threaded** — 高性能多线程扫描 ## 编译 ### 用于 C API 的 Shared library: ``` g++ -std=c++17 -shared -fPIC -o libport_scanner.so port_scanner.cpp -pthread ``` ### CLI 版本: ``` g++ -std=c++17 -o port_scanner_cli port_scanner_cli.cpp -L. -lport_scanner -pthread ``` ### 使用 main.cpp (standalone): ``` g++ -std=c++17 -o port_scanner main.cpp -pthread ``` ## CLI 使用方法 ``` ./port_scanner_cli [опции] ``` ### 主要选项 - `-h, --host ` — 要扫描的主机(默认:localhost)。可指定多次 - `-f, --file ` — 包含主机列表的文件(每行一个主机) - `-s, --start ` — 起始端口(默认:1) - `-e, --end ` — 结束端口(默认:1024) - `-t, --timeout ` — 超时时间,单位为毫秒(默认:1000) - `-T, --threads ` — 线程数(默认:10) - `-r, --range ` — 端口范围(-s 和 -e 的替代方案) ### 新选项 (v2.0) - `--syn` — 使用 SYN scan 代替 connect scan(需要 root) - `--version-detect` — 启用服务版本检测 - `--banner-grab` — 启用 banner 抓取 - `--json ` — 将扫描结果导出到 JSON 文件 - `--all-scans` — 启用所有功能(SYN + version + banner) ### 预设方案 ``` # 快速扫描 (connect scan, 前 100 个端口) ./port_scanner_cli --start 1 --end 100 # Stealth 扫描 (SYN scan, 前 1024 个端口) ./port_scanner_cli --syn --start 1 --end 1024 # 包含所有检查的完整扫描 ./port_scanner_cli --all-scans --host 192.168.1.1 ``` ### SYN Scan SYN scan(也称为“半开扫描”)是一种比完整 TCP 连接更高效、更隐蔽的扫描方法。 **工作原理:** 1. 发送 TCP SYN 数据包(连接请求) 2. 如果端口开放 — 目标服务器回复 SYN+ACK,扫描器发送 RST 并断开连接,不完成 3 次握手 3. 如果端口关闭 — 服务器回复 RST 4. 如果被防火墙过滤 — 超时 **SYN scan 的优势:** - **隐蔽性**:不完成 TCP 连接,在日志中更难被发现 - **速度**:无需等待连接完全建立 - **效率**:可以在单位时间内扫描更多端口 **要求:** - **root** 权限或 Capability `CAP_NET_RAW` (Linux) - 在 macOS 上 raw sockets 的工作方式不同 — 会自动回退到 connect scan **用法:** ``` # 基本 SYN scan (需要 sudo) sudo ./port_scanner_cli --syn --host 192.168.1.1 --range 1-1024 # 带服务版本检测的 SYN scan sudo ./port_scanner_cli --syn --version-detect --host example.com --range 1-1024 # 带所有检查的 SYN scan (version + banner grabbing) sudo ./port_scanner_cli --syn --all-scans --host target.com --range 1-65535 # 带结果导出的 SYN scan sudo ./port_scanner_cli --syn --version-detect --banner-grab --json report.json --host target.com ``` **回退到 Connect Scan:** 如果进程没有权限使用 raw sockets,程序会自动切换到 connect scan 并输出警告: ``` [WARN] Raw sockets unavailable (need root/CAP_NET_RAW). Falling back to connect scan for target.com ``` ### 示例 基础扫描: ``` ./port_scanner_cli ./port_scanner_cli --host 192.168.1.1 --host 192.168.1.2 ./port_scanner_cli --file hosts.txt ``` 带版本检测的 SYN scan: ``` sudo ./port_scanner_cli --syn --version-detect --host example.com ``` 完整扫描并导出为 JSON: ``` sudo ./port_scanner_cli --all-scans --json report.json --host 192.168.1.1 --range 1-1024 ``` ## 工作原理 ### TCP Connect Scan 1. 程序创建一个 TCP socket 并尝试与目标端口建立完整连接 2. 如果成功 — 端口开放;如果失败 — 端口关闭或不可达 ### SYN Scan ( 隐蔽 ) 1. 创建 raw socket 以在 IP 层发送数据包 2. 发送带有随机 source port 的 TCP SYN 数据包 3. 响应情况: - **SYN+ACK** → 端口开放,发送 RST 断开连接(隐蔽) - **RST** → 端口关闭 - **ICMP error** → 端口不可达/filtered 4. **Graceful Degradation**:如果 raw sockets 不可用(无 root 权限),自动切换到 connect scan ### Version Detection 对每个开放端口发送 protocol-specific probe: - **SSH** (22):发送 "SSH-2.0-PortScanner",解析响应 - **FTP** (21):FEAT 命令 (RFC 2389) - **HTTP** (80):HEAD 请求,解析 Server header - **SMTP** (25):EHLO 命令 - **Memcached** (11211):"version" 命令 - 结果按 key (host:port) 缓存 ### Banner Grabbing 1. 连接到开放端口 2. 等待 500ms 获取自动发送的 banner 3. 返回 banner 的第一行(最多 1024 字节) ### 导出为 JSON - 手动序列化,无外部依赖 - 包含 scan_info、hosts(包含端口、版本、banner)以及 summary - 对字符串中的特殊字符进行转义 ## 技术细节 - **SYN Scan**:raw sockets (IPPROTO_TCP),手动构建 TCP header,RFC 793 checksum - **Connect Scan**:使用 SO_RCVTIMEO/SO_SNDTIMEO 的标准 socket()+connect() - **DNS Resolution**:配合 AF_INET 使用 getaddrinfo() - **Thread Safety**:使用 mutex 处理队列、结果和输出;使用 atomic 处理进度 - **Cross-platform**:兼容 macOS(针对 raw sockets 提供 SO_CONNECT_TIME 回退) ## 在 Flutter 中使用 可以通过 FFI 调用 C API,从而在 Flutter 应用中使用端口扫描器。 ### 为 macOS 编译 shared library ``` g++ -std=c++17 -shared -fPIC -o libport_scanner.dylib port_scanner.cpp -pthread ``` ### 为 Android 编译 shared library Android 需要 NDK。以下是为各种架构编译的示例: **arm64-v8a:** ``` $NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android21-clang++ \ -std=c++17 -shared -fPIC \ -o libport_scanner_arm64-v8a.so \ port_scanner.cpp \ -pthread ``` **armeabi-v7a:** ``` $NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang++ \ -std=c++17 -shared -fPIC \ -o libport_scanner_armeabi-v7a.so \ port_scanner.cpp \ -pthread ``` 建议配置 CMakeLists.txt 以便自动为所有目标架构进行编译。 ### Dart API (通过 FFI) ``` import 'dart:ffi'; import 'dart:io'; import 'package:ffi/ffi.dart'; final DynamicLibrary _lib = Platform.isAndroid ? DynamicLibrary.open('libport_scanner.so') : DynamicLibrary.open('libport_scanner.dylib'); typedef ScannerCreateFn = Pointer Function( Pointer> hosts, Int32 hostsCount, Int32 startPort, Int32 endPort, Int32 timeoutMs, Int32 maxThreads); typedef ScannerCreate = Pointer Function( Pointer> hosts, Int32 hostsCount, Int32 startPort, Int32 endPort, Int32 timeoutMs, Int32 maxThreads); typedef ScannerDestroyFn = Void Function(Pointer scanner); typedef ScannerDestroy = Void Function(Pointer scanner); typedef ScannerScanFn = Void Function(Pointer scanner); typedef ScannerScan = Void Function(Pointer scanner); typedef ScannerGetResultCountFn = Int32 Function(Pointer scanner); typedef ScannerGetResultCount = Int32 Function(Pointer scanner); typedef ScannerGetResultFn = PortResult Function(Pointer scanner, Int32 index); typedef ScannerGetResult = PortResult Function(Pointer scanner, Int32 index); typedef ScannerGetHostStatusFn = HostStatus Function(Pointer scanner, Int32 index); typedef ScannerGetHostStatus = HostStatus Function(Pointer scanner, Int32 index); final scannerCreate = _lib.lookupFunction('scanner_create'); final scannerDestroy = _lib.lookupFunction('scanner_destroy'); final scannerScan = _lib.lookupFunction('scanner_scan'); final scannerGetResultCount = _lib.lookupFunction('scanner_get_result_count'); final scannerGetResult = _lib.lookupFunction('scanner_get_result'); final scannerGetHostStatus = _lib.lookupFunction('scanner_get_host_status'); @ ffi struct class HostStatus extends ffi.Struct { external int value; } @ffi.struct class PortResult extends ffi.Struct { external Pointer host; external int port; external int is_open; external Pointer service; } Future>> scanPorts({ required List hosts, int startPort = 1, int endPort = 1024, int timeoutMs = 1000, int maxThreads = 10, }) async { final hostArray = hosts.map((h) => h.toNativeUtf8()).toList(); final hostPtr = allocate>(count: hosts.length); for (int i = 0; i < hosts.length; i++) { hostPtr[i] = hostArray[i]; } final scanner = scannerCreate( hostPtr, hosts.length.toInt(), startPort.toInt(), endPort.toInt(), timeoutMs.toInt(), maxThreads.toInt(), ); if (scanner == nullptr) { for (final h in hostArray) { free(h); } free(hostPtr); throw Exception('Failed to create scanner'); } scannerScan(scanner); final results = >[]; final resultCount = scannerGetResultCount(scanner); for (int i = 0; i < resultCount; i++) { final result = scannerGetResult(scanner, i); results.add({ 'host': result.host.toDartString(), 'port': result.port, 'is_open': result.is_open == 1, 'service': result.service.toDartString(), }); free(result.host); free(result.service); } final hostStatusCount = hosts.length; final hostStatuses = {}; for (int i = 0; i < hostStatusCount; i++) { final status = scannerGetHostStatus(scanner, i); final statusStr = status.value == 0 ? 'ONLINE' : status.value == 1 ? 'NO_PORTS' : 'OFFLINE'; hostStatuses[hosts[i]] = statusStr; } scannerDestroy(scanner); for (final h in hostArray) { free(h); } free(hostPtr); return { 'results': results, 'hostStatuses': hostStatuses, }; } ``` ### C API 函数 `port_scanner.h` 中定义了以下函数: ``` ScannerWrapper* scanner_create(const char* hosts[], int hosts_count, int start_port, int end_port, int timeout_ms, int max_threads); void scanner_destroy(ScannerWrapper* scanner); void scanner_scan(ScannerWrapper* scanner); int scanner_get_result_count(ScannerWrapper* scanner); PortResult scanner_get_result(ScannerWrapper* scanner, int index); HostStatus scanner_get_host_status(ScannerWrapper* scanner, int index); ``` ### 数据类型 **HostStatus** — 主机状态枚举: - `HOST_STATUS_ONLINE = 0` — 主机可达,找到了开放端口 - `HOST_STATUS_NO_PORTS = 1` — 主机可达,但未找到开放端口 - `HOST_STATUS_OFFLINE = 2` — 主机不可达 **PortResult** — 端口扫描结果结构体: ``` typedef struct { char* host; // Имя хоста (выделяется память, требуется free) int port; // Номер порта int is_open; // 1 если порт открыт, 0 если закрыт char* service; // Название службы (выделяется память, требуется free) } PortResult; ``` ### Android 权限 要在 Android 上运行,请在 `AndroidManifest.xml` 中添加权限: ``` ``` 如果没有此权限,应用程序将无法建立用于扫描端口的网络连接。
标签:C++, 云存储安全, 内核驱动, 插件系统, 数据擦除, 数据统计, 端口扫描, 网络协议, 网络扫描