Java安全之攻击RMI的思考

总结一下rmi所有的攻击方法,原理,什么是jep290如何绕过,并配套环境以及exp。

阐述如何快速挖掘,一般哪些情况存在漏洞点

参考资料

https://xz.aliyun.com/t/8706

https://blog.0kami.cn/2020/02/06/java/rmi-registry-security-problem/

https://github.com/waderwu/attackRmi 根据具体情况看是否需要魔改

基础知识

什么是RMI&为什么会有这个功能

  • RMI(Remote Method Invoke 远程方法调用)是一个实现了RPC的Java框架。
  • RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。 这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。
  • Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。
  • RMI功能解决的问题:RMI(Remote Method Invocation)是Java语言提供的一种远程调用机制。它允许在不同的Java虚拟机(JVM)上运行的对象之间进行方法调用和数据传输,就像是在同一个JVM中的对象之间进行通信一样。
  • RMI的主要功能是实现分布式计算,让不同的计算节点可以通过网络进行通信和协作。它使得开发人员可以将应用程序的不同部分分布在不同的机器上,以实现更高的可伸缩性和性能。RMI主要有以下几个功能:
    • 远程对象调用:RMI允许在不同的JVM上调用远程对象的方法。这使得开发人员可以在分布式环境下使用面向对象的编程方式,通过调用远程对象的方法来完成相应的功能。
    • 分布式对象传输:RMI可以传输Java对象,并在不同的JVM之间进行序列化和反序列化。在方法调用过程中,参数和返回值都可以是Java对象,使得跨越网络传递数据变得非常方便。
    • 动态类加载:RMI支持动态类加载,即在远程节点上动态加载所需的类文件。这就意味着,在运行时可以通过网络获取相应的类文件,从而实现更灵活的系统设计和扩展性。
    • 透明性:RMI屏蔽了底层的网络细节,使得开发人员可以像调用本地对象一样调用远程对象,这种透明性简化了分布式系统的开发和维护。
  • 示例:这些示例表明了RMI在分布式环境中解决问题的能力,简化了分布式系统的开发和部署。
    • 在一个分布式电商系统中,通过RMI调用远程服务器上的订单管理对象,实现客户端和服务器之间的订单处理和更新。
    • 在一个分布式图像处理系统中,通过RMI将图像数据对象传输给各个节点进行处理,最后将结果返回给主节点,实现并行计算和分布式图像处理。
    • 在一个分布式协同编辑系统中,通过RMI传递文档对象和编辑操作,在不同的节点上实现多人协同编辑功能。

RMI的应用场景

RMI(Remote Method Invocation)是Java中用于实现远程方法调用的机制,它允许在不同的Java虚拟机之间进行通信和交互。RMI的应用场景包括但不限于以下几个方面:

  • 分布式系统:RMI可以用于构建分布式系统,将不同的模块或组件部署在不同的节点上,并通过RMI实现模块之间的远程方法调用。这样可以实现分布式计算、分布式任务处理等。

  • 客户端-服务器应用程序:RMI可以用于实现客户端-服务器架构的应用程序。客户端可以通过RMI调用远程服务器上的方法,实现数据查询、操作、处理等功能。

  • 远程服务:RMI可以用于构建远程服务,提供某种功能或服务给远程客户端使用。例如,远程数据库服务、远程文件存取服务、远程计算服务等。

  • 分布式对象系统:RMI支持分布式对象系统,允许在不同的Java虚拟机之间传递和共享对象。这对于跨越不同主机的对象通信和共享状态非常有用。

  • 分布式事件处理:RMI可以用于实现分布式事件处理系统,在不同的节点之间传递和处理事件。这对于实现分布式通知、消息传递和事件驱动的应用程序很有帮助。

  • 远程监控和管理:RMI可以用于远程监控和管理分布式系统的状态和性能。通过RMI,可以从管理节点监控和管理远程节点的运行状态、配置参数等。

攻击

攻击方式

  • Java反序列化漏洞:
  • 序列化:将java对象转换为字节序列的过程
  • 反序列化:序列化的逆过程,从储存区读出字节序列还原成对象的过程
    Java中的API实现:
  • 位置:Java.io.ObjectOutputStream      
