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

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

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

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
spark-rpc-stream-unauth — Apache Spark 4.2.0 - 高危 - 远程 - 文件读取 - 未认证 RPC StreamRequest 文件合并 | Kitploit
工具/GitHubGitHub/abraxas/spark-rpc-stream-unauth
漏洞分析漏洞利用Web应用程序漏洞利用信息收集网络安全渗透测试论文与研究实验室与实践
GitHubabraxas/spark-rpc-stream-unauth

spark-rpc-stream-unauth

Apache Spark 4.2.0 - 高危 - 远程 - 文件读取 - 未认证 RPC StreamRequest 文件合并

查看仓库
82天前尚未审核

最受欢迎

查看全部 →

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

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

Abraxas Labs - spark-rpc-stream-unauth

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  spark-rpc-stream-unauth

spark-rpc-stream-unauth

类别: 权限残留 / 文件读取 可达性: 远程

Apache Spark 4.2.0 (32f72996) - Apache Software Foundation

CVE-2020-9480 关闭了 RPC 控制平面上未认证的 RequestSubmitDriver / RegisterApplication。AbstractAuthRpcHandler 对 receive() 和 receiveStream() 进行了门控。它没有对 getStreamManager() 进行门控。TransportRequestHandler 仍然在 SASL 之前将 StreamRequest 分发到该管理器上。NettyStreamManager.openStream 执行 new File(dir, fname),没有做保持在根目录下的检查。

未认证的 StreamRequest classes/../../path 可读取 Spark-UID 文件。 Unix 绝对路径子项仍保持在注册目录下(实验环境 404)。files/ 是 map 查找(404)。receive() / receiveStream() 保持 401。这不是 9480 RCE。

ID暂无 CVE
类别权限残留 / 文件读取(CVE-2020-9480 未门控的 RPC 数据平面残留)
可达性远程(未认证 TCP 连接到启用了 spark.authenticate=true 的 driver RpcEnv / ESS / BlockManager)
CWECWE-862、CWE-22
CVSS高危:7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
产品Apache Spark
受影响版本4.2.0(32f7299601108917fb01920a54e084595b7b3bf8)。需运维启用 spark.authenticate=true。主机文件读取需要已注册的目录(spark.repl.class.outputDir 的 /classes 和/或 Connect 的 artifacts)。
认证StreamRequest / getStreamManager() 上无认证
许可证GNU Affero GPL v3.0
实验环境仅 127.0.0.1

攻击者能做什么

TCP 连接到启用了 spark.authenticate=true 且已注册目录的 Spark RPC 端口。无需共享密钥。无需 spark.network.crypto.enabled。发送传输层 StreamRequest(消息类型 6),streamId 为 classes/../../<path>。TransportRequestHandler.processStreamRequest 从不调用 RpcHandler.receive。它调用 getStreamManager().openStream。9480 的包装器返回真实的管理器。new File(dir, "../../oracle/secret") 规范化后位于 REPL/artifact 根目录之外,并作为 FileSegmentManagedBuffer 返回。

这就是以 Spark UID 身份进行的主机文件读取。它不是作业提交。它不是 RequestSubmitDriver。它不是 shell。

机密性(实验环境已验证)

方法汇聚点权限
未认证 StreamRequest classes/../../<path>NettyStreamManager.openStream 的 new File(dir, fname) 然后 FileSegmentManagedBuffer读取 driver 能打开的 Spark-UID 文件。实验环境已验证:opened /opt/repl-classes/../../oracle/secret,规范化路径 /oracle/secret,内容 SPARK-RPC-STREAM-UNAUTH-WITNESS,x-auth-gated=false,x-authenticated=false。
未认证 StreamRequest classes/hello.txt(目录内对照)相同的拼接,保持在注册目录下读取实际位于 /classes 下的文件。实验环境已验证 200 IN-DIR-OK,无见证字符串。确认即使对于受限名称,文件服务器也能在没有 SASL 的情况下工作。

机密性(推断)

方法汇聚点权限
未认证 ChunkFetchRequest / StreamRequest 针对活跃 ESS streamIdOneForOneStreamManager.getChunk / openStream。当 client.getClientId() == null 时 checkAuthorization 跳过读取其他应用正在进行的 shuffle / disk-RDD 字节。可用性:排空会推进 curChunk。需要活跃的 streamId(随机起始,然后 +1)。Gadget 未与活跃 ESS 通信。
未认证 MergedBlockMetaRequestAbstractAuthRpcHandler.getMergedBlockMetaReqHandler() 同样未门控当 ESS 有合并 shuffle 时,读取所选 appId 的合并 shuffle 块位图。同样的 null-clientId 跳过。未实际测试。

在此残留上已关闭(实验环境已验证)

