【Java小姿势】Log4j2漏洞的前世今生


本文作者: AceCandy
博客原文链接: https://acecandy.cn/archives/Log4j2漏洞的前世今生
版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!

A.源起

2021年12月9日,各大公司都被一个重量级漏洞引爆了,该漏洞一旦被攻击者利用就会造成及其严重的影响。经过快速分析和确认,该漏洞影响范围极其广泛,危害极其严重。然后从10日凌晨开始很多公司的程序员都被迫开始应急相应,加班加点修复问题。该漏洞涉及包含但不限于Struts2、Flink、ElasticSearch、Druid、dubbo、Redis、kafka等常用应用和组件。

爆出这个漏洞的这就是大名鼎鼎的日志组件log4j2 。作为日志组件,在java领域基本上是再常见运用不过的了,而这个漏洞可以让攻击者在使用了log4j组件的服务器上执行任意代码。所以勒索用户和企业还不是分分钟的事,怪不得一众媒体都称漏洞危害堪比“永恒之蓝”了。
在这里插入图片描述

B.Java反序列化RCE

说起log4j漏洞的攻击方式,实际上就是反序列化RCE漏洞,反序列化所造成的被黑客用来攻击的例子可是数不胜数。log4j包括早些年的shiro低版本以及fastjson这些大家都有所耳闻的漏洞,底层原理也与它息息相关,所以得先说说JAVA反序列化RCE(remote command/code execute 远程代码执行)漏洞的一些基础概念:RMI、JRMP、JNDI。

1.RMI

Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。
它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。
Java RMI极大地依赖于接口。在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节。客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。

我们知道一般JAVA方法调用指的是同一个JVM中方法的相互调用。而RMI恰恰相反,简单来说就是跨越JVM调用远程方法。

比如浏览器调用http接口,RMI就是直接调用JAVA方法。

2.JRMP

Java远程方法协议(Java Remote Method Protocol)是特定于Java技术的、用于查找和引用远程对象的协议。这是运行在Java远程方法调用(RMI)之下、TCP/IP之上的线路层协议。

从这个定义可以知道,JRMP是一个协议,用于JAVA RMI调用过程。RMI的过程是通过JRMP这个协议去组织数据格式然后通过TCP进行传输进行的。

还是类比浏览器,http协议就是处于TCP/IP协议之上,通过这个协议,浏览器和服务端才能正常交流通讯。

3.JNDI

Java命名和目录接口(Java Naming and Directory Interface),是Java的一个目录服务应用程序接口(API),它提供一个目录系统,并将服务名称与对象关联起来,从而使得开发人员在开发过程中可以使用名称来访问对象。

目前我们Java中使用最多的基本就是rmi和ldap的目录服务系统。

这就是指在一个目录系统,它实现了把一个服务名称和对象或命名引用相关联,在客户端,我们可以调用目录系统服务,并根据服务名称查询到相关联的对象或命名引用,然后返回给客户端。

所以简单理解JNDI是一个接口,在这个接口下会有多种目录系统服务的实现,我们能通过名称等去找到相关的对象(就像使用key在map中找value),并把它下载到客户端中来。

4.RMI和RPC的区别

说到这里是不是感觉RMI好像做的事和RPC有点像,顺便稍微复习下RPC。

RPC(Remote Procedure Call Protocol)远程过程调用协议,通过网络从远程计算机上请求调用某种服务。

RPC(远程过程调用)和RMI(远程方法调用)是两种可以让用户从一台电脑调用不同电脑上面的方法的的机制(也可以称作规范、协议)。

两者的主要不同是他们的使用方式或者称作范式,RMI使用面向对象 的范式,也就是用户需要知道他调用的对象和对象中的方法;RPC不是面向对象也不能处理对象,而是调用具体的子程序

RMI 能够让在客户端Java虚拟机上的对象像调用本地对象一样调用服务端Java虚拟机中的对象上的方法。

1:方法调用方式不同:

  • RMI中是通过在客户端的Stub对象作为远程接口进行远程方法的调用。每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口(stub)上,那么这个新方法就不能被RMI客户方所调用。
  • RPC中是通过网络服务协议向远程主机发送请求,请求包含了一个参数集和一个文本值,通常形成“classname.methodname(参数集)”的形式。RPC远程主机就去搜索与之相匹配的类和方法,找到后就执行方法并把结果编码,通过网络协议发回。

2:适用语言范围不同:

  • RMI只用于Java;
  • RPC是网络服务协议,与操作系统和语言无关。

3:调用结果的返回形式不同:

  • Java是面向对象的,所以RMI的调用结果可以是对象类型或者基本数据类型;RMI的结果统一由外部数据表示,这种语言抽象了字节序类和数据类型结构之间的差异。

RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一,其实RMI可以直接看作是RPC的Java版本(实现)。传统RPC并不能很好地应用于分布式对象系统,而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。满足了Java“一次编写,处处运行”的美好愿景。

C.如何利用RMI进行攻击

RMI攻击主要分3种目标:RMI Client、RMI Server、RMI Registry。要想理解攻击可能出现在哪块,首先看看RMI的调用流程到底是什么样的。

1.RMI调用流程

使用远程方法调用,必然会涉及参数的传递和执行结果的返回。参数或者返回值可以是基本数据类型,当然也有可能是对象的引用。所以这些需要被传输的对象必须可以被序列化,这要求相应的类必须实现 java.io.Serializable 接口,并且客户端的serialVersionUID字段要与服务器端保持一致。

任何可以被远程调用方法的对象必须实现 java.rmi.Remote 接口,远程对象的实现类必须继承UnicastRemoteObject类。如果不继承UnicastRemoteObject类,则需要手工初始化远程对象,在远程对象的构造方法的调用UnicastRemoteObject.exportObject()静态方法。

// 这里定义了一个继承Remote类的的IHello接口
// 该接口必须在server和client端都存在(且类名、包名都需要一样)
public interface IHello extends Remote {
   
   
    String sayHello(String name) throws RemoteException;
}

// server端需要实现该IHello类,以及对应的sayHello方法
// 另外因为这里没有继承UnicastRemoteObject类,所以是手工在构造方法中调用UnicastRemoteObject.exportObject()初始化了远程对象
public class HelloImpl implements IHello {
   
   
    protected HelloImpl() throws RemoteException {
   
   
        UnicastRemoteObject.exportObject(this, 0);
    }

    @Override
    public String sayHello(String name) throws RemoteException {
   
   
        System.out.println(name);
        return name;
    }
}

在服务端启动一个RMIResgistry,监听在1099这个端口上,并绑定了rmi://127.0.0.1:1099/hello这个路径给远程对象的引用rHello。

public class NormalRmiServer {
   
   

    public static void main(String[] args) throws Exception {
   
   

        IHello rhello = new HelloImpl();
        LocateRegistry.createRegistry(1099);
        Naming.bind("rmi://127.0.0.1:1099/hello", rhello);
        System.out.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AceCandy

期待金主爸爸投喂~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值