java.io.ObjectlnputStream

序列化:

ObjectOutputStream类-->writeObject()

注:该方法对参数指定的obj对象进行序列化,把字节序列写到一个目标输出流中按Java的标准约定是给文件一个.ser扩展名

反序列化:ObjectInoutStream类-->readObject()

注:该方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。很多Java应用会使用序列化的方式传递数据,应用程序接收用户传入的一个字节序列,将其反序列化恢复为Java对象。

这里,如果Java应用没有对传入的序列化数据进行安全性检查,我们可以将恶意的TransformedMap序列化后,远程提交给Java应用,如果Java应用可以触发变换,即可成功远程命令执行。那如何让Java应用触发Transformer的变换呢?

在进行反序列化时,我们会调用ObjectInputStream类的readObject()方法。如果被反序列化的类重写了readObject(),那么该类在进行反序列化时,Java会优先调用重写的readObject()方法。

结合前述Commons Collections的特性,如果某个可序列化的类重写了readObject()方法,并且在readObject()中对Map类型的变量进行了键值修改操作,并且这个Map变量是可控的,就可以实现我们的攻击目标了。

 什么用法会导致RMI反序列化漏洞

RMI(远程方法调用)反序列化漏洞是一种安全漏洞,它允许攻击者在RMI通信中利用Java对象的反序列化过程进行攻击。导致RMI反序列化漏洞的常见原因之一是未正确验证和处理接收到的反序列化数据。

以下是导致RMI反序列化漏洞的一些常见用法:

  • 不安全的序列化/反序列化实现:使用不安全或过于宽松的序列化/反序列化实现可能会导致RMI反序列化漏洞。例如,使用不受信任的ObjectInputStream类进行反序列化时,攻击者可以通过精心构造的恶意数据来执行任意代码。

  • 未验证反序列化数据:在RMI通信中,接收到的反序列化数据应该经过验证,以确保其完整性和合法性。如果没有正确验证反序列化数据,攻击者可以篡改数据并执行未经授权的操作。

  • 序列化数据的来源不可信:反序列化的数据应该来自可信的来源。如果接收到的数据来自不受信任的来源,就有可能存在安全风险。攻击者可以发送恶意数据来触发反序列化漏洞。

为了防止RMI反序列化漏洞,可以采取以下措施:

  • 使用安全的序列化/反序列化实现:使用经过安全审查和修复的序列化/反序列化库,如Jackson、Gson等,可以减少RMI反序列化漏洞的风险。

  • 对反序列化数据进行验证:在接收到的反序列化数据之前,应该对其进行验证,包括检查数据的完整性、合法性和有效性。可以使用数字签名、消息认证码(MAC)等技术来确保数据的完整性和来源可信。

  • 限制反序列化操作的权限:通过配置安全策略文件,限制RMI服务器执行反序列化操作时的权限,并避免执行不受信任的代码。

RMI反序列化漏洞利用

  • 攻击RMI Client
    • RMI Registry在RMI客户端使用lookup方法的时候,可以实现被动攻击RMI客户端
    • 服务端替换其返回的序列化数据为恶意序列化数据攻击客户端。
  • 攻击RMI Server
    • 客户端把参数的序列化数据替换成恶意序列化数据攻击服务端
  • 攻击RMI Registry
    • RMI客户端使用lookup方法理论上可以主动攻击RMI Registry
    • RMI服务端使用bind方法可以实现主动攻击RMI Registry
  • 可利用函数
    • Bind
    • Rebind
    • Lookup
    • unbind

防御

