Apache Kylin CVE-2022-43396&CVE-2022-44621分析

前言:年前看的这个,被CVE-2022-44621狠狠坑了,找了快一周的利用路径最终得出无法利用的结果

CVE-2022-43396

漏洞概述

Apache Kylin™是用于大数据的开源,分布式分析数据仓库;它旨在提供大数据时代的OLAP(在线分析处理)功能。通过在Hadoop和Spark上革新多维多维数据集和预计算技术,无论数据量如何增长,Kylin都能实现接近恒定的查询速度。Kylin将查询延迟从几分钟减少到亚秒级,将在线分析重新带回大数据。
Apache Kylin命令注入漏洞,该漏洞是历史漏洞CVE-2022-24697的黑名单修复绕过,恶意用户可以通过控制conf的kylin.engine.spark-cmd参数来执行命令,漏洞编号为CVE-2022-43396

漏洞版本

该漏洞在以下版本被修复:
Kylin >= 4.0.3

漏洞分析

根据漏洞补丁定位到github中修复处
https://github.com/apache/kylin/pull/2011/commits/418a63c61379d429312972fc94b87994e06b664f

可以看到漏洞修复方式是在NsparkExecutable.java中去掉了sparkSubmitCmd参数从KylinconfigBase.java的getSparksubmitCmd方法中取值的代码,并且在KylinconfigBase.java中去掉了getSparksubmitCmd
从漏洞描述中可知该漏洞是CVE-2022-24697的绕过,而CVE-2022-24697最终触发漏洞是在CliCommandExecutor中的runNativeCommand方法中,回顾apache kylin的所有历史命令执行漏洞会发现,所有漏洞的最终触发点均是在此处。
在CliCommandExecutor的runNativeCommand中打上断点,先随便使用touch /tmp/kylin_rce执行命令来调试流程

可以看到带入到CliCommandExecutor的execute方法中的cmd参数是在runSparkExecutable类中的runSparkSubmit方法中通过调用同类的generateSparkCmd方法获得的
进入到generateSparkCmd方法调试流程,其中sparkSubmitCmd参数来自于config.getSparkSubmitCmd
config.getSparkSubmitCmd返回值正是编辑配置时传入的kylin.engine.spark-cmd参数的值touch /cmd/kylin_rce

sparkSubmitCmd参数值touch /cmd/kylin_rce在418行处拼接到aliasedJar参数return,赋值给runSparkSubmit的cmd参数

接着cmd参数带入CliCommandExecutor的excute方法中,excute方法又调用runNativeCommand方法,最终在runNativeCommand方法中带入ProcessBuilder.start中命令执行

以上流程就是kylin.engine.spark-cmd的值被带入cmd参数中并最终在CliCommandExecutor中的runNativeCommand方法中命令执行的过程
然而由于我们使用的docker环境只有apache kylin 4.0.0版本,而该docker环境并未包含对CVE-2022-24697的修复,查看CVE-2022-24697的修复代码
https://github.com/apache/kylin/pull/1811/commits/bd1b6028b8374d38e6968b7ee8b7c16213334bf0#diff-0bbd2aecd8516a4a43475f99cbc29fd17bdd76c9bc01def796cdf5bc745d1ee8R24
可以看到CVE-2022-24697修复的代码中对所有config的key和value均调用了ParameterFilter.checkSparkConf

查看ParameterFilter.checkSparkConf,可以看到其实现就是对config的key和value做了黑名单,不允许出现SPARK_CONF_REGULAR_EXPRESSION中定义的几个特殊字符

那么就意味着我们不能使用来执行命令,回顾前面的调试流程会发现touch /tmp/kylin_rce`被注入的位置是在&&之后,那么就意味着其实并不需要反引号来执行命令
而直接插入touch /tmp/kylin_rce会报错unrecognized option '--class'
只需在touch /tmp/kylin_rce 后加入--将后续的--class 等参数当作文件名来处理即可成功执行命令且绕过CVE-2022-24697的黑名单

漏洞复现

根据官方文档安装apache kylin 4.0.0 docker环境https://kylin.apache.org/docs/install/kylin_docker.html

docker pull apachekylin/apache-kylin-standalone:4.0.0
docker run -d --name kylin -m 8G -p 7070:7070 -p 8088:8088 -p 50070:50070 -p 8032:8032 -p 8042:8042 -p 5005:5005 -p 2181:2181 apachekylin/apache-kylin-standalone:4.0.0

配置远程调试
编辑/home/admin/apache-kylin-4.0.0-bin-spark2/conf/setenv.sh,增加如下代码

export KYLIN_DEBUG_SETTINGS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

环境运行成功后在访问http://127.0.0.1:7070/kylin/login
使用默认密码ADMIN/KYLIN登录系统
在model处选择一个cube编辑,在Configuration Overwrites处填写Kylin Properties如下

保存配置后选中Actions中的build

查看docker环境可以看到命令已经成功执行

修复方案

Kylin 2.x & Kylin 3.x & 4.x 的用户应升级到4.0.3或应用补丁以修复漏洞,补丁获取链接:
https://github.com/apache/kylin/pull/2011

CVE-2022-44621

分析

根据漏洞补丁定位到github中修复处
https://github.com/apache/kylin/pull/2011/commits/418a63c61379d429312972fc94b87994e06b664f

可以看到针对CVE-2022-44621的修复方式是在DiagnosisController中的dumpJobDiagnosisInfo方法中对jobId参数做了过滤,关于dumpJobDiagnosisInfo方法中的JobId会被带入到在CliCommandExecutor中的runNativeCommand中这一事实其实早在CVE-2020-13925中就提到过
https://www.freebuf.com/vuls/243541.html

然而跟踪流程就会发现,jobId虽然看似是从http请求中传入,但其实根本无法控制
查看dumpJobDiagnosisInfo的代码,调用this.dgService.dumpJobDiagnosisInfo

跟到dumpJobDiagnosisInfo可以看到,把传入的jobId带入到Jobservice的getJobInstance方法,如果返回的jobInstance为null则抛出异常,而这一步如果传入自定义的JobId就会因为找不到JobInstance抛出异常

那么再来看看生成JobId的部分是否可以被控制,经过动态调试和代码分析发现,构建Job的地方有两个
第一个是在NsparkCubingJob的create方法,对应的是前端对cube的build操作
在构建时首先调用第一个create方法,然后在此处可以看到调用UUID.randomUUID().toString()生成一串随机字符串带入到第二个create方法中并作为JobId参数,也就是说JobId为随机生成的字符串

第二个是NSparkMergingJob的merge方法,对应的是前端对cube的merge操作,同样可以看到JobId为随机生成的字符串

只有传入数据库中已有的随机字符串JobId才能使Jobservice的getJobInstance不返回null从而流程继续直到拼接到CliCommandExecutor中的runNativeCommand的cmd中,而传入随机字符串JobId当然无法命令注入,所以该漏洞并不能被利用

posted @ 2023-02-24 17:17  Escape-w  阅读(560)  评论(0编辑  收藏  举报