Py学习  »  NGINX

IngressNightmare:Ingress NGINX 中存在 9.8 严重未经身份验证的远程代码执行漏洞

Ots安全 • 6 天前 • 79 次点击  

Wiz Research 发现了 CVE-2025-1097、CVE-2025-1098、CVE-2025-24514 和 CVE-2025-1974,这是 Kubernetes Ingress NGINX Controller 中一系列未经身份验证的远程代码执行漏洞,被称为#IngressNightmare。利用这些漏洞会导致攻击者未经授权访问 Kubernetes 集群中所有命名空间存储的所有机密,从而导致集群接管。 

此攻击媒介的 CVSS v3.1 基本评分为 9.8。 

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

我们建议尽快修补。这篇博文详细介绍了该漏洞的技术要素,并包含针对防御者的缓解和检测指南。

我们要感谢 Ingress-NGINX 维护人员,特别是Marco Ebert,感谢他们帮助解决 IngressNightmare 漏洞。我们的团队与 Kubernetes 维护人员和安全团队密切合作,确保在公开披露之前完全消除此攻击面。Kubernetes 的博客可以在此处找到,亚马逊和Google Cloud也发布了自己的公告。

什么是 Kubernetes 的 Ingress NGINX 控制器? 

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

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

Kubernetes 文档中明确强调了 Ingress-NGINX,将其作为 Ingress 控制器示例,满足在 Kubernetes 中使用 Ingress 的先决条件。我们的研究表明,超过 41% 的面向互联网的集群正在运行 Ingress-NGINX。 

漏洞  

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

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

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

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

图:IngressNightmare 攻击向量 

需要明确的是,获得集群 pod 网络的初始访问权限并不像人们想象的那么困难 - 容器化本身并不是一个强大的安全边界,并且许多在 K8 上运行的应用程序都容易受到容器逃逸的影响,正如我们在过去几年对云和 SaaS 应用程序的研究中反复证明的那样。此外,这些漏洞与 SSRF 漏洞非常匹配,SSRF 漏洞在 Web 应用程序中可以说是很常见的情况。

缓解和检测 

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

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

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

  • 确保admission webhook 端点没有暴露给外部。 

您可以使用此Nuclei 模板https://gist.github.com/nirohfeld/7a7c82c62321de9c2ef95d266b241fcb来检查暴露的 Ingress-NGINX 准入控制器。 

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

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

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

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

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

  • 升级后请记住重新启用验证准入控制器,因为它为您的 Ingress 配置提供了重要的保障。

如果您想测试 IngressNightmare 的检测,可以使用以下流程使用 Terraform启动故意存在漏洞的集群:

git clone https://github.com/ofirc/ingress-nightmare.git
cd ingress-nightmare
terraform init
terraform plan
terraform apply -auto-approve

kubectl port-forward svc/ingress-nginx-controller-admission -n ingress-nginx 8443:443
curl -vk https://localhost:8443/validate -H \"Content-Type: application/json\" --data-binary @admission-review.json

Wiz 客户可以使用 Wiz 威胁中心中预先构建的查询和咨询。Wiz 还使用 Wiz 动态扫描仪验证暴露的准入控制器。最后,Wiz 运行时传感器通过持续监控入口流量、实时捕获恶意准入审查请求以及标记异常库负载来检测 IngressNightmare 等零日漏洞,以防止类似的攻击。

请注意,CVE-2025-24513 的性质与 IngressNightmare 链中的其他漏洞不同,因为它不会导致 RCE。

我们是如何发现 IngressNightmare 的? 

研究动机 

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

Kubernetes 的 Ingress NGINX 控制器背景 

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

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

图:Ingress NGINX Controller 简化图

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

远程 NGINX 配置注入 

在审查 Ingress NGINX Admission Controller 代码的过程中,我们发现了一个有趣的代码路径:当它处理传入的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 []byte)error { 
... 
    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)([]byte, error) { 
    //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": {} 
                                        } 
                                    } 
                                } 
                            ] 
                        } 
                    } 
                ] 
            }, 
... 
    } 
}

图:入学审查对象的示例 

如上所示,我们可以控制许多字段,这显示出巨大的攻击面。在这篇博文中,我们将研究注释解析器中的两个漏洞,这些解析器解析.request.object.annotations 上述请求中的字段。此字段的属性随后包含在 NGINX 配置文件中 - 我们用它来注入任意指令。 

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