方法汇聚点保持关闭
未认证 StreamRequest classes//oracle/secret(Unix 绝对路径子项)new File(dir, "/oracle/secret")404。打开的路径是 /opt/repl-classes/oracle/secret。Unix 的 File 会拼接;它不会忽略父路径。声称绝对路径子项会丢弃根目录的说法在 Unix 上是错误的。
未认证 StreamRequest files//oracle/secretfiles map 查找404。files/ 和 jars/ 是基名查找,不是拼接。
未认证 receive() / OneWayMessageAbstractAuthRpcHandler.receive401 Unauthenticated call to receive(). x-auth-gated=true。
未认证 receiveStream() / UploadStreamAbstractAuthRpcHandler.receiveStream401 Unauthenticated call to receiveStream().
已认证 receiveStream() 使用实验环境密钥doAuthChallenge 之后的相同门控200 receiveStream-ok。对照验证密钥仍能打开 9480 路径。

实验环境已验证 vs 推断: 未认证 .. 文件读取、Unix 绝对路径 404、files/ 404、门控的 receive / receiveStream 均为实验环境验证。ESS shuffle 排空为推断。

相邻已关闭(不要夸大):

  • CVE-2020-9480 RCE 路径:通过 OneWayMessage / UploadStream / RpcRequest 的未认证 RequestSubmitDriver / RegisterApplication。仍需要共享密钥。
  • 默认 spark.authenticate=false 下的未认证 shuffle 和作业提交(SECURITY.md FAQ,文档化的可信网络默认值)。不是此残留。
  • 已认证应用 A 获取应用 B(AppIsolationSuite / SPARK-57889 非 null clientId)。
  • CVE-2021-38296 握手密钥恢复。
  • CVE-2025-55039 中等 CTR 默认值。
  • 独立 master RpcEnv 通常没有注册 /classes 或 artifacts,因此此主机文件遍历是 driver / REPL / Connect,而非 master:7077。
  • 不执行文件。不写入。不导出 spark.authenticate.secret。

我是如何发现的

我固定了 apache/spark v4.2.0(32f7299601108917fb01920a54e084595b7b3bf8),不是 master,也不是 4.3 RC。二十八次源码搜寻。开放集群上的作业提交是设计使然。ML 模型加载是可执行代码。公开的 Jackson History RCE、UI id -Gn shell、PySpark 本地模拟以及 9480 接收路径在此剥离版本上均已关闭。

RPC 认证搜寻本应是对 9480 的重新归档检查。AuthServerBootstrap 仍然包装了处理器。未认证 receive 仍然抛出异常。然后我读了 getStreamManager()。三行。它返回委托。TransportRequestHandler.handle 将 StreamRequest 路由绕过 receive。默认的 StreamManager.checkAuthorization 是空操作。SPARK-57889 在 StreamRequest 上添加了字符串 ID 检查,并保留了 ESS 用于"认证关闭"的 null-clientId 跳过,这同时也是"此连接从未认证"。

当设置了 spark.repl.class.outputDir 时,SparkContext 注册 /classes。Connect 的 ArtifactManager 注册 artifacts。NettyStreamManager.openStream 拆分 ftype/fname。非 files/jars 类型执行 new File(dir, fname),没有规范化前缀检查。

记录一个错误方向,因为它浪费了一天的搜寻信心:JavaDoc 说绝对路径子项会忽略父路径。在 Unix 上,UnixFileSystem.resolve 会拼接。new File("/opt/repl-classes", "/oracle/secret") 是 /opt/repl-classes/oracle/secret。实验环境 404。高危路径是 classes/../../oracle/secret。

作秀:声称这是 9480 RCE。控制平面仍然被门控。预言机只是 Spark UID 已经能读取的文件中的一个见证字符串。

实验环境

固定源码的 Gadget(AbstractAuthRpcHandler.java:52-87、NettyStreamManager.scala:54-70)。HTTP 是 TransportRequestHandler 的替身:/stream?id= 是 StreamRequest;POST /rpc/receive 是 OneWayMessage;POST /rpc/receive-stream 是 UploadStream。不需要官方 spark:4.2.0。仅限回环。

python3 spark-rpc-stream-unauth-Abraxas-Labs.py

或:

cd lab
./run.sh

回环 127.0.0.1:18910。Compose 项目 spark-rpc-stream-unauth。见证字符串 SPARK-RPC-STREAM-UNAUTH-WITNESS 位于 /oracle/secret。注册目录 /opt/repl-classes,其中 hello.txt = IN-DIR-OK。最后一行:

SUCCESS SPARK-RPC-STREAM-UNAUTH SPARK-RPC-STREAM-UNAUTH-WITNESS

修复方案

在 isAuthenticated 之前对 getStreamManager()(以及 getMergedBlockMetaReqHandler())进行门控,或返回一个拒绝的管理器。在 NettyStreamManager.openStream 中,拒绝经过 getCanonicalFile 后离开注册目录的 fname。在 ESS 上,当 spark.authenticate 开启时,将 null clientId 视为未认证。SPARK-57889 已经在 StreamRequest 上调用 checkAuthorization;跳过就是残留。

在此之前,不要在 TCP 端口可被任何你尚未信任其访问 Spark UID 文件的人访问的 RpcEnv 上注册 /classes 或 artifacts。spark.authenticate=true 并不能关闭此数据平面。

参考资料

下载工具