news 2026/10/9 3:41:32

基于Java与Nmap的漏洞扫描系统实战:内网巡检与MySQL CIS审计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Java与Nmap的漏洞扫描系统实战:内网巡检与MySQL CIS审计

简介:基于Java实现的漏洞扫描系统项目包,定位为网络安全与Java开发交叉领域的实战学习资源,适合希望掌握漏扫工具原理、服务识别与漏洞匹配逻辑的开发者。资源共927个文件,压缩包约33.07MB,核心由604个nse脚本、146个lua文件及Java源码、class、jar构成,涵盖Nmap脚本引擎与Java程序协同工作的完整结构。已有183人学习。系统知识点覆盖端口扫描、服务识别、CVE漏洞数据库匹配、扫描策略管理、报告生成与并发调度,Java多线程和NIO的应用也体现在工程代码中。通过阅读源码和脚本,可理解如何将Nmap探测能力封装进Java应用,并学会搭建具备自定义规则和权限控制的扫描框架。整体目录含nmap服务探测库、协议指纹文件、审计脚本及Java交互模块,适合作为课程设计或安全工具二次开发的参考。

1. 基于 Java 的漏洞扫描系统:Nmap 做引擎、Java 做外壳,适合内网巡检的现成骨架

这套东西说白了不是又一个自研扫描器的“牛皮”,而是一个把 Nmap 的扫描能力、MySQL 的 CIS 审计脚本和 Java 的跨平台界面拼在一起的完整工程包。对中小型企业的安全岗、做等保自查的运维,或是想弄懂“Java 怎么驱动底层扫描工具”的开发者来说,它最值钱的地方是:不用自己从零写端口扫描,直接在一套打包好的代码上改参数就能出结果。它解决的问题很具体——内网里哪些机器开了不该开的端口、MySQL 配置差在哪、两轮扫描之间漏洞有没有新增。这一类活儿,商业扫描器贵且重,这套方案是看得见、摸得着、能自己改的替代品。

2. 拆包看架构:start.bat、Main.class、nmap_service.c 和 mysql-cis.audit,各管哪一段

2.1 先把压缩包里的文件分成四层

拿到包先别急着双击,先看它提供了什么。文件列表其实分成了很明显的四层:

层次文件作用
启动层start.bat、ndiff.bat一键启动入口和扫描结果对比入口
Java 界面层Main.class、DisplayForm.class主程序入口和 Swing 图形窗体
扫描引擎层nmap_service.c、mysql-cis.audit服务识别模块与 MySQL 合规审计脚本
元信息层CHANGELOG 及 LGPL-2.1 / MPL-1.1 / BSD-simplified 许可证版本记录和依赖组件的授权声明

Main.class 是程序入口,负责把各模块串起来;DisplayForm.class 是典型的 Swing 界面,点击扫描按钮之后,后台会创建一个线程池去调度扫描任务。nmap_service.c 不是漏洞利用代码,而是服务识别相关模块,用来根据端口响应特征判断远程主机跑的是什么服务。mysql-cis.audit 是 Nmap 的 NSE 脚本(Lua 写的),专门检查 MySQL 实例是否符合 CIS 安全基线。整个包的核心链路是:Java 窗体接收扫描参数,ProcessBuilder 拉起 Nmap 进程,Nmap 跑端口探测和服务指纹识别,最后 Java 解析 XML 报告并展示在表格里。

2.2 为什么这个组合能立得住:Java 管调度,Nmap 管识别

选 Java 做外壳不是心血来潮。第一,Java 的跨平台特性让同一套代码在 Windows 和 Linux 上都能跑,这对安全巡检工具的部署很重要,很多客户环境服务器是 Linux、办公机是 Windows,一套代码两边通吃。第二,Java 的并发模型天然适合扫描这类高并发的场景,一台主机扫数百个端口,不可能串着来。第三,Swing 虽然在今天看起来老,但部署简单,不需要像 Electron 那样塞一个浏览器内核进去。

而扫描引擎选 Nmap 更是顺理成章的事。Nmap 的指纹库沉淀了二十年,几万条服务和操作系统指纹数据,指望一个团队自己从零搞一套同等质量的指纹库是不现实的。这个包的做法很务实:Java 只负责调度、解析和展示,把最难的指纹识别工作丢给 Nmap,自己只保留一个定制化的服务类型映射模块,这就把工作量降到了一个合理水平。LGPL、MPL、BSD 三个许可证混在一起也不用慌——它们分别对应包里不同来源的组件,只要你不把这套东西闭源后声称完全自主开发,商业内部使用基本没有障碍。

