Apache Kylin DiagnosisController.java 命令注入漏洞 CVE-2020-13925

漏洞描述

6月,京东安全的蓝军团队发现了一个 apache kylin 远程命令执行严重漏洞( CVE-2020-13925)。黑客可以利用这个漏洞,登录任何管理员账号和密码默认未修改的账号,获得管理员权限。由于Apache Kylin被广泛应用于企业的大数据分析平台,因此该漏洞将对企业核心数据具有较大的危害,存在数据泄露风险,建议用户尽快升级软件至安全版本。

影响版本

Apache Kylin 2.3.0 ~ 2.3.2
Apache Kylin 2.4.0 ~ 2.4.1
Apache Kylin 2.5.0 ~ 2.5.2
Apache Kylin 2.6.0 ~ 2.6.5
Apache Kylin 3.0.0-alpha

环境搭建

docker pull apachekylin/apache-kylin-standalone:3.0.1

docker run -d \\
-m 8G \\
-p 7070:7070 \\
-p 8088:8088 \\
-p 50070:50070 \\
-p 8032:8032 \\
-p 8042:8042 \\
-p 16010:16010 \\
apachekylin/apache-kylin-standalone:3.0.1

打开后使用默认账号密码admin/KYLIN登录,出现初始界面即为成功

漏洞复现

出现漏洞的代码文件在server-base/src/main/java/org/apache/kylin/rest/controller/DiagnosisController.java

/**
     * Get diagnosis information for project
     */
    @RequestMapping(value = "/project/{project}/download", method = { RequestMethod.GET }, produces = {
            "application/json" })
    @ResponseBody
    public void dumpProjectDiagnosisInfo(@PathVariable String project, final HttpServletRequest request,
            final HttpServletResponse response) {
        try (AutoDeleteDirectory diagDir = new AutoDeleteDirectory("diag_project", "")) {
            String filePath = dgService.dumpProjectDiagnosisInfo(project, diagDir.getFile());
            setDownloadResponse(filePath, response);
        } catch (IOException e) {
            throw new InternalErrorException("Failed to dump project diagnosis info. " + e.getMessage(), e);
        }

    }

这里可以看到{project}参数是用户可控的变量,向下跟进dumpProjectDiagnosisInfo函数

public String dumpProjectDiagnosisInfo(String project, File exportPath) throws IOException {
        aclEvaluate.checkProjectOperationPermission(project);
        String[] args = { project, exportPath.getAbsolutePath() };
        runDiagnosisCLI(args);
        return getDiagnosisPackageName(exportPath);
    }

首先通过checkProjectOperationPermission函数来检查该project是否许可,然后构建一个args的字符串数组,看一下checkProjectOperationPermission函数

public void checkProjectOperationPermission(String projectName) {
       ProjectInstance projectInstance = getProjectInstance(projectName);
       aclUtil.hasProjectOperationPermission(projectInstance);
   }

这里传入projectName,然后通过getProjectInstance来获取项目实例,跟进getProjectInstance

private ProjectInstance getProjectInstance(String projectName) {
        return ProjectManager.getInstance(KylinConfig.getInstanceFromEnv()).getProject(projectName);
    }