Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

admin 2025年3月25日12:53:45评论13 views字数 9655阅读32分11秒阅读模式

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

免责声明

道一安全(本公众号)的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他!!!

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

前言

    Wiz Research 发现了 CVE-2025-1097、CVE-2025-1098、CVE-2025-24514 和 CVE-2025-1974,这是 Kubernetes 入口 NGINX 控制器中一系列未经身份验证的远程代码执行漏洞,称为 #IngressNightmare。利用这些漏洞会导致攻击者未经授权访问 Kubernetes 集群中所有命名空间中存储的所有密钥,从而导致集群接管。
此攻击媒介的 CVSS v3.1 基本分数为 9.8。

    在这篇博文中,我们分享了从发现 IngressNightmare 中获得的关键经验,IngressNightmare 影响了 Kubernetes 的 Ingress NGINX 控制器的准入控制器组件。根据我们的分析,大约 43% 的云环境容易受到这些漏洞的影响,我们的研究发现,包括财富 500 强公司在内的 6,500 多个集群将易受攻击的 Kubernetes 入口控制器的准入控制器公开暴露在公共互联网上,使它们面临直接的严重风险。

    我们建议尽快修补。此博客文章详细介绍了漏洞的技术要素,并包含面向防御者的缓解和检测指南。

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

什么是适用于Kubernetes的Ingress NGINX控制器?

    Ingress NGINX Controller 是 Kubernetes 上最受欢迎的 Ingress 控制器之一,也是 Kubernetes 的核心项目,在 GitHub 上拥有超过 18,000 颗星。使用 Ingress-NGINX 是向外部公开 Kubernetes 应用程序的最常见方法之一。作为 Ingress 控制器,它的工作是接受传入流量并将其路由到相关的 Kubernetes 服务,后者又根据一组规则将流量转发到适当的 Pod。具体来说,Ingress NGINX Controller 基于流行的 NGINX 反向代理 

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

        图:Kubernetes 文档中的 Ingress 先决条件。

    Ingress-NGINX 在 Kubernetes 文档中明确突出显示为一个示例 Ingress 控制器,它满足在 Kubernetes 中使用 Ingress 的先决条件。我们的研究表明,超过 41% 的面向互联网的集群正在运行 Ingress-NGINX。

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

漏洞

    Ingress NGINX 在其 Pod 中部署一个准入控制器,旨在在部署传入的 Ingress 对象之前对其进行验证。默认情况下,无需身份验证即可通过网络访问准入控制器,这使它们成为极具吸引力的攻击媒介。

    当 Ingress-NGINX 准入控制器处理传入的 Ingress 对象时,它会从该对象构建 NGINX 配置,然后使用 NGINX 二进制文件对其进行验证。我们的团队在此阶段发现了一个漏洞,该漏洞允许通过网络直接向准入控制器发送恶意入口对象,从而远程注入任意 NGINX 配置。

    在配置验证阶段,注入的 NGINX 配置会导致 NGINX 验证器执行代码,从而允许在 Ingress NGINX Controller 的 Pod 上远程执行代码 (RCE)。

    准入控制器提升的权限和不受限制的网络可访问性创建了关键的升级路径。利用此缺陷,攻击者可以执行任意代码并跨命名空间访问所有集群密钥,这可能导致完全接管集群。

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

        图:IngressNightmare 攻击向量

缓解与检测

    首先,确定您的集群是否在使用 ingress-nginx。在大多数情况下,您可以通过使用集群管理员权限运行 kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx 来检查这一点。

    该漏洞已在 Ingress NGINX Controller 版本 1.12.1 和 1.11.5 中修复。我们强烈建议集群管理员:

  • 更新到最新版本的 Ingress NGINX Controller。

  • 确保准入 Webhook 端点未在外部公开 

    • 您可以使用此 Nuclei 模板来检查公开的 Ingress-NGINX 准入控制器。

如果您无法立即升级,请考虑以下缓解措施之一:

  • 实施严格的网络策略 ,以便只有 Kubernetes API 服务器可以访问准入控制器。

  • 如果您无法立即升级, 请暂时禁用 Ingress-NGINX 的准入控制器组件。

    • 如果您已使用 Helm 安装了 ingress-nginx,请使用 controller.admissionWebhooks.enabled=false 重新安装。

    • 如果您手动安装了 ingress-nginx,请删除调用的 ValidatingWebhookConfigurationingress-nginx-admission,并从 ingress-nginx-controller 容器的 Deployment 或 DaemonSet 中删除 --validating-webhook 参数。

    • 请记住在升级后重新启用 Validating Admission Controller,因为它为您的 Ingress 配置提供了重要的保护措施。

    Wiz 客户可以使用 Wiz 威胁中心中预先构建的查询和建议。Wiz 还使用 Wiz Dynamic Scanner 验证公开的准入控制器。最后,Wiz Runtime Sensor 通过持续监控入口流量、实时捕获恶意准入审查请求并标记异常库加载来防止类似攻击,从而检测 IngressNightmare 等零日漏洞。