开发者对于RMI漏洞的修复方法

  • 更新到最新的Java版本:及时更新使用的Java版本,因为Java通常会发布安全补丁来修复已知的漏洞。确保应用程序和服务器上使用的Java版本是最新的,并实施自动更新机制,以便及时获得安全修复。

  • 配置安全策略文件:通过配置安全策略文件,可以限制RMI服务器执行反序列化操作时的权限。在策略文件中,指定允许访问和执行的代码路径,并限制RMI服务器对不受信任的代码的访问。这样可以减少潜在的攻击面。

  • 实现自定义的ObjectInputFilter:自Java 9起,引入了ObjectInputFilter接口,可以用于过滤不受信任的类和限制反序列化操作。通过实现自定义的ObjectInputFilter,可以定义特定的反序列化策略,对输入流中的类进行验证和过滤。

  • 使用安全的序列化/反序列化库:选择经过安全审查和修复的序列化/反序列化库,如Jackson、Gson等,来代替Java默认的序列化机制。这些库通常实现了额外的安全措施,可以降低RMI漏洞的风险。

  • 审查和修复现有代码:审查应用程序中的代码,特别是涉及到RMI通信和反序列化的部分。查找潜在的漏洞,并修复存在的安全问题。确保对接收到的反序列化数据进行正确的验证和处理。

  • 安全测试和漏洞扫描:进行安全测试和漏洞扫描以发现潜在的RMI漏洞。使用专业的安全工具和服务,对应用程序进行渗透测试和代码审计,以识别和修复可能存在的漏洞。

现有防御方式

  • 黑/白名单
  • JEP290
    • JDK6 6u141
    • JDK7 7u131
    • JDK8 8u121

防御绕过

  • Bypass JEP290:JEP290 是 Java 底层为了解决反序列化攻击所提出的一种方案
  • 修改数据包:攻击者可以尝试修改传输的数据包,其中包含了反序列化数据。他们可能篡改或伪造数据以绕过验证和过滤机制。为了防止这种情况,应使用安全的传输协议(如TLS)对数据进行加密和完整性保护。
  • 绕过安全策略:攻击者可能尝试绕过安全策略文件中定义的限制和规则。他们可以尝试执行未经授权的操作或利用安全策略文件中的任何漏洞。为了防止这种情况,确保安全策略文件是正确配置的,并进行定期的安全审查。
  • 利用未知漏洞:尽管许多已知的RMI漏洞已得到修复,但仍可能存在未知的漏洞。攻击者可能会利用这些未知漏洞,以执行未经授权的操作。为了防止这种情况,定期更新和升级应用程序、库和Java版本,以便获取最新的安全补丁。
  • 使用自定义的反序列化机制:攻击者可能尝试利用自定义的反序列化机制,绕过常用的序列化/反序列化库。他们可以构造特殊的数据格式或利用序列化漏洞,绕过安全检查和过滤机制。为了防止这种情况,使用经过安全审查和广泛测试的序列化/反序列化库,并及时更新到最新版本。
  • 社会工程和钓鱼攻击:攻击者可能通过社会工程技术或诱骗用户提供敏感信息,从而绕过RMI漏洞的防御措施。这可能包括欺骗用户点击恶意链接、下载恶意附件或揭示敏感凭据。为了防止这种情况,加强用户教育和安全意识培训,并使用反钓鱼技术和安全策略来防范社会工程攻击。

工具

  • https://github.com/waderwu/attackRmi
  • ysoserial:ysoserial是一个开源的Java反序列化漏洞利用工具,它能够帮助安全研究人员测试和验证应用程序中的反序列化漏洞。

  • JavaDeserializationExploits:这是一个包含多个Java反序列化漏洞利用工具的项目,其中包括一些常见的反序列化漏洞利用Payload。

  • Metasploit:Metasploit是一款功能强大的渗透测试工具,它也提供了一些用于利用反序列化漏洞的模块。通过Metasploit,攻击者可以方便地利用已知的反序列化漏洞进行攻击。

  • Burp Suite:Burp Suite是一款广泛使用的Web应用程序安全测试工具,它包含了一些用于检测和利用反序列化漏洞的模块。

这些工具的使用应该遵循合法合规的原则。安全研究人员和专业人士可以使用这些工具来评估应用程序的安全性并提供相应的修复建议,而非用于进行非法的攻击行为。同时,开发人员和系统管理员也应该在开发和部署过程中注意预防和修复反序列化漏洞,以确保应用程序的安全性。

CTF

在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。

