Java安全之RMI协议分析
Java安全之RMI协议分析
0x00 前言
在前面其实有讲到过RMI,但是只是简单描述了一下RMI反序列化漏洞的利用。但是RMI底层的实现以及原理等方面并没有去涉及到,以及RMI的各种攻击方式。在其他师傅们的文章中发现RMI的攻击方式很多。 所以在此去对RMI的底层做一个分析,后面再去对各种攻击方式去做一个了解。
0x01 底层协议概述
RPC
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。
小总结:
在最原始数据通讯中其实还是归根到TCP/UDP协议,但是自使用了RPC后可以不需要了解底层网络协议,但是底层还是通过TCP/UDP去进行网络调用的。 其实RPC也只是远程方法调用的统称,重点在于方法调用中。而RMI实现就是Java版的一个RPC实现。
JMX
JMS:Java 消息服务(Java Messaging Service) 是一种允许应用程序创建、发送、接受和读取消息的Java API。JMS 在其中扮演的角色与JDBC 很相似, JDBC 提供了一套用于访问各种不同关系数据库的公共API,JMS 也提供了独立于特定厂商的企业消息系统访问方式。
JMS 的编程过程很简单,概括为:应用程序A 发送一条消息到消息服务器(也就是JMS Provider)的某个目的地(Destination),然后消息服务器把消息转发给应用程序B。因为应用程序A 和应用程序B 没有直接的代码关连。
RPC 和RMI的区别
RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC不依赖于具体的网络传输协议,tcp、udp等都可以。
RPC是跨语言的通信标准。
RMI可以被看作SUN对RPC的Java版本的实现,当然也还有其他的RPC
微软的DCOM就是建立在ORPC协议之上实现的RPC。
RMI集合了Java序列化和Java远程方法协议(Java Remote Method Protocol)。这里的Java远程方法协议则是JRMP。
RMI和JMS的区别
传输方式
- JMS 与 RMI 的区别在于:采用 JMS 服务,对象是在物理上被异步从网络的某个 JVM 上直接移动到另一个 JVM 上。
- RMI 对象是绑定在本地 JVM 中,只有函数参数和返回值是通过网络传送的。
方法调用
- RMI 一般都是同步的,也就是说,当client端调用Server端的一个方法的时候,需要等到对方的返回,才能继续执行client端,这个过程跟调用本地方法感觉上是一样的,这也是RMI的一个特点。
- JMS 一般只是一个点发出一个Message(消息)到Message Server端,发出之后一般不会关心谁用了这个message(消息)。
- 一般RMI的应用是紧耦合,JMS的应用相对来说是松散耦合的应用。
本段取自RMI与RPC的区别
由此得知其实RMI协议是发送方法以及方法参数,请求到server端后,server进行执行后返回结果给client端。
0x02 RMI底层架构
底层架构概念
根据上面内容其实可以总结为一句话,RPC是为了隐藏网络通信过程中的细节,方便使用。而在RMI中也是一样的。RMI中为了隐藏网络通讯的过程细节采用了动态代理的方式来进行实现。
下面先来看到调用流程图

在客户端和服务器各有一个代理,客户端的代理叫Stub(存根),服务端的代理叫Skeleton(骨架),合在一起形成了 RMI 构架协议,负责网络通信相关的功能。代理都是由服务端产生的,客户端的代理是在服务端产生后动态加载过去的。
stub担当远程对象的客户本地代表或代理人角色,负责把要调用的远程对象方法的方法名及其参数编组打包,并将该包转发给远程对象所在的服务器。

Stub编码后发送的数据包内容,包含如下内容:
1. 被使用的远程对象的标识符
2. 被调用的方法的描述
3. 编组后的参数
Skeleton接收到Stub发送数据会执行如下操作:
1. 从数据包中定位要调用的远程对象
2. 调用所需的方法,并传递客户端提供的参数
3. 捕获返回值或调用产生的异常。
4. 将打包返回值编组,返回给客户端Stub
本段内容部分取自:RMI反序列化漏洞分析
总结大体的内容如下:
客户端(Client):服务调用方。
客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
服务端(Server):服务的真正提供者。
这里值得注意的一点是前面说到的传输进行打包和解包的步骤其实就是序列化和反序列化,传输的是序列化的数据。

架构调用流程
RMI大致的远程调用执行流程:
1. 客户端发起请求,请求转交至RMI客户端的stub类;
2. stub类将请求的接口、方法、参数等信息进行序列化;
3. 基于socket将序列化后的流传输至服务器端;
4. 服务器端接收到流后转发至相应的Skeleton类;
5. Skeleton类将请求的信息反序列化后调用实际的处理类;
6. 处理类处理完毕后将结果返回给Skeleton类;
7. Skelton类将结果序列化,通过socket将流传送给客户端的stub;
8. stub在接收到流后反序列化,将反序列化后的Java Object返回给调用者。
socket层中执行流程
server在远程机器上监听一个端口,这个端口是jvm或者os在运行时随机选择的一个端口。可以说server在远程机器上在这个端口上导出自己。
client并不知道server在哪,以及sever监听哪个端口,但是他有stub。stub知道所有这些东西,这样client可以调用stub上他想调用的任何方法。
client调用给你stub上的方法
stub链接server监听的端口并发送参数,详细过程如下:
4.1 client连接server监听的端口
4.2 server收到请求并创建一个socket来处理这个连接
4.3 server继续监听到来的请求
4.4 使用双方协定的歇息,传送参数和结果
4.5 协议可以是JRMP或者 iiop方法在远程server上执行,并发执行结果返回给stub
stub返回结果给client,就好像是stub执行了这个方法一样。
其实也是一样对于了下面的这张图