2.3 Java 侧的调度模型:一个线程池管住整个扫描过程

扫描器在 Java 侧的核心调度逻辑并不复杂,常见做法是维护一个目标主机队列,用固定大小的线程池从队列里拿主机,每台主机再触发一次 Nmap 子进程。我一般会这样设计:

// 线程池调度扫描任务 int corePoolSize = 8; ExecutorService executor = new ThreadPoolExecutor( corePoolSize, corePoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100), new ThreadPoolExecutor.CallerRunsPolicy()); List<String> targets = loadTargetList("targets.txt"); CountDownLatch latch = new CountDownLatch(targets.size()); for (String target : targets) { executor.submit(() -> { try { // 每个主机一次 Nmap 调用,输出 XML 到标准输出 NmapResult result = NmapScanner.scan(target, "-sS -T3 -A -oX -"); ResultStore.save(result); } finally { latch.countDown(); } }); } latch.await(30, TimeUnit.MINUTES);

这里有几个参数值得展开说。corePoolSize 设为 8,是因为同时拉起 8 个 Nmap 子进程,对一个普通内网环境来说已经足够,再多容易把执行机自己的网络栈打满。队列容量 100,超过上限后 CallerRunsPolicy 会让提交线程自己执行任务,防止内存溢出。latch.await 的超时设为 30 分钟,是为了防止某个慢目标拖垮整个扫描批次,那些扫描不动的目标,宁可标记为超时未完成,也不死等。

提示:Nmap 的-oX -表示把 XML 结果输出到标准输出,Java 这边直接读子进程的 stdout 就能拿到结果,不需要临时文件中转,这是比较干净的做法。

3. 把它跑起来:JDK 和 Nmap 环境准备、start.bat 解析与 Java 调 Nmap 的完整链路

3.1 先做三件事:装 JDK、装 Nmap、准备目标清单

这个包不带 Nmap,也不带 JDK,环境要自己装。JDK 建议用 8 或 11,代码里的 Swing 界面和 ProcessBuilder API 在 17 上也能跑,但没必要追新,8 的生态最稳。Nmap 是核心依赖,Windows 下装完后要确认 nmap.exe 和 ncat.exe 都进了系统 PATH;Linux 下用 apt install nmap 即可,但版本建议 7.x 以上,太老对 NSE 脚本的兼容性差。

装完之后,在命令行里先验证两件事:

java -version nmap --version

如果 Java 报错,检查 JAVA_HOME 有没有指向 jdk 目录;如果 Nmap 报错,把安装目录的路径加到 PATH 里。很多新手卡在这一步,不是版本不对,而是 PATH 环境变量里根本没有这两个命令。

接着准备 targets.txt,一行一个目标,支持 IP、网段、域名三种形式:

192.168.1.1 192.168.1.0/24 db-server.example.com

域名形式适合混合云环境,扫描时会先做 DNS 解析再探测。如果目标多,把文件维护在配置管理里,每次扫描直接拉最新版,避免手工改。

3.2 start.bat 逐行拆解:建议你顺手移植成 start.sh

这个包里的 start.bat 内容不多,核心逻辑是把 Java 虚拟机拉起来指向 Main 类:

@echo off setlocal set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_202 set NMAP_HOME=C:\Program Files (x86)\Nmap set PATH=%JAVA_HOME%\bin;%NMAP_HOME%;%PATH% java -Xms256m -Xmx2g -cp .;lib\* com.scanner.Main endlocal

这里有几个关键点:-Xmx2g 限制堆内存上限,防止解析大 XML 时把系统内存吃光;-cp 指定类路径,包含当前目录和 lib 目录下所有 jar 包;setlocal 和 endlocal 让环境变量只在脚本内生效,不污染系统全局。如果你换成 Linux 环境,批处理脚本用不了,需要写等价版本:

#!/bin/bash export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export NMAP_HOME=/usr/bin export PATH="$JAVA_HOME/bin:$NMAP_HOME:$PATH" java -Xms256m -Xmx2g -cp .:lib/* com.scanner.Main

这算不上高技术,但很多包交付时只提供了 .bat,你要上生产环境反而得先补一个 .sh。把它翻译成 .sh 之后,配合 crontab 还能做到定时巡检,把一次性扫描变成周期性例行工作。

3.3 Java 调 Nmap 的完整链路:ProcessBuilder、超时与输出重定向

Java 调外部进程的标准姿势是 ProcessBuilder,这个包里的核心调用大概是下面这个写法:

