不平静的集群:Kubernetes 中的本地卷漏洞
编辑和评论补充:Tricia Howard
执行摘要
Akamai 安全研究人员 Tomer Peled 最近在 Kubernetes 中发现了一个 高严重性漏洞 ,该漏洞编号为 CVE-2023-5528 ,CVSS 评分为 7.2。
该漏洞让攻击者可以在 Kubernetes 集群中的所有 Windows 端点上以 SYSTEM 权限远程执行代码。要利用该漏洞,攻击者需要在集群上应用恶意 YAML 文件。
该漏洞可导致集群中的所有 Windows 节点被完全接管。
该漏洞可在 Kubernetes 的默认安装版本(早于 1.28.4 的版本)上被利用,并且已针对本地部署和 Azure Kubernetes Service 进行了测试。
- 在这篇博文中,我们提供了一份概念验证 YAML 文件,以及用于防止该漏洞被利用的 开放策略代理 (OPA) 规则。
简介
Kubernetes 和 容器 总体上已经成为安全领域的主导力量,因此也成为了全世界安全研究人员(包括我们)的关注焦点之一。在研究初期,我们发现了 CVE-2023-3676 (CVSS 评分 8.8),这是一个命令注入漏洞,攻击者可通过将恶意 YAML 文件应用到集群来利用该漏洞。由于 Kubernetes 框架几乎将 YAML 文件用于各个方面,从配置容器网络接口到 Pod 管理,甚至是密钥处理都会用到该文件,因此一旦被攻击者利用,该漏洞会引发灾难性后果。
该漏洞的发现推动了另外两个漏洞的发现,这些漏洞都有相同的根本原因——不安全的函数调用和缺乏用户输入清理机制。
在创建带有卷的 Pod 的 YAML 文件中, subPath 参数缺乏清理机制,这给恶意注入创造了机会。这是最初的发现,但在研究的最后,我们注意到代码中的一个潜在位置可能导致另一个命令注入漏洞。经过多次尝试,我们得到了相似的结果:作为“kubelet”服务(SYSTEM 权限)执行命令。我们今天对 CVE-2023-5528漏洞的讨论就从这里开始。
在这篇博文中,我们将介绍该漏洞的详细信息和 Kubernetes 源代码中导致该漏洞的问题,并分析 Kubernetes 团队的补丁及其有效性。 虽然推荐做法是尽快修补,但我们也简单说明了如何查找受影响的节点,以及如何应用开放策略代理 (OPA) 规则来帮助检测和阻止漏洞利用行为。
这篇博文再次强调了验证 Kubernetes 配置文件 YAML 的重要性,因为 Kubernetes 本身及其“边车”项目(例如 Ingress)的多个代码区域均缺乏输入清理机制。
漏洞详情
在介绍该漏洞本身的具体情况之前,我们必须先了解 Kubernetes中的几个关键组件。
什么是 Kubernetes 卷?
Kubernetes 卷 是一种支持 Pod 之间共享数据或在 Pod 生命周期结束后持久存储数据的功能。开发人员可以使用许多不同类型的卷。例如,在之前对 CVE-2023-3676 的研究中,我们使用了 hostPath 卷。但对于此漏洞,我们的侧重点是 本地卷,这是 Kubernetes 中另一种类型的卷。本地卷可以让用户在 Pod 内挂载磁盘分区,而 hostPath 卷可以让用户将目录从他们的节点(主机)挂载到 Pod 中。
在创建包含本地卷的 Pod 时, kubelet 服务将(最终)到达函数“MountSensitive()”。该函数内有一个对“exec.command”的 cmd 调用,会在节点上的卷位置和 Pod 内部的位置之间建立符号链接(图 1)。
为了便于使用,许多终端在操作中会使用某种形式的命令串联(图 2)。Windows 的 命令提示符 (cmd) 也是如此,通过使用“&&”符号,终端将依次执行两个或多个命令。
C:\Users\user>echo "by using &&" && echo "we can execute multiple commands in the same command line"
"by using &&"
"we can execute multiple commands in the same command line"
C:\Users\user>
图 2: cmd 中的命令串联
我们可以控制 cmd 执行中的一个参数,这就意味着可以使用命令注入。不过这有前提条件——用户需要指定或创建 persistentVolume 才能使用本地卷。
什么是 persistentVolume?
persistentVolume 是集群管理员可以创建的存储资源,用于提前配置存储空间,这些空间将在 Pod 生命周期结束后持续存在(图 3)。创建 persistentVolume 后,用户可以使用 persistentVolumeClaim请求存储空间。
在此处就可以执行注入。 攻击者可以更改 persistentVolume YAML 文件中“local.path”参数的值,从而添加会在挂载过程中执行的恶意命令。
在图 4 中,我们使用了无害的“&calc.exe&&”(会在节点上打开一个计算器),但这个过程如果被攻击者利用,会引发更有破坏性的结果。
图 5 显示利用该漏洞在目标节点上注入无害的计算器命令后的表现。
修补分析
为了杜绝注入机会,Kubernetes 团队选择删除 cmd 调用,使用执行相同操作的内置 GO 函数“os.Symlink()”(图 6)取而代之。
现在,GO“os”库只会执行符号链接操作,这与最初的预期相符。
我是否容易受到攻击?
只有 Kubernetes 版本早于 1.28.4 的用户才会受此漏洞影响。如果您还未修补,最好优先考虑进行修补。尤其是集群中有 Windows 节点的企业更应该重视此事,因为这些节点存在漏洞。
所幸,这好像不是行业标准。管理员可以在集群控制器上运行图 7 所示的命令,轻松测试企业集群中是否包含 Windows 节点。
root@controller:~/$ kubectl get nodes -o wide --show-labels | grep “os=windows”
akswin000000 Ready agent 4d17h v1.26.6 agentpool=win,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=windows…
akswin000001 Ready agent 4d17h v1.26.6 agentpool=win,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=windows…
root@controller:~/$
图 7:显示集群中的 Windows 节点的命令
要确定是否存在漏洞非常简单。注意观察“os=windows”部分。如果没有 Windows 节点,命令就不会有输出结果,表示不存在此漏洞。
抵御措施
唯一可用的抵御措施是对 Kubernetes 进行修补,达到 1.28.3 之后版本的标准。
话虽如此,我们了解有些企业和网络无法立即进行修补。为了帮助应对未及时修补的风险,我们提供了一种 OPA 规则来帮助检测和防止该漏洞被利用。
package kubernetes.admission
deny[msg] {
input.request.kind.kind == "PersistentVolume"
path := input.request.object.spec.local.path
contains(path, "&")
msg := sprintf("malicious path: %v was found", [path])
}
OPA 是一种开源代理, 可以让用户接收流入和流出节点的流量的相关数据,并对接收到的数据执行基于策略的操作。
请记住,该漏洞只影响 Windows 节点。如果您的 Kubernetes 集群中没有 Windows 节点,则不必急于对这个漏洞进行修补。但如果有时间,则无论如何都有必要进行修补。
由于问题出在源代码中,这个威胁会持续存在,而且对漏洞的利用可能会加剧,所以即使集群中没有 Windows 节点,我们也建议进行修补。
结论
该漏洞是一个很好的例子,说明了责任共担模式为何在安全领域至关重要。在意识到 Kubernetes 源代码中缺乏输入清理机制之后,即可采取外部预防措施来帮助避免严重的安全影响。
仅在 2023 年,业界就发现了七个不同的命令注入漏洞,代码的其他区域还有更多潜在问题。蓝队及其所在企业应该对这种增长趋势更加警惕,并尝试监控 YAML 文件内容,因为其中可能存在隐藏的威胁。我们在这篇博文中提供的 OPA 规则可以帮助达成这个目的。
Akamai 安全情报组将继续监控这一威胁和其他类似的威胁,并公布我们的发现。如需了解该漏洞的新变化和其他安全研究动态, 请关注我们的微信公众号 。
在此,我们想感谢 Kubernetes 团队的快速响应和顺畅沟通。
披露时间表
2023 年 11 月 1 日——漏洞披露给 Kubernetes 团队
2023 年 11 月 11 日——Kubernetes 团队分配 CVE 编号
2023 年 11 月 14 日——Kubernetes 发布 CVE 修复方法
2024 年 3 月 13 日——此博文发布