authreq解析器负责处理与身份验证相关的注释。注释需要设置 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 { 
        returnnil, err 
    }
创建临时配置时,$externalAuth.URL(对应于auth-url注释中的 URL)未经适当清理就被纳入。  
proxy_http_version 1.1; 
proxy_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 注释注入 

对于其auth -tls-match-cn 注释,authtls 解析器使用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) 
    } 
    returnnil
}

换句话说,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 使用的服务帐户可以访问集群中的所有机密,因此我们可以从任何命名空间指定任何机密名称,只要它与所需的 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 注入 

在mirror注释解析器中,以下代码https://github.com/kubernetes/ingress-nginx/blob/bacee47448595e0cf328d420518cde3e1258fe97/internal/ingress/annotations/mirror/main.go#L115处理来自入口对象的 UID,并将其插入到$location.Mirror.Source临时 NGINX 配置中。我们控制该ing.UID字段,这允许新的注入点。  

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

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

上述漏洞允许攻击者向 NGINX 配置注入任意指令,稍后将由 进行测试nginx -t。这不会立即导致代码执行。如果我们可以在 中找到执行任意代码的指令nginx -t,它将破坏 pod 并获得其高权限的 Kubernetes 角色。需要注意的是,NGINX 配置仅正在测试,尚未应用,这减少了我们实际可以(滥用)的指令数量。 

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

(图片来源) 

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

图:“load_module”因在配置中指定得太晚而失败

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

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

使用 NGINX Client Body Buffers 上传共享库 

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

图:NGINX 与 Ingress NGINX Controller 在同一个 pod 中运行

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

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

图:尽管文件本身已被删除,但文件描述符仍然可以从 ProcFS 访问(FD #11)

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

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

从配置注入到 RCE 

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

该漏洞的工作原理如下: 

  1. 利用 NGINX 的客户端缓冲功能,将我们的有效负载以共享库的形式上传到 pod 

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

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

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

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

结论 

我们对准入控制器安全性的审查还只是皮毛。最初,我们很惊讶地发现幕后使用了如此庞大的代码库。我们认为,应该以更好的方式限制这个攻击面:从集群内的 pod 中删除访问权限,并且永远不要公开暴露这一点。我们还对缺乏最小权限设计感到惊讶,因为漏洞最终获得了控制集群的权限。在这项研究中,我们在 Ingress NGINX Controller 中发现了其他漏洞,我们预计会在其他准入控制器中发现更多漏洞。 

最后,我们了解到这nginx -t应该被视为有害。我们很高兴听到其他nginx -t进程在野外未清理用户输入的情况。这应该在 NGINX 文档中更清楚地强调。 


负责任的披露时间表 

2024 年 12 月 31 日——Wiz Research 向 Kubernetes 报告了 CVE-2025-1974 和 CVE-2025-24514。 

2025 年 1 月 2 日——Wiz Research 向 Kubernetes 报告了 CVE-2025-1097。 

2025 年 1 月 3 日——Kubernetes 承认了这些报告。 

2025 年 1 月 9 日——Kubernetes 提出了针对 CVE-2025-1097 的修复。 

2025 年 1 月 10 日——Wiz Research 报告了针对 CVE-2025-1097 的拟议修复的绕过方法。 

2025 年 1 月 12 日——Kubernetes 提出了针对 CVE-2025-1974 的修复。 

2025 年 1 月 16 日——Wiz Research 报告了针对 CVE-2025-1974 的拟议修复的绕过方法。 

2025 年 1 月 20 日——Kubernetes 提出了针对 CVE-2025-24513 的修复。 

2025 年 1 月 21 日——Wiz Research 报告了针对 CVE-2025-24513 的拟议修复的绕过方法。 

2025 年 1 月 21 日——Wiz Research 向 Kubernetes 报告了 CVE-2025-1098。 

2025 年 2 月 7 日——Kubernetes 发布了针对注入漏洞的内部补丁:CVE-2025-1098、CVE-2025-1097 和 CVE-2025-24514。 

2025 年 2 月 20 日——Kubernetes 通知 Wiz Research,他们从准入控制器中删除了 NGINX 配置验证,解决了 CVE-2025-1974。 

2025 年 3 月 10 日——Kubernetes 就 Wiz Research 报告的五个漏洞发送了禁运通知。 

2025 年 3 月 24 日——公开披露。 



感谢您抽出

.

.

来阅读本文

点它,分享点赞在看都在这里


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/180466
 
79 次点击