abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-history-store-path
类别: 文件写入(受配置门控) 可达性: 远程
Apache Spark 4.2.0(32f72996)- Apache Software Foundation
HistoryServerDiskManager.appStorePath 执行 new File(appStoreDir, appId + extension),未做任何清理。Utils.sanitizeDirName 仅用于事件日志文件名。JSON 中的 App ID 通过 asText() 获取。列表存储 event.appId.orNull。Lease.commit 使用该字符串。App ID 为 ../ 时会在 spark.history.store.path 之外写入一个 .rdb 文件。默认未设置的 store.path 为内存模式(不写入)。内容为存储文件,并非 RCE。
| ID | 暂无 CVE |
| 类别 | 文件写入(受配置门控的 History 磁盘存储) |
| 可达性 | 远程(事件日志写入者加上设置了 spark.history.store.path 的 History;UI ACL 默认关闭) |
| CWE | CWE-22 |
| CVSS | 高危:7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N(当设置了 spark.history.store.path 时) |
| 产品 | Apache Spark History Server |
| 受影响版本 | 4.2.0(32f7299601108917fb01920a54e084595b7b3bf8) |
| 认证 | spark.history.fs.logDirectory 的写入者(默认 file:/tmp/spark-events);History 必须设置 spark.history.store.path |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅限 127.0.0.1:18990。所引用拼接的利用组件。在 store.path 之外生成见证文件 .rdb。 |
与 CVE-2025-54920 相同的受害者模型:History Server 指向攻击者可写入的日志目录。Jackson 不再构造 HiveConnection 类利用组件。磁盘存储路径仍然信任事件 JSON 中的 App ID。
| 方法 | 汇聚点 | 权限 | 实验环境 vs 推断 |
|---|---|---|---|
植入一个事件日志,其 JSON App ID 为 ../<name>(或 ../../oracle/...)。等待扫描。GET 加载应用 UI / getAppUI / loadDiskStore / createDiskStore | HistoryServerDiskManager.appStorePath 然后 Lease.commit renameTo | 完整性: 以 History UID 身份在 {store.path}/apps 之外创建 .rdb(默认 RocksDB)或 .ldb(LevelDB)路径。在利用组件上实验证明:escaped=yes,文件 /work/oracle/SPARK-HISTORY-STORE-PATH-WITNESS.rdb 包含见证内容。内容为存储文件,并非攻击者选择的主机字节码,也不是 shell。 | 实验证明(在逃逸路径写入见证字节的利用组件)。完整 History 对 RocksDB 目录的 renameTo 是同一拼接。 |
| 当逃逸目标已是目录时使用相同 App ID | Lease.commit 的 if (dst.isDirectory()) deleteStore(dst) 然后 Utils.deleteRecursively | 可用性: 删除名称已以后端后缀结尾的现有目录,然后用租用的存储替换它。 | 推断(依据 HistoryServerDiskManager.scala 提交逻辑)。利用组件写入的是文件,未调用 deleteRecursively。 |
默认未设置 spark.history.store.path | LOCAL_STORE_DIR createOptional;diskManager = storePath.map | 已关闭。内存列表。无 HistoryServerDiskManager。实验证明 gated=yes written=no。 | 实验证明 |
先对 App ID 应用 Utils.sanitizeDirName | 事件日志文件名辅助函数 | 保持在 apps/ 内。/ 和 : 变为 -。实验证明为否定结果。 | 实验证明 |
控制 App ID 为 local-control 且设置了 store.path | 同一拼接 | 写入 {store.path}/apps/local-control.rdb。保持在 apps/ 内。 | 实验证明 |
相邻已关闭项: 默认未设置的存储(内存模式)。Jackson 的 sparkEventFromJson 仍要求 SparkListenerEvent(CVE-2025-54920)。URL getAppUI 回退 eventlog_v2_ + nameForAppAndAttempt 已清理。列表 KV 键不是文件系统路径。HybridStore / kvstore 映射器没有 Id.CLASS。压缩默认关闭。清理器默认关闭。开放集群上的作业提交(SECURITY.md FAQ)。ML 模型加载(docs/ml-security.md)。此遗留问题并非主机 RCE。
我固定使用 Spark 4.2.0,不是 master,也不是 4.3 RC。二十八次搜寻。公开的 History Jackson RCE 在此版本上已关闭。事件日志写入者已调用 Utils.sanitizeDirName,因此日志文件不能包含 /。磁盘缓存文件名使用原始 App ID。
private[history] def appStorePath(appId: String, attemptId: Option[String]): File = {
val fileName = appId + attemptId.map("_" + _).getOrElse("") + extension
new File(appStoreDir, fileName)
}
appStoreDir 为 {spark.history.store.path}/apps。Unix 的 new File(parent, "../../oracle/name.rdb") 会解析到 parent 之外。JsonProtocol.applicationStartFromJson 取 json.get("App ID").asText()。AppListingListener.onApplicationStart 存储 event.appId.orNull。lease.commit(appId, attempt.info.attemptId) 将该字符串送入 appStorePath。
已记录的弯路:将默认未设置的 store.path 视为写入(实际为内存模式);期望 Unix 的 new File(dir, "/abs") 忽略 parent(实际不会;遗留为 ..);因后缀为 .rdb 而声称 RCE;在拼接即为 oracle 时启动完整 History Server;将 sanitizeDirName 视为覆盖此路径。
python3 spark-history-store-path-Abraxas-Labs.py
或
cd lab
./run.sh
HistoryServerDiskManager.appStorePath 在 127.0.0.1:18990 上的利用组件。固定版本摘录位于 lab/pin/ 下。未启动完整 History Server。将其绑定到回环地址。
SUCCESS SPARK-HISTORY-STORE-PATH how=gadget escaped=yes gated=yes outside=/work/oracle/SPARK-HISTORY-STORE-PATH-WITNESS.rdb SPARK-HISTORY-STORE-PATH-WITNESS
在 appStorePath 内、new File 之前,对 appId 和 attemptId 运行 Utils.sanitizeDirName(或拒绝 .. / / / NUL)。拼接后,要求 dst.getCanonicalFile() 保持在 appStoreDir.getCanonicalFile() 之下。未设置 spark.history.store.path 仍为安全默认值。
32f7299601108917fb01920a54e084595b7b3bf8)HistoryServerDiskManager.scala appStorePath / Lease.commitFsHistoryProvider.scala diskManager / loadDiskStore / onApplicationStartJsonProtocol.scala applicationStartFromJsonUtils.scala sanitizeDirNameHistory.scala LOCAL_STORE_DIR(可选)GNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。无担保。