JNDI注入加RMI联合攻击并log4j2漏洞复现
2023-4-26 20:25:0 Author: xz.aliyun.com(查看原文) 阅读量:22 收藏

Java Naming and Directory Interface ​

java命名和目录接口

让配置参数和代码 解耦的规范或思想

例,使用mysql数据库的语言,当需要更换其他数据库(本质就是更改配置文件),却又不想改代码,就需要JNDI

是我们的数据更加 : 低耦合,高内聚

Name

java对象通过命名绑定到容器环境

我们可以将java对象和一个特定的名称关联到一起

Directory

将一个对象的所有的属性信息保存在一个容器环境

context.xml

DbUtil.java

Remote Method Invocation Java远程方法调用

实现java程序之间jvm的远程通信

JVM代表Java虚拟机(Java Virtual Machine),是一种能够在不同平台上运行Java程序的虚拟计算机。它是Java平台的核心组件之一,负责将Java字节码翻译成特定平台上的机器指令,并管理程序的执行。

Java程序员编写的代码首先被编译成Java字节码,然后由JVM解释和执行。这种设计使得Java程序可以跨平台运行,而无需修改代码。JVM还提供了许多高级功能,如垃圾回收、动态加载、安全管理和调试支持,使得Java编程变得更加方便和高效。

例:

某个复杂计算

一台计算机需要很久

如果这台计算机支持RMI调用

则可以分配任务到远程计算机

基本逻辑

分为三部分

Server 服务端 提供远程的对象

Client 客户端 调用远程的对象

Regist 注册 存放远程对象的位置,包括 IP 端口 标识符

演示代码

首先建立一个这样的项目

Exp.java

RMITest.java(这是一个接口)

RMIServer.java

RMIClient.java

RMITestTmpl.java

客户端通过lookup方法,找绑定的恶意类

  • 远程对象有恶意方法,可以直接调用
  • 远程对象有可利用的readObject方法,可以传输Object参数(仅限Object类型的参数),实现反序列化攻击

演示

服务端源码

客户端代码示例

远程仓库(自建)

在本地测试环境中,可以利用phpstudy在本地建立仓库使用
但是在测试的时候要删除项目目录中的payload.java
否则rmi不会再去链接本地仓库

原理

客户端通过lookup()方法,注入了rmi协议,访问了远程的rmi服务器

rmi服务器返回了引用对象,而引用对象包含了类的加载工厂

如果本地没有这个类,就去加载工厂加载类的字节码

而加载工厂是本地的localhost的80端口,目录下有payload.class文件

客户端再去访问localhost的80端口,去下载payload.calss的字节码

然后Class.forName加载了这个字节码

造成了payload.class这个类里面的静态代码被执行

log4j RCE的攻击角色

  1. 在客户端的日志中,插入了jndi语句,造成了jndi注入
  2. 客户端向远程恶意rmi服务器请求远程对象,返回引用对象
  3. 引用对象里面要执行的类,需要从类工厂中获取,而类工厂中,类定义在另一个恶意的vps中
  4. 客户端的jvm向恶意的yvps请求恶意类的字节码文件 payload.class
  5. 远程下就后,使用class.forname类似方法,载入到客户端的虚拟机中
  6. 执行了恶意类的静态方法

利用

需要一个恶意的rmi服务器

在这段代码中,我们创建了一个名为 "payload" 的 Reference 对象,这个对象可以被用于注入恶意代码。接下来,我们将该对象包装在一个 ReferenceWrapper 中,使其可以实现远程接口。最后,我们将该包装对象绑定到了 RMI 注册表的 "hello" 名称上,从而使得该服务可以被远程客户端调用。当客户端调用该服务时,ReferenceWrapper 对象会被反序列化并执行其中的恶意代码,从而实现攻击。

实施JNDI注入

攻击者需要将恶意的Log4j日志信息发送到目标服务器,使得目标服务器解析该日志信息并发起JNDI连接请求。攻击者可以利用JNDI注入攻击获得对目标服务器的控制。

攻击者可以通过向目标服务器发送经过精心构造的日志信息来实现JNDI注入攻击。攻击者可以构造一个包含JNDI URL的恶意日志消息,将其发送到目标服务器的Log4j日志中,当目标服务器解析该日志消息时,它会尝试创建JNDI连接并执行JNDI操作。攻击者可以通过JNDI连接获得对目标服务器的控制,例如读取敏感数据、执行恶意代码等。

攻击者可以通过多种方式将恶意日志消息发送到目标服务器。例如,攻击者可以通过网络发送带有恶意负载的HTTP请求或SMTP邮件,或者通过在已被入侵的服务器上运行恶意代码生成日志消息并将其发送到目标服务器。攻击者也可以伪造源IP地址,使得日志消息看起来像是来自可信来源。

需要一个http公网服务,能够以下载字节码

http://localhost"是将创建的 Reference 对象的 factoryClassLocation 属性设置为本地主机地址的URL。这是因为在进行JNDI注入攻击时,攻击者将利用被攻击方的服务器上的JNDI服务来绑定恶意的引用对象,然后再通过远程调用执行恶意代码。在这种情况下,由于攻击者和被攻击方在不同的主机上,所以需要使用可公开访问的IP地址或域名作为 factoryClassLocation 属性的值,以便攻击者可以从远程访问它。但是在本地测试环境中,可以将 factoryClassLocation 属性设置为本地主机地址的URL(如"http://localhost"),以方便进行测试和调试。

factoryClassLocation

factoryClassLocation属性是InitialContext类的一个可选属性,它指定了用于创建InitialContext对象的工厂类的位置。如果没有设置该属性,则会使用默认的工厂类。工厂类是一个实现了javax.naming.spi.InitialContextFactory接口的类,用于创建InitialContext对象。factoryClassLocation属性的值是指定工厂类的位置的字符串。

在使用JNDI(Java命名和目录接口)时,通常需要使用InitialContext对象来连接到JNDI服务提供者,并在命名和目录服务中查找或存储对象。在创建InitialContext对象时,需要指定JNDI提供者的名称或URL,以及可能的上下文工厂和URL工厂。如果没有指定上下文工厂和URL工厂,则默认使用JNDI实现提供的工厂。如果需要使用自定义的工厂,则需要设置factoryClassLocation属性来指定工厂类的位置。

factoryClassLocation 属性用于指定 RMI 客户端在远程调用时从哪里加载远程对象的类定义。如果此属性被设置为恶意的远程代码库的位置,那么客户端将会从该位置下载并执行该代码库中的字节码,从而受到攻击。因此,如果 RMI 服务端无法保证其提供的远程对象的安全性,那么最好不要在客户端上设置 factoryClassLocation 属性,或者只允许从受信任的代码库加载类定义。

需要一个包含恶意代码的类文件字节码 可以是任意类

用static{}包裹·即可在虚拟机加载类字节码后自动执行

条件

被攻击者(客户端)存在有漏洞的log4j版本

被攻击者(客户端)可以出网(或者攻击端与被攻击端处在同一个内网)


文章来源: https://xz.aliyun.com/t/12490
如有侵权请联系:admin#unsafe.sh