我们是如何发IngressNightmare 的?

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

我们是如何发现IngressNightmare的?

研究动机

    Kubernetes 准入控制器在 Kubernetes 环境中提供了一个有趣且经常被忽视的攻击面。它们由 Kubernetes API 服务器触发,以便在处理请求之前审查并可能修改或阻止请求 (AdmissionReview), 并且它们通常在集群内以相对较高的权限运行。准入控制器通常不需要身份验证,本质上充当 Web 服务器,在集群中引入了一个额外的内部网络可访问终端节点。这种架构允许攻击者直接从网络中的任何 Pod 访问它们,从而显著增加攻击面。

适用于 Kubernetes 的 Ingress NGINX 控制器的背景

    Ingress NGINX Controller 是一种 Ingress 实现,它使用 NGINX 作为反向代理和负载均衡器。它是最受欢迎的入口之一,也是 Kubernetes 的核心项目。

    为了在 Kubernetes 和 NGINX 配置之间架起桥梁(这是一种非 Kubernetes 原生技术),控制器会尝试将 Kubernetes Ingress 对象转换为 NGINX 配置。为了确保 NGINX 服务器的稳定性,控制器使用验证准入 webhook,在应用最终配置之前对其进行验证。

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷
            图:Ingress NGINX Controller 的简化图

    从攻击者的角度来看,准入控制器是一个未经身份验证的 HTTP 端点,负责复杂的作,默认情况下,它与 Kubernetes 角色一起运行,该角色允许访问环境的所有机密,使其成为一个有吸引力的研究目标。

远程 NGINX 配置注入

    在审查 Ingress NGINX 准入控制器代码时,我们发现了一个有趣的代码路径:当它处理传入的 AdmissionReview 请求时,它会根据模板文件和提供的 Ingress 对象生成一个临时的 NGINX 配置文件。然后,它使用 nginx -t 命令测试临时配置文件的有效性。我们发现了多种在此代码路径中注入新配置指令的方法。

