再次攻击我吧:Kubernetes 日志查询中的命令注入漏洞
编辑和评论补充:Tricia Howard
执行摘要
Akamai 安全研究人员 Tomer Peled 最近在 Kubernetes 中发现了一个漏洞,该漏洞编号为 CVE-2024-9042。
利用该漏洞,攻击者能够在 Kubernetes 集群中的所有 Windows 端点上使用 SYSTEM 特权实现远程代码执行 (RCE)。要利用此漏洞,该集群必须配置为运行新的日志记录机制“日志查询”。
只需向远程节点发送简单的 GET 请求即可触发该漏洞。
如果攻击者成功利用了该漏洞,可导致集群中的所有 Windows 节点被完全接管。
该漏洞可在选择使用测试功能的 Kubernetes 默认安装版本(1.32.1 之前的版本)上被利用,并且已针对本地部署和 Azure Kubernetes Service 进行了测试。
在本博文中,我们将提供一个概念验证 curl 命令,并讨论可行的抵御措施。
前言
总体而言,Kubernetes 和容器已经成为安全领域的主导力量,因此也成为了全世界安全研究人员(包括我们)的关注焦点之一。我们的研究过程最初引导我们发现了 CVE-2023-3676:一个命令注入漏洞,攻击者可以通过对集群应用恶意 YAML 文件来利用该漏洞。该研究发现 Kubernetes 源代码中还存在其他几个问题,这些问题也会导致完全集群接管。
我们发现的漏洞还不止这些,在 Sidecar 项目 git-sync 中也发现了一个重大问题。我们在第 32 届 DEF CON 大会的 Red Team Village 上展示了这些发现结果,而在准备演讲时,我们偶然发现了本博文的主题:命令注入的另一个机会——Kubernetes 为其更大的日志记录框架提供的测试版功能,即日志查询。
日志查询是什么?
借助日志查询功能,用户可以使用 CLI 或 curl 来查询远程机器的系统状态。例如,用户可输入以下命令来查询远程节点上 kubelet 服务的状态:
kubectl get --raw "/api/v1/nodes/node-1.example/proxy/logs/?query=kubelet"
在看到上述示例命令时,我们便想到了先前的研究:发送给远程机器的查询是否会进行验证?
图 1 是日志查询功能的源代码示例,我们在其中发现了多个正在构建的 PowerShell 命令。
这些命令用于根据多个不同的参数(例如,Windows 服务名称、使用时间模式等)从指定的节点中检索日志。
根据以往的经验 (CVE-2023-3676),我们知道,构建 PowerShell 命令时,Kubernetes 不一定会先验证用户输入,再将输入作为参数插入命令中。我们想看看日志查询功能是否也是如此,结果发现服务名称实际上是使用预定义的正则表达式进行验证的(图 2)。
名称 reServiceNameUnsafeCharacters 表明此检查仅针对服务。解析过程中不存在任何其他正则表达式这一事实进一步证实了此假设。
在查看其他参数后,可以明显看出,需要验证的唯一参数就是服务名称,确实如此。这意味着,我们可以查看其他参数以期实现命令注入。在日志查询功能中,用户可以提供多个不同的可选参数,但唯一的字符串参数是 Pattern 参数(图 3)。正如我们先前所提到的,不会对该参数进行任何验证(长度除外)。
值得注意的是,利用此漏洞并非易事。我们尝试使用 PowerShell 有效负载的多种不同排列组合(例如,添加括号、使用分隔符等)在远程计算机上触发这些命令,但似乎都不起作用,也没有出现任何错误,这让我们更难找出问题所在。
问题并不在于有效负载
在尝试了很多不同的命令注入方法之后,我们最终发现问题并不在于有效负载本身。要利用此漏洞,我们需要指定一项服务,该服务将其状态记录到本机 Windows 事件跟踪 (ETW) 而非常规 klog 框架中,因为只有在记录到 ETW 时才会存在易受攻击性检查。
使用 Calico(一个用于 Kubernetes 的热门开源网络接口)的 Kubernetes 环境提供了一种通过 Non-Sucking Service Manager (NSSM) 利用此漏洞的可靠方法。
在 Calico 设置中,NSSM 通常用于控制 Kubernetes 服务的状态。在其他环境/设置中,它们使用不同的方法来处理服务状态。
- Kubernetes 并不管理 NSSM 的日志记录输出,以确保日志直接写入 ETW 而非通过 klog 写入。
展示漏洞利用查询
漏洞利用查询如下所示:
curl "<Kubernetes API Proxy server IP>/api/v1/nodes/<NODE name>/proxy/logs/?query=nssm&pattern=’\$(Start-process cmd)’"
*与 API 服务器通信所需的身份验证令牌已被删除
眼尖的读者可能会对我们用来转义恶意命令的撇号感到疑惑。我们之所以需要撇号,是因为 Kubernetes 会使用以下命令插入我们的输入:
…Where-Object -Property Message -Match '%s'...
与典型的 SQL 注入攻击类型的是,我们需要添加撇号来转义其模式,这样我们的输入就会被解析为单独的命令(图 4)。
优先进行修补
如果您受到了此漏洞的影响,那么您使用的一定是版本低于 1.32.1 的 Kubernetes。如果您尚未修补此漏洞,最好优先考虑进行修补。尤其是集群中有 Windows 节点的企业更应该重视此事,因为漏洞就存在于这些节点中。
所幸,这好像不是行业标准。管理员可通过在集群控制器上运行以下命令来轻松测试企业集群是否包含 Windows 节点(图 5)。
我是否容易受到攻击?
要确定是否容易受到攻击非常简单。注意“os=windows”部分。如果没有 Windows 节点,命令就不会有输出结果,这表示不容易受到攻击。
由于这是一项测试功能,因此还需要对集群进行配置才能使用框架本身。
要检查该功能是否已启用,管理员可以查看“kubelet”的“feature-gate”启动参数。您可以在 Kubernetes 网站上获取更多信息。
修补分析
为了修复此漏洞,Kubernetes 决定在将值传递给 PowerShell 命令本身之前使用名为“kubelet_pattern”的环境变量。
通过这种方式,用户输入将被视为一个字符串文字,而不是需要求值的子表达式。
抵御措施
为了帮助抵御此漏洞,管理员可以使用基于角色的访问控制 (RBAC) 模块来控制有权访问日志查询功能的用户,甚至可以彻底禁止对其进行访问。RBAC 是一种根据用户角色划分用户操作的方法。例如,每个用户只能在自己的命名空间中创建 Pod,或者只能查看允许访问的命名空间的信息。这不仅可以从执行层面,还可以从检测层面降低 RCE 的风险——异常的用户行为往往是恶意行为的征兆。
请记住,该漏洞只影响 Windows 节点。如果您的 Kubernetes 集群没有任何 Windows 节点,那么您不会受到该漏洞的影响。但是,仍然建议您尽可能及时更新补丁,以避免出现其他未知的漏洞。
由于问题出在源代码中,这个威胁会持续存在,而且对漏洞的利用可能会加剧,所以即使集群中没有 Windows 节点,我们也建议进行修补。
结论
在本博文中,我们介绍了拥有查询特权的攻击者如何在集群内的任何 Windows 节点上执行命令。只需通过简单的 curl 命令即可利用此漏洞,而不必提交 YAML 文件。这一事实带来了巨大的风险,因为对此漏洞的利用更加难以抵御和检测。Kubernetes 清理问题并非日志查询功能所特有,这一点我们先前已讨论过。
蓝队成员应密切注意他们企业中出现的异常行为。此攻击媒介可能会导致完全集群接管;因此对我们而言,非常有必要加强认知,并帮助安全管理员了解可能造成的危害。
Akamai 安全情报组将继续研究此类威胁,并随时向我们的客户及整个安全社区报告相关情况。如需及时了解我们的最新工作进展,请关注我们的微信公众号。
在此,我们想感谢 Kubernetes 团队的回应和讨论。
时间表
2024 年 6 月 28 日——向 Kubernetes 团队披露漏洞
2024 年 7 月 18 日——Kubernetes 团队开始修复此问题
2024 年 7 月 30 日——Kubernetes 团队分配了 CVE 编号
2025 年 1 月 16 日——Kubernetes 发布了 CVE 修复方法
2025 年 1 月 24 日——发布相关博文