在CTF(Capture The Flag)比赛中,反序列化漏洞是一个常见的挑战类别,也是一项重要的技术。

常见的反序列化相关的CTF挑战:

  • 反序列化漏洞利用:在这种挑战中,会给出一个包含反序列化漏洞的应用程序,并要求参赛者通过构造恶意的序列化数据来实现代码执行或获取特定的目标信息。

  • 修改序列化数据:这个挑战要求参赛者修改给定的序列化数据,以达到特定的目标,比如更改对象属性、修改控制流等。

  • 反序列化漏洞检测:在这种挑战中,参赛者需要分析给定的代码或二进制文件,发现其中潜在的反序列化漏洞,并提供相应的修复方案。

在CTF过程中,利用反序列化漏洞的关键在于理解目标应用程序的反序列化逻辑和漏洞利用原理。通常,攻击者可以通过以下步骤来利用反序列化漏洞胜利:

  • 分析目标应用程序:仔细研究目标应用程序的代码和功能,尤其是涉及到反序列化的部分。了解应用程序使用的反序列化框架和相关的类和方法。

  • 寻找潜在的漏洞点:通过代码审计或动态调试等手段,查找应用程序中可能存在的反序列化漏洞点。这些漏洞点通常是未正确验证或处理用户提供的序列化数据的地方。

  • 构造恶意的序列化数据:根据漏洞点的特点,构造针对性的恶意序列化数据,以实现攻击者的目标。例如,可能需要构造一个触发代码执行的序列化对象。

  • 利用漏洞实现攻击目标:将恶意序列化数据发送给目标应用程序,触发反序列化并利用漏洞实现攻击目标。这可能包括执行任意代码、获取敏感数据、绕过访问控制等操作。

需要注意的是,在CTF比赛中,参赛者需要遵循比赛规则和道德准则,不得利用漏洞进行非法的攻击行为。参赛者应该将重点放在学习和实践安全技术,为了促进网络安全和个人成长而参加比赛

RealWorld

CVE-2021-26295 Apache OFBiz rmi反序列化漏洞

  • https://fengchenzxc.github.io/%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%BC%8F%E6%B4%9E/Apache/Apache%20OFBiz/Apache%20OFBiz%20RMI%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%20CVE-2021-26295/

学习过程中可能会遇到的疑问及解答

RMI JRMP JNDI LDAP等概念辨析

  • LDAP:轻量目录访问协议,英文全称是Lightweight Directory Access Protocol
  • RMI:远程方法调用(行为)
  • JRMP:Java远程方法协议(数据协议)
    • RMI数据传输协议
  • JNDI:Java命名和目录接口(接口)
    • 基于RMI
    • 基于LDAP
    • 有多种目录系统服务的实现,我们能通过名称等去找到相关的对象,并把它下载到客户端中来
  • 参考资料
    • https://xz.aliyun.com/t/7079
    • https://xz.aliyun.com/t/7264

为什么用InitialContext lookup一个JNDI的RMI、LDAP服务会导致自身被反序列化RCE?

使用InitialContext来查找JNDI(Java Naming and Directory Interface)服务时,可能存在一些安全风险,导致自身受到反序列化远程代码执行(RCE)攻击。这主要是由于以下原因:

  • 对象的反序列化:InitialContext在查找JNDI服务时,可能会将接收到的数据进行反序列化。反序列化是将二进制数据转换为Java对象的过程。如果攻击者能够控制传递给InitialContext的反序列化数据,他们可以构造恶意对象,以触发远程代码执行。

  • 反序列化漏洞:在Java中,反序列化操作涉及到反序列化器。如果使用了不安全的反序列化器或存在反序列化漏洞,攻击者可以通过构造特殊的反序列化数据来执行恶意代码。例如,攻击者可以在反序列化数据中包含恶意类或利用已知的反序列化漏洞。

  • JNDI服务的安全配置:JNDI服务本身可能存在安全配置不当的问题,使得攻击者可以注入恶意对象或执行恶意操作。如果攻击者能够修改或篡改JNDI服务的响应,他们可以引导InitialContext返回恶意的对象,并触发后续的反序列化攻击。