public class NmapScanner { // 组装 Nmap 命令并执行,返回 XML 字符串 public static String scan(String target, String args) throws IOException, InterruptedException, TimeoutException { ProcessBuilder pb = new ProcessBuilder( "nmap", args.split("\\s+")[0], args.split("\\s+")[1], "--", target); pb.redirectErrorStream(true); // 合并 stderr 到 stdout,统一读 Process process = pb.start(); // 读 stdout,避免子进程输出阻塞管道 StringBuilder output = new StringBuilder(); try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { output.append(line).append(System.lineSeparator()); } } // 最多等 10 分钟,超时直接杀掉进程 if (!process.waitFor(10, TimeUnit.MINUTES)) { process.destroyForcibly(); throw new TimeoutException("Nmap 扫描超时: " + target); } return output.toString(); } }

这段代码里有三个细节值得单独说。一是 pb.redirectErrorStream(true),如果不合并,Nmap 的报错信息会单独写进 stderr,读取端只读 stdout 就会漏掉关键错误,排查时一头雾水;二是 waitFor(10, TimeUnit.MINUTES) 用带超时的重载而不是傻等,能避免某个目标网络黑洞把整个扫描任务挂死;三是逐行读输出,防止 XML 输出量过大时子进程被写缓冲区堵死。

参数层面,-sS 是 SYN 半开扫描,速度快且不易被目标系统记录完整连接;-T3 是适度时序控制,在隐蔽性和速度之间取平衡;-A 会开启服务版本探测和操作系统指纹识别,信息最全但耗时翻倍。如果你只想快速摸一遍端口开放情况,可以去掉 -A 改成 -sV,速度能有明显提升。

3.4 解析 Nmap 的 XML 输出:别用正则,用 DOM

Nmap 的 -oX 输出是标准 XML 结构,最省事的做法是用 DOM 一次性加载,把解析逻辑抽象成独立类:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new InputSource(new StringReader(xml))); // 遍历端口节点 NodeList ports = doc.getElementsByTagName("port"); for (int i = 0; i < ports.getLength(); i++) { Element port = (Element) ports.item(i); String portId = port.getAttribute("portid"); String protocol = port.getAttribute("protocol"); String state = port.getAttribute("state"); // 按需继续提取 service 和 script 节点 }

这里最关键的一行是 setFeature(...disallow-doctype-decl, true),它关闭了 XML 外部实体解析,防止恶意的 XML 文件触发 XXE。扫描器面向内网还好,但如果哪天你把扫描器暴露到不可信网络,解析不可信 XML 时这行代码是保命级别的安全措施。

注意:解析时优先选 DOM 而不是 SAX。扫描结果的 XML 体量通常在几 MB 以内,DOM 完整加载后用 XPath 查询非常方便;如果单次 XML 超过 100MB,再考虑换成 SAX 或 StAX 省内存。

4. 把 MySQL CIS 审计接进来:漏扫不碰业务数据,但能看出配置合不合规

4.1 mysql-cis.audit 这个脚本查的是规矩,不是漏洞

mysql-cis.audit 是 Nmap NSE 库中的一个审计脚本,对应的是 MySQL 的 CIS 安全基线,检查范围包括:是否允许匿名登录、root 账户是否设置了强密码、是否开启了 general log、默认端口有没有被改动、文件权限是否过宽、SSL 是否启用等几十个检查项。这些项严格说不是漏洞,是配置规范——配置不合规不一定会被攻击者直接利用,但往往是攻击链条上最容易被利用的一环。

用法是在 Nmap 调用时按脚本名引用:

nmap -p 3306 --script mysql-cis.audit --script-args mysql-cis.username=scanuser,mysql-cis.password=scanpass 192.168.1.10

注意这里需要提供一对有登录权限的 MySQL 账号密码。如果拿不到账号,脚本只能连到 3306 端口,但里面的检查项大多需要实际建连接执行 SQL 才能得出结果。扫描账号推荐只用 SELECT 权限的空账号,不要用 root 扫,一方面减少对业务库的影响,另一方面也避免审计日志里留下大量 root 操作记录。

4.2 把 CIS 审计结果并回 Java 展示层

NSE 脚本的结果会以 script 节点写在 Nmap 的 XML 输出里,Java 解析时按节点名定位即可:

