Java反序列化中的RMI、JRMP、JNDI、LDAP(2)
前言
乱七八糟的东西。
readObject
找一找Java里有没有其他不受黑白名单限制,又可以通过反序列化触发的反序列化点。
简单来说就是存在重开InputStream操作的类,要么是可序列化类,要么存在发起连接操作,不然数据就要通过别的可序列化类传递过来,不好控制。
有一些叫做getObject的函数,比如SignedObject、SealedObject,然而没有什么会调用他们的地方。
MarshalledObject
其get函数如下:
1 |
|
看起来是可控的,然而看到这里有一个碍眼的objectInputFilter,它在readObject时会被赋值:
1 |
|
getObjectInputFilter会从原本的InputStream中取出其InputFilter:
1 |
|
所以原本反序列化流程中存在的InputFilter也会影响这里的反序列化。
想要通过反序列化操作调用这里的get函数,就要调用ActivatableRef类的invoke函数,即RemoteRef接口的invoke函数,但是反序列化过程中方便触发的点位于RemoteObjectInvocationHandler函数中,需要使用动态代理,还需要代理的接口继承了Remote。
整条利用链应该跟以前学习过的JRMP绕过类似,这里就不验证了。
RegistryImpl_Skel
即RMI中注册中心使用的反序列化点,该类不可序列化。
当通过LocateRegistry.createRegistry创建注册中心时会实例化一个RegistryImpl对象:
1 |
|
其构造函数会开始建立监听并通过registryFilter函数注册反序列化白名单:
1 |
|
RegistryImpl_Stub
位于其list函数和lookup函数中,依旧是RMI中注册中心使用的反序列化点,该类不可序列化。
同样受到白名单影响。
UnicastRef
即RMI中服务端使用的反序列化点,其unmarshalValue函数中会有一个反序列化操作,用于反序列化客户端传输过来的对象。
可反序列化,有两条路可以来到该反序列化点,第一是跟MarshalledObject类似,同样是调用RemoteRef接口的invoke函数,但是需要满足的条件更多,需要代理的函数返回类型不是Int、Boolean等主要类型。
第二就是走正常途径,通过反序列化搞定一个RMI服务端了,听起来就不可靠。
DGCImpl_Skel
位于dispatch函数中,即JRMPListener利用链使用的反序列化点,会受到DGCImpl类的白名单影响。
DGCImpl_Stub
位于dirty函数中,即JRMPClient利用链使用的反序列化点,同样会受到DGCImpl类的白名单影响。
StreamRemoteCall
位于executeCall函数中,同样有两条路径,第一条与MarshalledObject相似,通过RemoteRef接口的invoke函数触发,即以前学习过的JRMP反序列化绕过利用链。
第二条不怎么可信,走DGCImpl_Stub的clean、dirty函数会受到白名单影响,走RegistryImpl_Stub的话它的ref成员又无法通过反序列化控制。
触发RemoteRef接口的invoke函数
可控触发点位于RemoteObjectInvocationHandler类中,需要用其代理一个Remote子接口中定义的函数才能触发。
RMIServer
存在一个getVersion函数,或许可以跟fastjson之类的会调用getter的东西一起用?
ActivationInstantiator
往上追又到了Activator接口的activate函数,没必要看了。
Activator
有一个activate函数,要通过RemoteRef接口的invoke函数触发。