// testTemplate checks if the NGINX configuration inside the byte array is valid // running the command "nginx -t" using a temporal file. func(n *NGINXController) testTemplate(cfg []byteerror { ...     tmpfile, err := os.CreateTemp(filepath.Join(os.TempDir(), "nginx"), tempNginxPattern) ...     err = os.WriteFile(tmpfile.Name(), cfg, file.ReadWriteByUser) ...     out, err := n.command.Test(tmpfile.Name()) func(nc NginxCommand) Test(cfg string) ([]byteerror) {     //nolint:gosec // Ignore G204 error     return exec.Command(nc.Binary, "-c", cfg, "-t").CombinedOutput() 

    通常,只有 Kubernetes API 服务器应该发送这些 AdmissionReview 请求。但是,由于 Admission Controller 缺少身份验证,因此具有最小网络访问权限的攻击者可以从集群内的任何 Pod 构建并发送任意 AdmissionReview 请求。

    在我们的测试中,我们使用 kube-review 从 Ingress 资源清单创建准入审查请求,然后可以通过 HTTP 直接发送到准入控制器。

    "kind""AdmissionReview"    "apiVersion""admission.k8s.io/v1"    "request": {         "uid""732536f0-d97e-4c9b-94bf-768953754aee"...         "name""example-app"        "namespace""default"        "operation""CREATE"...         "object": {             "kind""Ingress"            "apiVersion""networking.k8s.io/v1"            "metadata": {                 "name""example-app"                "namespace""default"...                 "annotations": {                     "nginx.ingress.kubernetes.io/backend-protocol""FCGI"                 }             },             "spec": {                 "ingressClassName""nginx"                "rules": [                     {                         "host""app.example.com"                        "http": {                             "paths": [                                 {                                     "path""/"                                    "pathType""Prefix"                                    "backend": {                                         "service": {                                             "name""example-service"                                            "port": {}                                         }                                     }                                 }                             ]                         }                     }                 ]             }, ...     } 

                图:Admission Review 对象示例

    从上面可以看出,我们可以控制很多字段,显示出较大的攻击面。在这篇博文中,我们将介绍注释解析器中的两个漏洞,这些漏洞解析了上述请求中的 .request.object.annotations 字段。此字段中的属性稍后包含在 NGINX 配置文件中 - 我们使用它来注入任意指令。

CVE-2025-24514 – auth-url 注释注入

    authreq 解析器负责处理与身份验证相关的 Comments。在以下代码流中,该注释需要设置 auth-url 字段,其中包括一个 URL,并最终传播到配置文件中:

func(a authReq) Parse(ing *networking.Ingress) (interface{}, error) {     // Required Parameters     urlString, err := parser.GetStringAnnotation(authReqURLAnnotation, ing, a.annotationConfig.Annotations)     if err != nil {         return nil, err     } 
    创建临时配置时,$externalAuth.URL(对应于 auth-url 注释中的 URL)将被合并 ,而无需进行适当的清理。
proxy_http_version 1.1proxy_set_header Connection ""set $target {{ changeHostPort $externalAuth.URL $authUpstreamName }}; {{ else }} proxy_http_version {{ $location.Proxy.ProxyHTTPVersion }}; set $target {{ $externalAuth.URL }}; {{ end }} 
    由于缺乏适当的清理,攻击者可以注入任意 NGINX 配置指令,这些指令会在 nginx -t 运行时进行评估。请考虑以下 auth-url 注释:
nginx.ingress.kubernetes.io/auth-url: "http://example.com/#;ninjection_point" 
最终配置将如下所示:
... proxy_http_version 1.1; set $target http://example.com/#; injection_point proxy_pass $target... 

    该漏洞不适用于 v1.12.0。在这个版本中,Ingress NGINX Controller 更改了其默认安全设置 ,以根据严格的正则表达式规则验证所有注释,包括 auth-url

CVE-2025-1097 – auth-tls-match-cn 注释注入

authtls 解析器的auth-tls-match-cn 注解使用 CommonNameAnnotationValidator 来验证字段值:

funcCommonNameAnnotationValidator(s string) error {     if !strings.HasPrefix(s, "CN=") {         return fmt.Errorf("value %s is not a valid Common Name annotation: missing prefix 'CN='", s)     }     if _, err := regexp.Compile(s[3:]); err != nil {         return fmt.Errorf("value %s is not a valid regex: %w", s, err)     }     return nil 

换句话说,auth-tls-match-cn 注释需要:

1.该值必须以 CN= 开头。

2.所有剩余字符必须构成有效的正则表达式。

    与之前的注入类似, $server.CertificateAuth.MatchCN 对应于 auth-tls-match-cn 注解的值。虽然很棘手,但我们仍然可以绕过这两个要求,在模板的这一部分注入任意的 NGINX 配置:

if ( $ssl_client_s_dn !~ {{ $server.CertificateAuth.MatchCN }} ) {     return 403 "client certificate unauthorized"
请考虑以下 auth-tls-match-cn 注释:
nginx.ingress.kubernetes.io/auth-tls-match-cn: "CN=abc #(n){}n }}nglobal_injection;n#" 
最终配置将如下所示:
... set $proxy_upstream_name "-";  if ( $ssl_client_s_dn !~ CN=abc #(  ){} }} global_injection;  # ) {  return 403 "client certificate unauthorized"; } ... 
    要使 auth-tls-match-cn 注释值显示在配置中,我们还需要提供 nginx.ingress.kubernetes.io/auth-tls-secret 注释,该注释对应于集群中存在的 TLS 证书或密钥对密钥。由于 Ingress NGINX 使用的服务帐户可以访问集群中的所有 Secret,因此我们可以指定任何命名空间中的任何 Secret 名称,只要它与所需的 TLS 证书/密钥对格式匹配即可。值得注意的是,许多托管的 Kubernetes 解决方案默认包含此类密钥。以下是可用于此类攻击的常见密钥的简短列表:
kube-system/konnectivity-certs kube-system/azure-wi-webhook-server-cert kube-system/aws-load-balancer-webhook-tls kube-system/hubble-server-certs kube-system/cilium-ca calico-system/node-certs cert-manager/cert-manager-webhook-ca linkerd/linkerd-policy-validator-k8s-tls linkerd/linkerd-proxy-injector-k8s-tls linkerd/linkerd-sp-validator-k8s-tls 

CVE-2025-1098 – 镜像 UID 注入

    在镜像注释解析器中, 以下代码处理 ingress 对象的 UID,并将其插入 $location 中。Mirror.Source 的 Mirror.Source 的 Mirror.Source 的 Mirror.Source 中。我们控制着 ing。UID 字段,该字段允许新的注入点。

    由于此注入位于 UID 参数中,而不是 Kubernetes 注解,因此我们的输入不会被注解的正则表达式规则清理。由于我们的输入是按原样插入的,因此我们可以轻松转义上下文并注入任意 NGINX 配置指令。

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

CVE-2025-1974 - NGINX配置代码执行

    上述漏洞允许攻击者向 NGINX 配置注入任意指令,稍后将由 nginx -t 进行测试。这不会立即导致代码执行。如果我们能在 nginx -t 中找到执行任意代码的指令,它将破坏 Pod 并获得其高特权的 Kubernetes 角色。需要注意的是,NGINX 配置只是在测试中,并没有被应用,从而减少了我们实际可以(滥用)使用的指令数量。
Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

                图:可用 NGINX 指令的部分列表( 来源 

    最初我们尝试使用 load_module 指令 ,它可以从文件系统加载共享库。但是,它只能在 NGINX 配置的开头使用,因此在注入时,load_module 将失败,并显示以下错误消息:

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷
            图:“load_module”失败,因为在配置中指定它太晚

    Ingress NGINX Controller 中有许多可用的指令, 因为它们的 NGINX 实例是使用许多附加模块编译的 。我们发现 ssl_engine 指令是 OpenSSL 模块的一部分,也可以加载共享库。此行为未记录在案。与 load_module 不同,此指令可以在配置文件中的任何位置使用 ,因此它适用于我们注入的约束。

    我们现在可以在 NGINX 配置测试阶段加载任意库文件。我们的下一个挑战是:如何将共享库放在 Pod 的文件系统上?

使用 NGINX 客户端 Body 缓冲区上传共享库

    与 nginx -t 和准入控制器 webhook 并行,Pod 还运行 NGINX 实例本身,侦听端口 80 或 443:

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷
        图:NGINX 与 Ingress NGINX Controller 运行在同一个 Pod 中

    在处理请求时,NGINX 有时会将请求体保存到临时文件中( 客户端体缓冲 )。如果 HTTP 请求正文大小大于特定阈值( 默认为 8KB),则会发生这种情况。这意味着理论上我们应该能够发送一个大型 (>8KB) HTTP 请求,其中包含共享库形式的有效负载作为请求的正文,NGINX 会将其临时保存到 Pod 文件系统上的文件中。在 Pod 的文件系统上。

    不幸的是,NGINX 也会立即删除该文件 ,从而产生几乎不可能的争用条件。但是,NGINX 持有一个指向该文件的打开文件描述符,可以从 ProcFS 访问该文件:

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷
        图:尽管文件本身已被删除,但仍然可以从 ProcFS 访问文件描述符 (FD #11)

    为了保持文件描述符打开,我们可以将请求中的 Content-Length 标头设置为大于实际内容大小。NGINX 会一直等待发送更多数据,这会导致进程挂起,让文件描述符打开的时间更长。

    这个技巧的唯一缺点是我们在不同的进程中创建文件,因此我们不能使用 /proc/self 来访问它。相反,我们将不得不猜测 PID 和 FD 编号才能找到共享库,但由于这是一个进程最少的容器,因此只需几次猜测即可相对较快地完成此作。

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

从配置注入到RCE

通过将文件可靠地上传到 Ingress NGINX Controller 的 pod,我们现在可以将它们放在一起,以利用此问题进行全面的远程代码执行。

该漏洞的工作原理如下:

  1. 滥用 NGINX 的 client-body 缓冲区功能,将我们的 payload 以共享库的形式上传到 Pod

  2. 向 Ingress NGINX 控制器的准入控制器发送 AdmissionReview 请求,其中包含我们的任意一个指令注入

  3. 我们注入的指令是 ssl_engine 指令,它会导致 NGINX 将指定的文件作为共享库加载

  4. 我们指定有效负载的文件描述符的 ProcFS 路径

  5. 如果一切顺利,我们的共享库现在已加载,我们远程执行代码

以下是实际漏洞利用的演示:

https://vimeo.com/1068882440

原文链接:https://www.wiz.io/blog/ingress-nginx-kubernetes-vulnerabilities#how-did-we-discover-ingressnightmare-23

本公众号仅做翻译转载

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

点分享

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

点收藏

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

点在看

Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

点点赞

原文始发于微信公众号(道一安全):Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年3月25日12:53:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Kubernetes 集群安全警报:Ingress NGINX 高危漏洞或致集群全面沦陷https://cn-sec.com/archives/3882629.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息