RMI

发布时间 2023-09-13 08:42:02作者: Jasper_sec

前言

时间有限,目前只跟完了RMI的源码分析部分,攻击和绕过只有下周再来了。
不过跟源码也已经发现了一些有意思的反序列化点,也算是为后面学习打基础了。

源码分析

看了一些师傅的文章,发现RMI交互这块内容写得都异常混乱,大篇幅的文字,很容易看得云里雾里。
这里我按照下图标号的顺序,依次调试每一块代码,并对代码进行标注,希望能对师傅们有所帮助。

推荐先看完组长的视频,自己跟着调一遍,此时可能会感觉云里雾里、不知所云,这是正常的;
接着再看素十八师傅的博客,主要是源码分析这一块,再调试一遍,基本就能掌握了。

一图胜千言

1.png

服务端创建注册中心

image.png
创建RegistryImpl对象
image.png
image.png
setup#UnicastServerRef#exportObject暴露RegistryImpl对象
image.png
image.png
LiveRef#exportObject暴露Target对象,三层套娃。
LiveRef#exportObject(Target target)
image.png
TCPEndpoint#exportObject(Target target)
image.png
TCPTransport#exportObject(Target target)
image.png
最后,把封装了RegiseryImpl_Stub的Target记录进hashtable里,至此注册中心创建完成。
image.pngimage.png

服务端创建远程对象

image.png
创建RemoteObjectImpl对象
image.png
调用父类UnicastRemoteObject构造函数,二层套娃。
image.png
image.png
UnicastRemoteObject#exportObject暴露RemoteObjectImpl对象,二重套娃。
image.png
image.png
UnicastServerRef#exportObject暴露RemoteObjectImpl对象
image.png
LiveRef#exportObject暴露Target对象,三层套娃。
LiveRef#exportObject(Target target)
image.png
TCPEndpoint#exportObject(Target target)
image.png
TCPTransport#exportObject(Target target)
image.png
最后,把封装了RemoteObjectImpl_Stub的Target记录进hashtable里,至此远程对象创建完成。
image.png
image.png

服务端远程对象绑定注册中心

image.png
调用RegistryImpl_Stub#bind()绑定远程对象与名称,将name和对应obj存入bindings,绑定过程到此结束。
image.png

客户端获取注册中心代理对象

image.png
套娃一层getRegistry,函数重载
image.png
根据host/ip封装LiveRef和UnicastRef
image.png
通过Ref和RegistryImpl来创建注册中心的代理对象
image.png
到此为止,注册中心的代理对象就创建完毕了。
image.png

客户端通过注册中心查找远程对象

image.png
调用Registry_Stub#lookup获取查找的远程对象的代理
下面这里直接return var23,返回反序列化后的远程对象的代理
image.png

注册中心收到查询请求并返回远程对象的代理

这里开始涉及C/S交互,首先DEBUG起一个RMIServer,断点打在TCPTransport#handleMessages,
这个函数专门用于处理请求信息,然后运行RMIClient,由于执行了lookup方法,所以能命中断点开始调试。
image.png
调用serviceCall进一步处理网络请求信息,最后调用到UnicastServerRef#dispatch
image.png
这里套娃调用UnicastServerRef#oldDispatch
image.png
再套娃调用skel#dispatch,最终肯定是通过服务端的代理skel来处理网络请求的
image.png
调用RegistryImpl_Skel#dispatch,获取Client传过来的name,另外新建RegistryImpl,在Server端本地调用RegistryImpl.lookup(name),获取返回的远程对象,序列化写回网络连接中,传给Client。
image.png

客户端调用远程对象的方法

同样涉及C/S交互,不过这里DEBUG的是Client,Server正常运行起就行,Client DEBUG启动。
image.png
Client获取的是远程对象的动态代理stub,它调用任意方法都会走到invoke里
三层套娃调用
image.png
image.png
最后一层,真正进行C/S交互,客户端调用远程对象方法,并且从Server端获取到返回值。
image.png
image.png
至此,Client调用远程对象的方法结束。

服务端接收调用函数请求并返回执行结果

Server还是断在TCPTransport#handleMessages,DEBUG起Server,正常运行起Client。
handleMessages会获取很多请求,像是之前注册中心的lookup,这里多跳几下就能到远程对象的请求了。
image.png
调用serviceCall进一步处理网络请求信息,最后调用到UnicastServerRef#dispatch
image.png
UnicastServerRef#dispatch,真正处理网络请求,并且返回响应的函数。
与调用lookup的不同之处如下
image.png
主要逻辑如下
image.png
至此,服务端完成接受客户端调用(传参)、本地执行函数、返回执行结果这个过程。

参考链接

https://www.bilibili.com/video/BV1L3411a7ax
https://su18.org/post/rmi-attack
https://tttang.com/archive/1530/
https://xz.aliyun.com/t/9261