参考:
http://xxlegend.com/2018/06/20/CVE-2018-2628 简单复现和分析/
在CVE-2017-3248的利用中,我们用ysoserial生成了一个java.rmi.registry.Registry类型的proxy
首先回答1个问题,这里的proxy为什么需要是java.rmi.registry.Registry类型的?
因为我们在反序列化这个proxy时,调用的是RemoteObjectInvocationHandler.readObject()(动态代理,用RemoteObjectInvocationHandler代理了Registry接口),然后调用它的父类RemoteObject.readObject()
我们看看RemoteObjectInvocationHandler是啥,看一下这个类源码中的注释
简单说就是用于RMI的动态代理,而RMI需要一个继承了java.rmi.Remote的接口,因此这里的proxy需要是java.rmi.registry.Registry类型的(java.rmi.registry.Registry继承了java.rmi.Remote)。
在修复补丁中,weblogic在InboundMsgAbbrev
的resolveProxyClass
方法中使用了黑名单对反序列化类进行限制:
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);
}
对java.rmi.registry.Registry
进行了过滤,那么绕过思路就比较简单了,就是找另外一个继承了java.rmi.Remote的接口即可。
可以使用java.rmi.activation.Activator
进行绕过:
同样的思路,还可以使用java.rmi.Remote其它的子接口进行绕过:
还有另一种绕过思路,就是取消代理proxy
放一张来自https://xz.aliyun.com/t/8443的图:
这张图是weblogic反序列化过程中调用的函数,从图中我们可以看出,反序列化的过程中会有两个分支,一个会调用InboundMsgAbbrev.resolveProxyClass()(修复补丁所在的类),另一个会调用ObjectInputStream.resolveProxyClass(),决定走哪个分支的因素就是被反序列化的类是否是动态代理类。
因此,我们只要使被反序列化的类不被代理,即可不调用InboundMsgAbbrev.resolveProxyClass(),而调用ObjectInputStream.resolveProxyClass(),这样的话,最终仍然会正常反序列化,但绕过了修复补丁。
修改后的代码如下:
那么,为什么在不用动态代理的情况下仍然能成功利用这个漏洞呢,我们可以看下未修改时,ysoserial.payloads.JRMPClient的利用链:
* UnicastRef.newCall(RemoteObject, Operation[], int, long)
* DGCImpl_Stub.dirty(ObjID[], long, Lease)
* DGCClient$EndpointEntry.makeDirtyCall(Set<RefEntry>, long)
* DGCClient$EndpointEntry.registerRefs(List<LiveRef>)
* DGCClient.registerRefs(Endpoint, List<LiveRef>)
* LiveRef.read(ObjectInput, boolean)
* UnicastRef.readExternal(ObjectInput)
*
* Thread.start()
* DGCClient$EndpointEntry.<init>(Endpoint)
* DGCClient$EndpointEntry.lookup(Endpoint)
* DGCClient.registerRefs(Endpoint, List<LiveRef>)
* LiveRef.read(ObjectInput, boolean)
* UnicastRef.readExternal(ObjectInput)
可以看到,它调用了UnicastRef.readExternal(),那么,在修改后的代码中,我们将要反序列化的就是一个UnicastRef,在这个类反序列化的过程中,一样会调用UnicastRef.readExternal(),因此即使不用动态代理,仍然能利用这个漏洞。
标签:序列化,java,2628,resolveProxyClass,调用,weblogic,Registry,搞懂,rmi From: https://www.cnblogs.com/rnss/p/17160420.html