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 ...
随机推荐
- Typora入门教程
Typora学习教程 1目录 [TOC]加空格 ,自动生成 目录 1目录 2图片 3下划线 4删除线 5解决语法和内容冲突 6加粗 6.1测试页面跳转 7倾斜 8超链接 9模块 10引用 11表格 1 ...
- 【JSOI2019】精准预测(2-SAT & bitset)
Description 现有一台预测机,可以预测当前 \(n\) 个人在 \(T\) 个时刻内的生死关系.关系有两种: \(\texttt{0 t x y}\):如果 \(t\) 时刻 \(x\) 死 ...
- 题解-洛谷P5217 贫穷
洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...
- css处理文字不换行、换行截断、溢出省略号
1.使文字不换行 white-space: nowrap; 值 描述 normal 默认.空白会被浏览器忽略. pre 空白会被浏览器保留.其行为方式类似 HTML 中的 <pre> 标签 ...
- PHP字符串你不知道的事
PHP常见的定义字符串的方式有那些? 1.单引号 在单引号中,任何特殊字符都会按原样输出[除\.\'将会被转义输出],不是什么都不解析的,这是很多人的误解 echo 'this is a var!'. ...
- vue第二单元(webpack的配置-学习webpack的常用配置)
第二单元(webpack的配置-学习webpack的常用配置) #课程目标 掌握webpack的常用配置 掌握如何根据实际的需求修改webpack的对应配置 了解webpack-dev-server的 ...
- flink连接器-流处理-读写redis
写入redis resultStream.addSink(new RedisSink(FlinkUtils.getRedisSinkConfig(parameters),new MyRedisMapp ...
- Spring Data JPA 整合Spring
1.1 Spring Data JPA 与 JPA和hibernate之间的关系 JPA是一套规范,内部是有接口和抽象类组成的.hibernate是一套成熟的ORM框架,而且Hibernate实现 ...
- 基于SpringBoot+Mybatis+MySQL5.7的轻语音乐网
一个基于SpringBoot+Mybatis+MySQL5.7的轻语音乐网站项目 1.主要用到的技术: 使用maven进行项目构建 使用Springboot+Mybatis搭建整个系统 使用ajax连 ...
- Github标星26k+!一个神奇的软件!1分钟即可打造了一个科幻风格的终端
Github掘金计划项目分类汇总(原创不易,若有帮助,欢迎分享/点赞): 编程基础 :精选编程基础如学习路线.编程语言相关的开源项目. 计算机基础:精选计算机基础(操作系统.计算机网络.算法.数据结构 ...