但是第二部分内容是值得思索的一点,为什么client不知道server的监听端口和server在哪,而stub却知道呢?client不知道server的host和port的话,stub是如何创建一个知道所有这一切的stub对象呢?
这时候就引出了RMIRegistry(注册中心)的作用了。
RMIRegistry作用
RMIRegistry 可以认为是一个服务,它提供了一个hashmap,里面是 public_name, Stub_object 名值对。比如有一个远程服务对象叫做 Scientific_Calculator,然后想把这个服务对外公布为 calc,这样会在server上创建一个stub对象,把他注册到RMIRegistry ,这样client就可以从RMIRegistry 中得到这个stub对象了,可以使用一个工具类java.rmi.Naming来方便的操作注册和操作。
实现可看Java安全之RMI反序列化该篇文章。
总结:
简单来说就是使用java.rmi.Naming将一个某一个类注册进RMIRegistry 里面,注册后会在server端创建stub对象,而client就可以从RMIRegistry 中得到这个stub对象。前面内容说到过代理都是由服务端产生的,客户端的代理是在服务端产生后动态加载过去的。RMIRegistry运行在server端当中。
RMIRegistry 执行流程详解
首先RMIRegistry 运行在server端,RMIRegistry 自身也是一个远程对象。有一点需要注意的是:所有的远程对象(继承了UnicastRemoteObject对象)都会在sever上任意的端口导出自己,因为RMIRegistry 也是一个远程对象,他也在server上导出自己,这个端口是1099。
服务端运行在server上,在UnicastRemoteObject构造函数里面,他把自己导出在server上一个任意端口上,这个端口client是不知道的
当你调用Naming.rebind()的时候,会传入一个CalcImpl 的引用(这里叫做 c)作为第2个参数,Naming 就会构造一个stub对象,详细如下:
a. Naming会使用getClass来获取类的名字,这里就是CalcImpl
b. 加上后缀_Stub 变成了 CalcImpl _Stub
c. 加载CalcImpl_Stub.class到虚拟机中
d. 从c中获取RemoteRef 对象e. 就是这个RemoteRef 对象中封装了服务端细节,包括服务端的hostname、port
f. 获取了RemoteRef 对象之后,就可以构造stub对象了。
g. 传递stud对象到RMIRegistry中进行绑定,即(publicname,stub)
f. RMIRegistry 中内部使用一个hashmap来存储(publicname,stub)当客户端使用 Naming.lookup()的时候,会传入public name 作为参数,RMIRegistry 就会返回stub给客户端调用
这里作者说的导出自己这个没太理解这个的意思,我的理解是映射,将内容映射到1099端口中。
总结:
总体来说就是所以的远程对象都会在server的任意的端口上映射,RMIRegistry 也会进行映射,但是RMIRegistry 映射的端口是1099(默认是,可以修改)。远程对象进行映射的端口,client是不知道的。但是stub对象会知道。
在调用Naming.rebind()并并且传入某一个引用的时候,Naming 就会构造一个stub对象。Naming内部采用getClass来获取类的名字,并且添加_Stub后缀后价值到虚拟机中,然后从引用中获取 RemoteRef 对象,该对象就封装了封装了服务端的细节。而获取到该RemoteRef 就可以构造stub对象了,构造完成后传递到RMIRegistry注册中心中进行绑定,内部采用hashmap键值对的方式,即(publicname,stub),这时候使用Naming.lookup()传入对应的方法名,则会返回对应的stub到client端。
RMIRegistry 存在的意义只是为了方便client获取到stub对象,stub构造函数中需要一个RemoteRef 对象,这个对象只能在server端获取。
本段内容部分摘取自:深入理解rmi原理
0x03 结尾
简单的分析了一下RMI底层的架构,但是这些其实都仅仅是基于概念和理论层面的,具体的代码实现其实还没去看。在其中也是看得晕头转向的,部分也摘取了其他师傅们的文章内容,感觉已经总结很到位了,疯狂安利。摘取的内容下也贴出来 摘取内容的出处,感谢各位师傅们的详细讲解。

