FlawOpen

flawopen.com/Teardowns/cve-2024-7646-ingress-nginx-annotation-code-injection

● CVE-2024-7646 · CVSS 8.8 · 高危
安全研究 · FlawOpen

CVE-2024-7646:Ingress-NGINX 校验绕过

回车符校验绕过可使 Ingress 创建者注入命令并获取 ingress-nginx 控制器凭据。已在 1.11.2 和 1.10.4 修复;项目已退役。

💡 通俗易懂的原理解析 (ELI5)

想象一位门卫只检查表单里是否出现一个允许的词,却没有校验整个值。回车符可能改变下一个系统读取剩余文本的方式。这里,注解通过了部分匹配检查,随后被写入生成的 NGINX 配置。修复方案要求校验完整值,并安全处理回车符。

核心概念与专有名词

Ingress 对象
描述从主机或路径到 Service 的流量路由的 Kubernetes API 资源。用户可能被授权创建它,但并非集群管理员。
注解校验绕过
注解值通过了只查找合法子串的校验器,而未要求整个值精确匹配允许选项。
回车符 (`\r`)
某些格式中表示换行的控制字符。如果校验和配置生成阶段解释不同,可能改变配置行的边界。
控制器 ServiceAccount
ingress-nginx 控制器使用的 Kubernetes 身份。上游公告指出,默认权限可能允许访问集群中所有 Secrets。

框架映射

  • 本指南所述弱点的 CWE 参考: CWE-20

根本原因剖析 (Root Cause)

CVE-2024-7646 是 ingress-nginx 的注解校验绕过,并非无限制使用自定义 Lua snippet。auth-tls-verify-client 校验器使用了未锚定起止位置的 Go 正则,因此 MatchString 可能只因较长值中包含某个合法选项子串就接受该值。注解中的回车符随后可能在清理生成的 NGINX 配置时被不同方式解释。上游修复要求整个值精确匹配,并在 cleanConf 中安全处理单独的回车符。Kubernetes 安全公告说明,有权限创建 Ingress 对象的主体可以绕过校验、注入命令并获取控制器凭据;默认配置下该凭据可能有权读取集群中的所有 Secrets。这是需要 Kubernetes API 身份权限的高危路径(CVSS 8.8),不是来自任意网络客户端的匿名请求。项目于 2026 年 3 月退役;升级到历史修复版本只能作为紧急遏制措施,部署应迁移到仍受维护的控制器或 Gateway API 实现。

攻击执行流程分解

步骤 1

用户具备创建 Ingress 的权限

攻击者需要拥有通过 Kubernetes API 创建 Ingress 对象的权限。在将该权限委派给应用团队的多租户集群中风险尤其突出。

步骤 2

注解通过部分匹配校验

存在缺陷的 auth-tls-verify-client 正则没有锚点,因此 Go MatchString 可能接受包含合法选项的较长值,而不是只接受精确值。

步骤 3

回车符影响配置边界处理

注解会进入生成的 NGINX 配置。修复系列同时处理完整值校验和清理配置时对单独回车符的处理。

步骤 4

控制器身份凭据遭到暴露

Kubernetes 公告指出,命令注入可获取控制器凭据。默认情况下,该 ServiceAccount 可读取所有 Secrets;实际影响取决于部署的 RBAC 权限。

源代码对比:漏洞与安全实现

这些摘录来自 CVE-2024-7646 的上游修复:PR #11719 为 auth-tls-verify-client 的允许值添加锚点,PR #11721 在 cleanConf 中处理单独的回车符。1.10 分支也包含 PR #11718 和 #11722 的对应修改。省略了无关的函数上下文。

存在漏洞的实现
// internal/ingress/annotations/authtls/main.go(修复前)
authVerifyClientRegex = regexp.MustCompile(`on|off|optional|optional_no_ca`)

// internal/ingress/controller/template/template.go(修复前)
switch c {
case ' ', '\t':
    needOutput = lineStarted
case '\n':
    needOutput = !(!lineStarted && emptyLineWritten)
    nextLineStarted = false
}
加固后的安全修复
// internal/ingress/annotations/authtls/main.go(修复后)
authVerifyClientRegex = regexp.MustCompile(`^(on|off|optional|optional_no_ca)$`)

// internal/ingress/controller/template/template.go(修复后)
switch c {
case '\r':
    rest := in.Bytes()
    if len(rest) > 0 && rest[0] != '\n' {
        c = ' '
        needOutput = lineStarted
    }
case '\n':
    needOutput = !(!lineStarted && emptyLineWritten)
    nextLineStarted = false
}

工程与系统安全加固清单

参考来源