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

复现

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

image

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

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

 1private Object readOrdinaryObject(boolean var1) throws IOException {
 2    if (this.bin.readByte() != 115) {
 3        throw new InternalError();
 4    } else {
 5        ObjectStreamClass var2 = this.readClassDesc(false);
 6        var2.checkDeserialize();
 7
 8        Object var3;
 9        try {
10            var3 = var2.isInstantiable() ? var2.newInstance() : null;
11        } catch (Exception var6) {
12            throw (IOException)(new InvalidClassException(var2.forClass().getName(), "unable to create instance")).initCause(var6);
13        }
14
15        this.passHandle = this.handles.assign(var1 ? unsharedMarker : var3);
16        ClassNotFoundException var4 = var2.getResolveException();
17        if (var4 != null) {
18            this.handles.markException(this.passHandle, var4);
19        }
20
21        if (var2.isExternalizable()) {
22            this.readExternalData((Externalizable)var3, var2);
23        } else {
24            this.readSerialData(var3, var2);
25        }
26
27        this.handles.finish(this.passHandle);
28        if (var3 != null && this.handles.lookupException(this.passHandle) == null && var2.hasReadResolveMethod()) {
29            Object var5 = var2.invokeReadResolve(var3);
30            if (var1 && var5.getClass().isArray()) {
31                var5 = cloneArray(var5);
32            }
33
34            if (var5 != var3) {
35                var3 = var5;
36                this.handles.setObject(this.passHandle, var5);
37            }
38        }
39
40        return var3;
41    }
42}

在这里调用了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

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