Weblogic CVE-2016-3510 MarshalledObject反序列化绕过分析

警告
本文最后更新于 2020-02-12,文中内容可能已过时。

Weblogic系列文章,还是绕过黑名单。

https://github.com/5up3rc/weblogic_cmd 修改payload类型

image

成功执行命令,断点同样下在InvokerTransformer的transform(),堆栈如下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
transform:123, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:157, LazyMap (org.apache.commons.collections.map)
invoke:50, AnnotationInvocationHandler (sun.reflect.annotation)
entrySet:-1, $Proxy57
readObject:327, AnnotationInvocationHandler (sun.reflect.annotation)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:39, NativeMethodAccessorImpl (sun.reflect)
invoke:25, DelegatingMethodAccessorImpl (sun.reflect)
invoke:597, Method (java.lang.reflect)
invokeReadObject:974, ObjectStreamClass (java.io)
readSerialData:1848, ObjectInputStream (java.io)
readOrdinaryObject:1752, ObjectInputStream (java.io)
readObject0:1328, ObjectInputStream (java.io)
readObject:350, ObjectInputStream (java.io)
readResolve:58, MarshalledObject (weblogic.corba.utils)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:39, NativeMethodAccessorImpl (sun.reflect)
invoke:25, DelegatingMethodAccessorImpl (sun.reflect)
invoke:597, Method (java.lang.reflect)
invokeReadResolve:1061, ObjectStreamClass (java.io)
readOrdinaryObject:1761, ObjectInputStream (java.io)
readObject0:1328, ObjectInputStream (java.io)
readObject:350, ObjectInputStream (java.io)
readObject:69, InboundMsgAbbrev (weblogic.rjvm)
read:41, InboundMsgAbbrev (weblogic.rjvm)
readMsgAbbrevs:283, MsgAbbrevJVMConnection (weblogic.rjvm)
init:215, MsgAbbrevInputStream (weblogic.rjvm)
dispatch:498, MsgAbbrevJVMConnection (weblogic.rjvm)
dispatch:330, MuxableSocketT3 (weblogic.rjvm.t3)
dispatch:394, BaseAbstractMuxableSocket (weblogic.socket)
readReadySocketOnce:960, SocketMuxer (weblogic.socket)
readReadySocket:897, SocketMuxer (weblogic.socket)
processSockets:130, PosixSocketMuxer (weblogic.socket)
run:29, SocketReaderRequest (weblogic.socket)
execute:42, SocketReaderRequest (weblogic.socket)
execute:145, ExecuteThread (weblogic.kernel)
run:117, ExecuteThread (weblogic.kernel)

用的common-collection1,MarshalledObject 在 (weblogic.corba.utils) 中 WEB-INF\lib\weblogic.jar!\weblogic\corba\utils\MarshalledObject.class

同样是绕过黑名单,将反序列化的对象封装进了weblogic.corba.utils.MarshalledObject,然后再对MarshalledObject进行序列化,生成payload字节码。由于MarshalledObject不在WebLogic黑名单里,可正常反序列化,在反序列化时MarshalledObject对象调用readObject时对MarshalledObject封装的序列化对象再次反序列化,可以绕过黑名单的限制。

看下weblogic_cmd中如何构造的

image

handler是构造的cc对象,进入BypassPayloadSelector.selectBypass()

image

根据TYPE决定使用什么来构造payload,跟进到marshalledObject(payload)

image

将构造的cc对象封装进MarshalledObject对象marshalledObject,然后return,进入Serializables.serialize(_handler)

image

拿到序列化对象的字节码数组,然后通过t3协议发送出去,后面不在解释。

总的来说,就是将cc对象封装进MarshalledObject,MarshalledObject不在黑名单中,那么执行他的readObject()就可以触发cc链。

再来看下weblogic在哪触发的readObject(),断到MarshalledObject.class的48行。

image

这里的readObject()触发反序列化,怎么进入到readResolve()这个方法的?查看堆栈进入invokeReadResolve()

image

这里通过反射调用var1也就是MarshalledObject对象的readResolve()方法。var1中包含了我们恶意的序列化数据,它怎么传进来的?

进入堆栈中readOrdinaryObject()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private Object readOrdinaryObject(boolean var1) throws IOException {
    if (this.bin.readByte() != 115) {
        throw new InternalError();
    } else {
        ObjectStreamClass var2 = this.readClassDesc(false);
        var2.checkDeserialize();

        Object var3;
        try {
            var3 = var2.isInstantiable() ? var2.newInstance() : null;
        } catch (Exception var6) {
            throw (IOException)(new InvalidClassException(var2.forClass().getName(), "unable to create instance")).initCause(var6);
        }

        this.passHandle = this.handles.assign(var1 ? unsharedMarker : var3);
        ClassNotFoundException var4 = var2.getResolveException();
        if (var4 != null) {
            this.handles.markException(this.passHandle, var4);
        }

        if (var2.isExternalizable()) {
            this.readExternalData((Externalizable)var3, var2);
        } else {
            this.readSerialData(var3, var2);
        }

        this.handles.finish(this.passHandle);
        if (var3 != null && this.handles.lookupException(this.passHandle) == null && var2.hasReadResolveMethod()) {
            Object var5 = var2.invokeReadResolve(var3);
            if (var1 && var5.getClass().isArray()) {
                var5 = cloneArray(var5);
            }

            if (var5 != var3) {
                var3 = var5;
                this.handles.setObject(this.passHandle, var5);
            }
        }

        return var3;
    }
}

在这里调用了invokeReadResolve(),参数var3在上文经过this.readClassDesc().newInstance()拿到传入t3协议的MarshalledObject对象,具体做了什么处理不深入研究。

t3传入MarshalledObject对象 -> readOrdinaryObject() 拿到MarshalledObject对象 -> invokeReadResolve() 反射调用MarshalledObject对象的readResolve() -> readObject()触发cc反序列化。

  1. jdk最好用1.6的,不然总是定位不到正确的函数。
  2. https://www.cnblogs.com/afanti/p/10240232.html

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。