为了防止此类攻击,可以考虑以下几点:

  • 使用安全的序列化/反序列化机制:选择经过安全审查和修复的序列化/反序列化库,以代替Java默认的序列化机制。这些库通常实现了额外的安全措施,可以降低反序列化漏洞的风险。

  • 限制反序列化操作的权限:合理配置安全策略文件,限制反序列化操作的权限,并对反序列化数据进行验证和过滤。通过实现自定义的ObjectInputFilter,可以定义特定的反序列化策略,对输入流中的类进行验证和过滤。

  • 更新和升级相关组件:及时更新应用程序中使用的框架、库和依赖组件,以获取最新的安全补丁和修复。这包括Java运行时环境、JNDI服务提供者和相关的第三方库。

  • 加强网络安全措施:采取网络隔离、访问控制和安全监控等措施,限制对JNDI服务的访问,并检测异常行为和潜在的攻击。

为什么Registry bind暴露一个服务对象到RmiRegistry会导致Registry服务自身被反序列化RCE?

使用Registry.bind()将一个服务对象绑定到RMI注册表(RmiRegistry)可能导致RMI注册表服务自身受到反序列化远程代码执行(RCE)攻击。这主要是由于以下原因:

  • 对象的反序列化:当调用Registry.bind()将服务对象绑定到RMI注册表时,服务对象需要进行序列化操作,以便在RMI注册表上进行传输和存储。在远程客户端请求服务对象时,RMI注册表会将接收到的序列化数据进行反序列化。如果攻击者能够控制传递给RMI注册表的反序列化数据,他们可以构造恶意对象,从而触发远程代码执行。

  • 反序列化漏洞:在Java中,反序列化操作涉及到反序列化器。如果使用了不安全的反序列化器或存在反序列化漏洞,攻击者可以通过构造特殊的反序列化数据来执行恶意代码。例如,攻击者可以在反序列化数据中包含恶意类或利用已知的反序列化漏洞。

  • RMI注册表的安全配置:RMI注册表本身可能存在安全配置不当的问题,使得攻击者可以注入恶意对象或执行恶意操作。如果攻击者能够修改或篡改RMI注册表的响应,他们可以引导RMI客户端返回恶意的对象,并触发后续的反序列化攻击。

为什么使用JRMP能互相对打?

JRMP(Java Remote Method Protocol)是Java远程方法调用协议,它允许在不同的Java虚拟机之间进行远程方法调用。然而,JRMP协议本身并不会导致互相对打的情况。互相对打通常发生在存在安全漏洞的应用程序或网络环境中,可能与以下因素有关:

  • 可信任的网络环境:JRMP协议主要设计用于在受信任的网络环境中进行远程方法调用。如果在非受信任的网络环境中使用JRMP协议,并且未采取适当的安全措施,攻击者可能能够窃取、篡改或伪造通信数据,从而导致互相对打的情况。

  • 安全配置不当:在配置和使用JRMP时,如果相关组件(例如RMI注册表、RMI服务等)的安全性配置不当,可能会导致安全漏洞的出现。攻击者可以利用这些漏洞来触发恶意操作,进而导致互相对打的情况。

  • 缺乏身份验证和授权:JRMP支持基于用户名/密码的身份验证和访问控制机制。如果应用程序在远程调用过程中没有正确实施身份验证和授权机制,攻击者可能会伪造身份或越权操作,导致互相对打的情况。

为了防止互相对打的情况发生,可以考虑采取以下安全措施:

  • 使用安全的网络通信:将JRMP限制在受信任的网络环境中,例如使用虚拟专用网络(VPN)或防火墙来隔离不信任的网络。

  • 实施加密和完整性保护:使用安全的传输层协议(如TLS/SSL)对JRMP通信进行加密,以确保数据的机密性和完整性。

  • 强化身份验证和授权机制:在应用程序中实施适当的身份验证和授权控制,确保只有授权用户能够进行远程方法调用。

  • 配置安全策略:合理配置相关组件的安全策略文件,限制访问权限,以防止未经授权的操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值