RMI学习
RMI学习
基础
组成
- Client
- Registry
- Server
通信原理
- 服务端绑定远程对象(java中定义的一个远程对象类)
- 客户端只要传value
- 解决端口问题:注册中心,储存远程对象value与服务端端口的映射(在远程对象创建时形成映射)
动态代码加载(JDK高版本去掉了)
如果客户端调用了服务端没有的类对象,RMI允许服务端去远程的Web Server上加载类
远程接口、对象、方法
通信的两端要实现一个相同接口:java.rmi.Remote
这个接口要抛一个异常
服务端实现远程调用的接口时,要继承UnicastRemoteObject,这样才能绑定到rmi服务里
流程
客户端和服务端都各自设置了一个代理 Skeleton/Stub
如果绑定端口到0,会被分配到随机端口
注册中心和服务端放在一台服务器上,防止远程调用时的安全问题
JRMP协议:RMI自定义的客户端协议
可以通过这个协议攻击stub
传输过程利用序列化,将收取到的数据反序列化,存在攻击点
DGC
静态变量dgclog,调用时会触发这个类的初始化,其静态代码块中会实例化一个DGCImpl_Stub
风险点:调用invoke,可进行反序列化攻击
攻击dgc不需要知道参数类型
Stub和Skeleton
Stub:客户端代理类
Skeleton:服务端代理类
实现过程
- 客户端要调用远程主机上的方法
- 经过Stub的代理,请求杯编码通过网络传输给Skeleton
- Skeleton收到请求,转换成服务端可以识别的请求
- 发送请求到服务的
- 服务端处理后结构,发送到Skeleton进行编码
- Stub收到后解码结果
- 客户端获得远程方法调用的结果
注册远程对象
1 | RemoteInterface remoteObj2 = new RemoteImpl();// 创建远程对象 |
只要继承了java.rmi.Remote接口,就可以成为存在于服务器的远程对象
远程对象必须实现java.rmi.server.UniCastRemoteObject类,该类的构造函数中将生成stub和skeleton, 这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为Stub( 存根), 而服务器端本身已存在的远程对象则称之为Skeleton(骨架) 。
获取注册中心
创建时获取 createRegistry
- 第一种只要传port,表示和注册中心申请使用的端口,后面再绑定value上去以便客户端请求
- 第二张传port外,还需要传递RMIClientSocketFactory以及RMIServerSocketFactory对象。
- 两个方法最终获取到的都是RegistryImpl对象,对于攻击者的我们关系并不大
对第一种方法的分析
1 | public static Registry createRegistry(int var0) throws RemoteException { |
var0便储存着我们要传递的port
跟进
1 | public RegistryImpl(int var1) throws RemoteException { |
LiveRef封装了ip和端口
远程获取 getRegistry
JDK高版本绕过
高版本做的防御
反序列化前判断类型
dgc反序列化也做了过滤
远程对象反序列化,需要知道具体参数类型
攻击思路
服务端发起对客户端的请求,使用dgc向客户端发起请求,通过利用链调用dgc的dirty方法来给客户端发请求
- 标题: RMI学习
- 作者: Sl0th
- 创建于 : 2022-10-01 23:31:00
- 更新于 : 2024-11-11 18:23:06
- 链接: http://sl0th.top/2022/10/01/RMI学习/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论