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{ |
开启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) |
跟进调用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