Java安全之RMI协议分析的更多相关文章
- Java安全之ysoserial-JRMP模块分析(一)
Java安全之ysoserial-JRMP模块分析(一) 首发安全客:Java安全之ysoserial-JRMP模块分析(一) 0x00 前言 在分析到Weblogic后面的一些绕过方式的时候,分析到 ...
- Java学习---RMI 技术分析[Hessian]
一.什么是Hessian Hessian 是一个基于 binary-RPC 实现的远程通讯 library.使用二进制传输数据.Hessian通常通过Web应用来提供服务,通过接口暴露.Servlet ...
- ref:Java安全之反序列化漏洞分析(简单-朴实)
ref:https://mp.weixin.qq.com/s?__biz=MzIzMzgxOTQ5NA==&mid=2247484200&idx=1&sn=8f3201f44e ...
- Java安全之RMI反序列化
Java安全之RMI反序列化 0x00 前言 在分析Fastjson漏洞前,需要了解RMI机制和JNDI注入等知识点,所以本篇文来分析一下RMI机制. 在Java里面简单来说使用Java调用远程Jav ...
- Java安全之Weblogic 2016-0638分析
Java安全之Weblogic 2016-0638分析 文章首发先知:Java安全之Weblogic 2016-0638分析 0x00 前言 续上篇文的初探weblogic的T3协议漏洞,再谈CVE- ...
- Java 安全之Weblogic 2017-3248分析
Java 安全之Weblogic 2017-3248分析 0x00 前言 在开头先来谈谈前面的绕过方式,前面的绕过方式分别使用了streamMessageImpl 和MarshalledObject对 ...
- Java安全之Weblogic 2018-3248分析
Java安全之Weblogic 2018-3248分析 0x00 前言 基于前面的分析,后面的还是主要看补丁的绕过方式,这里就来简单的记录一下. 0x01 补丁分析 先来看看补丁细节 private ...
- Java安全之SnakeYaml反序列化分析
Java安全之SnakeYaml反序列化分析 目录 Java安全之SnakeYaml反序列化分析 写在前面 SnakeYaml简介 SnakeYaml序列化与反序列化 常用方法 序列化 反序列化 Sn ...
- 协议分析TMP
最近闲来有事, 分析了一个非常低端(非常低端的意思是说你不应该对她是否能取代你现有的QQ客户端作任何可能的奢望,她只是一个实验性的东西)的手机QQ的协议, 是手机QQ3.0, 所用到的TCP ...
随机推荐
- NOI Online #1 入门组 魔法
全网都是矩阵快速幂,我只会倍增DP 其实这题与 AcWing 345. 牛站 还是比较像的,那题可以矩阵快速幂 / 倍增,这题也行. 先 \(Floyd\) 预处理两点之间不用魔法最短距离 \(d_{ ...
- 五、Jmeter的目录结构
进入安装Jmeter可以看到路径 bin目录 jmeter.bat windows的启动文件 jmeter.log jmeter运行日志文件 jmeter.sh linux的启动文件 jmeter. ...
- 为了Java微信支付V3开发包,我找出了微信支付文档至少六个错误
1. 前言 最近忙的一批,难得今天有喘气的机会就赶紧把最近在开发中的一些成果分享出来.前几日分享了自己写的一个微信支付V3的开发包payment-spring-boot-starter,就忙里偷闲完善 ...
- JavaSE15-集合·其二
1.Set集合 1.1 Set集合概述和特点 Set集合的特点 元素存取无序 没有索引.只能通过迭代器或增强for循环遍历 不能存储重复元素 1.2 哈希值 哈希值简介 是JDK根据对象的地址或者字符 ...
- css 01-CSS属性:字体属性和文本属性
01-CSS属性:字体属性和文本属性 #本文重要内容 CSS的单位 字体属性 文本属性 定位属性:position.float.overflow等 #CSS的单位 html中的单位只有一种,那就是像素 ...
- [IOI1994]The Castle
开了博客之后一直没动今天水完题手痒想起这个就来水一篇陈年水题(雾 题目链接<< 题意:给一张n*m个格子的地图信息,求连通块个数以及最大连通块面积. 每个格子四个方向可以有墙,输入用一个十 ...
- 安装nodejs 版本控制器
安装下载地址: https://pan.baidu.com/s/1Ed_IPDTOHxR9NShUEau-ZA 下载好后,放在安装nodejs的文件夹下 然后敲cmd,进入安装nodejs的文件夹下. ...
- Typora+Picgo+Gitee实现上传图片
下载picgo和node.js 百度网盘地址: 链接:https://pan.baidu.com/s/1QwbXn4vFuDfSFNOnZU5-Jg 取码:efgc 打开picgo,安装gitee-u ...
- 30G 上亿数据的超大文件,如何快速导入生产环境?
Hello,大家好,我是楼下小黑哥~ 如果给你一个包含一亿行数据的超大文件,让你在一周之内将数据转化导入生产数据库,你会如何操作? 上面的问题其实是小黑哥前段时间接到一个真实的业务需求,将一个老系统历 ...
- MySQL误删除用户怎么解决
前言:在不考虑到原来用户对关联数据库的授权问题的情况下,有以下两种思路解决 #1.安全模式修改 第一步:关闭数据库服务: [root@db01 ~]#/etc/init.d/mysqld stop 第 ...