Apache-NiFi反序列化漏洞(CVE-2023-34212)原理分析
2023-06-30 14:50:00

0x00、前言

Apache-NiFi反序列化漏洞(CVE-2023-34212)原理分析,直接从官网下载binary文件直接启动,docker创建的版本使用java11,会导致jndi注入失败,高版本绕过需要另外的环境依赖,以低版本java环境启动分析。简单来说就是一个单纯的jndi调用,但由于该漏洞需要经过身份验证,相对比较鸡肋,简单分析一下。

0x01、漏洞描述

Apache NiFi 是一个开源的数据流处理和自动化工具, JndiJmsConnectionFactoryProvider 控制器组件用于配置 JMS 连接地址。
Apache NiFi 1.8.0 至 1.21.0 版本中,由于 JndiJmsConnectionFactoryProvider 控制器服务允许已授权的用户配置 URL 和库属性,经过身份验证的攻击者可在 ConnectionFactory 中将 JndiJmsConnectionFactoryProvider 的 JMS 连接地址配置为恶意的 JNDI 服务器,通过反序列化恶意构造的数据远程执行恶意代码。

0x02、漏洞范围

1.8.0 <= Apache Nifi <= 1.21.0

0x03、环境搭建

nifi运行环境:java 1.8.0_66
idea调试环境:java 1.8.0_332(因为会涉及反射相关操作,低版本的java没有对应的源码不便于调试,下文会有说明)

可以直接官网下载运行,其中Binary是直接编译好能运行的,Sources为源码
https://nifi.apache.org/download.html

下载完运行bin目录下的run-nifi.bat启动即可,默认无需更改其它配置

在启动过后,在logs日志文件夹下的nifi-app.log日志文件中可以查看登录账号密码以及启动状态


看到http地址以及服务成功启动则表示正常启动,浏览器访问本地8443端口即可访问nifi服务


调试环境:
编辑conf目录下bootstrap.conf文件,将debug取消注释修改为idea远程debug端口即可


重启nifi服务后,导入nifi源码,idea配置debug后即可连接调试


0x04、漏洞复现

恶意类class:

public class EvilPayload2{
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {
e.printStackTrace();
}
}

public EvilPayload2() throws Exception{
Runtime.getRuntime().exec("calc.exe");
}
public static void main(String[] args) {

}
}

开启ldap服务,设置恶意类

在nifi flow配置添加JndiJmsConnectionFactoryProvider功能组件

JndiJmsConnectionFactoryProvider工件配置jndi属性

ConsumeJMS组件添加JndiJmsConnectionFactoryProvider工件,并随便设置一个Destination Name

启动ConsumJMS,触发jndi调用并执行漏洞


dns请求:

0x05、原理分析

在该漏洞描述中,漏洞原因描述的比较清楚,由于 JndiJmsConnectionFactoryProvider 控制器服务允许已授权的用户配置 URL 和库属性,经过身份验证的攻击者可在 ConnectionFactory 中将 JndiJmsConnectionFactoryProvider 的 JMS 连接地址配置为恶意的 JNDI 服务器,通过反序列化恶意构造的数据远程执行恶意代码。也就是官方提供了一个jndijms的连接服务,可以让下面的组件通过该服务去请求jndi,由于没有对jndi做限制(除java版本限制外),导致jndi远程调用恶意代码触发漏洞。

分析前idea需要导入源码中的nifi-framework-bundle文件夹和nifi-jms-bundle文件夹,JndiJmsConnectionFactoryProvider和ConsumeJMS的相关实现和调用主要就来源这两个文件夹。


接着简单分析源码

JndiJmsConnectionFactoryProvider控制组件提供了jndi调用接口,可配置远程jndi地址

下属组件(ConsumeJMS)可以将JndiJmsConnectionFactoryProvider组件作为配置环境,在启动该组件时调用JndiJmsConnectionFactoryProvider组件的jndi调用接口

代码跟进一下,在用户配置了jndi属性过后,启动JndiJmsConnectionFactoryProvider组件服务,会调用onEabled方法,再将Context配置内容通过调用JndiJmsConnectionFactoryHandler方法传入


配置内容的表字段属性赋值给propertyDescriptors字段

然后再通过自身的一些方法最后启动JndiJmsConnectionFactoryProvider组件服务


接着再看ConsumeJMS组件的调用过程,ConsumeJMS组件配置完JndiJmsConnectionFactoryProvider后,开启ConsumeJMS,其中主要进程进入FlowEngine.wrap方法,当中的run方法启动(查找方式通过执行报错信息逆推调用流程)

调用AbstractProcessor.onTrigger方法,参数为ConsumeJMS组件的所有属性集合的对象context

继续跟进调用buildTargetResource方法

该方法中会通过配置的JndiJmsConnectionFactoryProvider组件进行jndi连接工厂(这里需要稍微高点的java版本这里使用java1.8.0_332,低版本java调试到这过后无法跟进下一步查看准确的执行位置)

调用栈:

invoke:85, StandardControllerServiceInvocationHandler (org.apache.nifi.controller.service)
getConnectionFactory:-1, $Proxy83 (com.sun.proxy)
buildTargetResource:298, AbstractJMSProcessor (org.apache.nifi.jms.processors)
onTrigger:200, AbstractJMSProcessor (org.apache.nifi.jms.processors)
onTrigger:27, AbstractProcessor (org.apache.nifi.processor)
onTrigger:1360, StandardProcessorNode (org.apache.nifi.controller)
invoke:246, ConnectableTask (org.apache.nifi.controller.tasks)
run:102, TimerDrivenSchedulingAgent$1 (org.apache.nifi.controller.scheduling)
run:110, FlowEngine$2 (org.apache.nifi.engine)
call:511, Executors$RunnableAdapter (java.util.concurrent)
runAndReset:308, FutureTask (java.util.concurrent)
access$301:180, ScheduledThreadPoolExecutor$ScheduledFutureTask (java.util.concurrent)
run:294, ScheduledThreadPoolExecutor$ScheduledFutureTask (java.util.concurrent)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:745, Thread (java.lang)

跟进调用StandardControllerServicelnvocationHandler.getConnectionFactory方法,由于该类使用动态代理,因此会先进入invoke方法

该方法主要调用jndiJmsConnectionFactoryProvider组件的类和类加载,以及ConsumeJMS的类加载器,接着调用invoke方法

反射调用jndiJmsConnectionFactoryProvider.getConnectionFactory方法

跟进接着调用lookupConnectionFactory方法

先是从context中获取工厂名

然后初始化上下文

同样从context中获取jndi地址、jndi初始化工厂类等信息

最后获取到上下文后,进行jndi调用,调用lookup方法,触发漏洞


0x06、漏洞修复

将 org.apache.nifi:nifi 升级至 1.22.0 及以上版本,官方已更新最新版本:
官方连接:https://nifi.apache.org/download.html

修复方式:

  • 添加了jndi Schemes限制,只允许JndiJmsProvider调用(file、jgroups、t3、t3s、tcp、ssl、udp、vm)这几个协议,禁止调用rmi、ldap等白名单之外的协议


0x07、参考链接

https://github.com/apache/nifi/commit/3fcb82ee4509d1ad73893d8dca003be6d086c5d6
https://nvd.nist.gov/vuln/detail/CVE-2023-34212