NodeList scripts = doc.getElementsByTagName("script"); for (int i = 0; i < scripts.getLength(); i++) { Element script = (Element) scripts.item(i); String id = script.getAttribute("id"); if ("mysql-cis.audit".equals(id)) { // 脚本输出在 table 节点下的 elem 节点里 NodeList tables = script.getElementsByTagName("table"); for (int j = 0; j < tables.getLength(); j++) { Element table = (Element) tables.item(j); String key = table.getAttribute("key"); // 按 key 提取检查项名称,再取子节点 elem 拿结果 System.out.println("检查项: " + key); } } }

这里有个容易翻车的地方:NSE 脚本的返回结构不统一,有的检查项返回 table 树状结构,有的直接返回 elem 文本。写解析代码时不要假设所有项都是同一种结构,最稳妥的办法是先把一段真实 XML 输出打印出来,对着结构写代码,而不是凭空猜。拿不到样例就一层层 getChildNodes 遍历,把节点名打出来看一遍再动笔。

4.3 两个容易理解错的概念:扫描快不等于安全,服务识别不等于攻击

最后想提醒一个容易忽略的心态问题。扫描器跑完,开放端口多、告警多,这不代表系统就比扫描结果干净的机器更不安全——攻击者真正利用的是漏洞,不是端口本身。同理,nmap_service.c 做的是服务识别,它根据响应特征判断这台机器上跑的可能是 MySQL,这并不等于这台机器可以被攻击。把扫描器定位成摸底工具,扫出高风险端口后人工复核,才合理。

5. 避坑实录:这套 Java 漏扫跑起来最容易翻车的五个地方

5.1 没有管理员权限,SYN 扫描假装成功其实什么也没扫到

现象:Linux 上用普通用户执行 -sS 扫描,Nmap 不报错,结果里所有端口都是 filtered,看起来像目标全开了防火墙。

原因:SYN 半开扫描需要发送原始 IP 包,这要求 root 权限。普通用户没有原始套接字权限,Nmap 会静默降级成 TCP connect 扫描,但目标防火墙策略严格时,connect 扫描结果和 filtered 一样,表面上不报错,实际没结果。

解决:内网巡检场景下直接用 -sT 代替 -sS,牺牲一点隐蔽性换来权限兼容性;生产环境跑扫描时,给执行账户配置 sudo 且设置 NOPASSWD,避免人工输密码打断自动化。

5.2 XML 输出 GBK 编码读成 UTF-8,解析结果全乱

现象:Windows 上 Nmap 的 XML 输出带中文注释或中文主机名,Java 用 UTF-8 读出来一堆乱码,节点名没乱但取值全废。

原因:Windows 默认编码是 GBK,Nmap 在某些版本会把本地化信息按系统编码写进 XML 注释和主机名。这些信息对显示结果很有用,一旦乱码,报告没法看。

解决:InputStreamReader 指定编码时不要写死 UTF-8,而是从 Nmap 输出里读 encoding 声明;或者在启动脚本里加 -Dfile.encoding=UTF-8 和 -Dsun.jnu.encoding=UTF-8,两边统一后乱码问题基本消失。

5.3 路径带空格,ProcessBuilder 直接抛 IOException

现象:把包放在 C:\Program Files\Scanner 这种带空格目录下,点击扫描后 Java 报 Cannot run program "nmap"。

原因:ProcessBuilder 接收的是字符串数组,第一个元素是 nmap,会依赖系统 PATH 解析。PATH 里没有 Nmap,或者工作目录里没有 nmap.exe,瞬间报错。不少人用 cmd 手工敲 nmap 是好用的,进了 Java 就不行,原因多半在 PATH 继承出了问题。

解决:在启动脚本里显式把 NMAP_HOME 加到 PATH,或者 Java 侧用系统属性配置完整路径:

String nmapPath = System.getProperty("nmap.path", "C:\\Program Files (x86)\\Nmap\\nmap.exe");

部署到不同机器时改启动脚本,不用动代码。

5.4 MySQL 账号密码写死在命令行,日志里全是明文的

现象:用 --script-args mysql-cis.username=scanuser,mysql-cis.password=scanpass 扫描后发现运维平台的日志里明文记录了密码。

原因:命令行参数会出现在进程列表和历史记录里,Linux 的 ps、Windows 的 WMIC 都能看到,这不是可能泄露的问题,而是一定会泄露的问题。

解决:NSE 脚本支持 --script-args-file 参数,账号密码写到单独文件里,并把文件权限设为 600。Java 侧调用时把参数从配置文件读出来再组装,输出日志时对密码字段做脱敏。

5.5 大批量目标时线程池爆掉,内存直接 OOM

现象:targets.txt 里写了几百上千个目标,跑起来没一会儿 Java 程序直接 OutOfMemoryError。

原因:很多扫描器会把所有任务一股脑提交到无界队列,每个任务还持有完整的 XML 字符串,内存不炸才怪。没设队列容量是第一个原因,解析完的 XML 字符串没有及时释放是第二个原因。

解决:线程池队列设成长度上限的 LinkedBlockingQueue,配合 CallerRunsPolicy;解析完 XML 后立即释放引用,让大字符串随方法退出被回收;大批量目标分批写结果,别攒在内存里最后一次性落盘。

6. 把对比扫描变成习惯:用 ndiff.bat 在两次扫描之间找出新增风险

扫描器跑一遍拿到报告,这只是做完了一半。真正能让你觉出这套工具价值的是第二遍:隔一周再扫一次,对比前后两个结果,看出新增了哪些端口、多了哪些服务。这就是 ndiff.bat 的用武之地。

ndiff 是 Nmap 自带的对比工具,用法很直接:

ndiff scan-before.xml scan-after.xml

它会输出三块内容:新增的主机、主机上新增的端口、端口状态变化。我一般会把两次扫描的 XML 都保存下来,然后用 ndiff 生成 diff 报告归档。比如周一全公司扫一遍,下周一再扫一遍,对比结果就能看出“这台服务器这周新开了一个 3389 端口”——这通常意味着有人擅自改了防火墙规则或装了远程桌面服务。

一个更省事的习惯是把对比集成到定时脚本里:

#!/bin/bash # 每周巡检:先扫,再对比上周结果,输出变更摘要 nmap -sT -T3 --open -oX scan-$(date +%Y%m%d).xml -iL targets.txt ndiff scan-$(date -d '7 days ago' +%Y%m%d).xml scan-$(date +%Y%m%d).xml > diff-$(date +%Y%m%d).txt

这里 -oX 生成的 XML 文件名带日期,配合 ndiff 的自然对比,每周只需要翻 diff 文件就能了解整个网络的变化。这个习惯帮我省掉了大量重复翻报告的功夫——大部分机器每周不会有任何变化,diff 文件通常就几行,一眼看完;真正需要重视的就是这几行新增的内容。

从那以后,我每次跑扫描之前都会强制走一遍这个流程:先确认上次扫描结果在不在,扫完立刻做 diff,看到新增端口先查变更单,查不到再上机器人工核实。希望你也能把这套 Java 漏扫系统用起来,让它在内网巡检里真正发挥作用。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 3:41:02

Java课设“记事簿管理系统”实战:跑通、避坑与优化

简介&#xff1a;一套基于Java编程语言开发的综合性个人管理源码包&#xff0c;集成记事簿、备忘录、通讯录与记账本四大常用模块&#xff0c;面向Java Web方向初学者、课程实训及毕业设计参考者&#xff0c;可帮助掌握模型-视图-控制器架构、Servlet/JSP技术、数据库访问等核心…

作者头像 李华
网站建设 2026/10/9 3:40:46

Codex桌面版更新后无法加载组织设置?config.toml排查与修复指南

1. 一次更新引发的连锁反应&#xff1a;从“打不开”到“无法加载组织设置”事情发生在上周。我平时主力用 Codex 桌面版做代码补全和重构&#xff0c;那天早上打开电脑&#xff0c;习惯性地点开图标&#xff0c;结果窗口闪了一下就没了。再点&#xff0c;还是闪退。任务栏里能…

作者头像 李华
网站建设 2026/10/9 3:40:28

SQL Server实战指南:从T-SQL查询到索引优化与慢查询排查

平时工作里天天和数据打交道&#xff0c;SQL Server 是我用得最顺手的关系型数据库之一。相比 MySQL 的轻巧灵活和 Oracle 的厚重严谨&#xff0c;SQL Server 在 Windows 生态下的集成度、图形化管理工具的易用性、以及 T-SQL 语法的人性化程度&#xff0c;都让它成为很多企业业…

作者头像 李华
网站建设 2026/10/9 3:39:54

频域盲反褶积结合基尼稀疏约束的地震分辨率提升方法

1. 项目到底解决什么问题&#xff0c;为什么要用盲反褶积1.1 地震记录、子波与反射系数&#xff1a;卷积模型先讲清楚做地震资料处理的朋友应该都清楚&#xff0c;地震道从来都不是地层反射系数的直接记录&#xff0c;而是地震子波和反射系数序列的褶积结果。写成公式就是&…

作者头像 李华
网站建设 2026/10/9 3:39:49

AI工具环境管理:venv、conda、pyenv、uv分层协作指南

一直有人问我&#xff0c;电脑上装了那么多AI工具&#xff0c;环境到底是怎么管的。问这个问题的人&#xff0c;多半是刚被依赖冲突搞崩过——上午还能跑的OCR脚本&#xff0c;下午一import就报错&#xff1b;为了试一个新出的开源AI项目&#xff0c;conda create了一个新环境&…

作者头像 李华