0x00 事件背景

2018-12-03凌晨Kubernetes的开发者 @liggitt 在Kubernetes 的issuse中公布该漏洞的一些细节以及影响。

只要可以从Kubernetes API服务器的网络中可以直接访问聚合API服务器,就可以提升权限对任何聚合API服务器端点进行API调用,以及对该聚合API服务器执行任何API请求(例如Pod的创建以及执行任意命令并获得返回结果)。 在默认配置中,允许所有用户(经过身份验证和未经身份验证的用户)执行允许此权限提升的API调用。

该漏洞由Rancher Labs的首席架构师兼联合创始人@Darren Shepard发现。

0x01 影响范围

  • Kubernetes v1.0.x-1.9.x
  • Kubernetes v1.10.0-1.10.10 (fixed in v1.10.11)
  • Kubernetes v1.11.0-1.11.4 (fixed in v1.11.5)
  • Kubernetes v1.12.0-1.12.2 (fixed in v1.12.3)

主要受影响的方面如下

可从Kubernetes API服务器网络直接访问的扩展API服务器(如调度服务器)的群集 不希望对Kubelet API具有完全访问权限的用户授予pod exec / attach / portforward权限的群集

@liggitt指出目前没有简单的方法可以检测是否被此漏洞攻击。 由于未经授权的请求是通过已建立的连接进行的,因此它们不会出现在Kubernetes API服务器审核日志或服务器日志中。 请求会记录在kubelet或聚合的API服务器日志中,但是与正确授权和代理的请求无法区分开。

0x02 修复建议

官方推荐的最佳的修复方案是及时升级到

  • Kubernetes v1.10.11
  • Kubernetes v1.11.5
  • Kubernetes v1.12.3
  • Kubernetes v1.13.0-rc.1

下面是一些@liggitt 给出的缓解措施

针对匿名用户的缓解措施 -> 可以按照如下方式对聚合服务器进行配置:

  • 暂停使用聚合的API服务器(请注意,这将影响使用聚合服务器提供的API的用户)
  • 通过将--anonymous-auth = false传递给kube-apiserver来禁用匿名请求(请注意,这可能会破坏kube-apiserver的负载均衡器或kubelet运行状况检查,并中断kubeadm join设置流程)
  • 删除对所有聚合API的所有匿名访问(包括由默认发现角色绑定授予的发现权限)

针对经过身份验证的用户的缓解措施 -> 可以按照如下方式对聚合服务器进行配置:

  • 暂停使用聚合的API服务器(请注意,这将影响使用聚合服务器提供的API的用户)
  • 从不应具有对聚合API的完全访问权限的用户中删除对所有聚合API(包括由默认发现角色绑定授予的发现权限)的所有访问权限(请注意,这可能会破坏用户和控制器利用发现信息映射API类型到URLs)

针对授权pod exec / attach / portforward的缓解 - > 可以按照如下方式对kubelet API进行配置:

  • 从不应具有对kubelet API的完全访问权限的用户中删除pod exec / attach / portforward权限

0x03 简要分析

根据Issue中@liggitt的描述可以得知

kube-apiserver <-> kubelet 的连接是依靠 kube-apiserver的 TLS 凭证实现的,只要拥有已经建立的TLS连接, 那么kubelet 就会认可来自kube-apiserver的请求并且完成相应的操作。默认情况下kubelet是允许执行所有API权限的操作。

而该漏洞的产生也就是在 k8s.io/apimachinery/pkg/util/proxy/upgradeaware.go 中接口的逻辑有缺陷,导致用户完成对该接口的访问后即可获得持续的TLS连接。

修复函数为 (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Request)

tryUpgrade() 由 ServeHTTP()进行调用,ServeHTTP() 用于处理代理响应请求,在 UpgradeRequestRoundTripper() 接口描述中,所有有关Upgrade的响应都会经由代理(Proxy)处理。此时代理,也就相当于一个中间服务器(Server)。

在用户通过API Server向 Backend 发起请求时,API Server 会先进行一次是否为 Upgrade 请求判断, 使用函数 httpstream.IsUpgradeRequest() , 对 HTTP 请求头部是否含 Upgrade 字段进行判断,不含 Upgrade 的请求,则判断失败,结束。

ServeHTTP() 在处理过程中,使用了 http.Hijacker, Go语言的 Hijacker 可以用于接管请求,对请求消息进行转发。

此刻 Proxy(API Server) 是具有 Full access 权限的,导致转发的请求(由部分不具备高权限的用户发起/以及未授权的用户) 也具备了 Full access 权限,造成提权漏洞

补丁围绕着 rawResponseCode 进行,如果状态码不是101,则会在转发请求前结束。

Upgrade 说明: HTTP/1.1 引入了 Upgrade 机制,允许将一个已建立的连接升级成新的,不相容的协议。需要对HTTP头进行设置,状态码为101。

Handle error responses from backends by liggitt · Pull Request #71412 · kubernetes/kubernetes

而根据这个commit的修复我们可以看到

当客户端发起的请求和服务端状态不一致的时候将直接关闭该连接,这样用户就不再持有可以任意访问其他API操作的相应权限

0x04 资产统计

360CERT结合自身Quake平台进行全网资产统计,发现暴露在外的Kubernetes API server数量如下

Kubernetes 1.10 and beyond, serves OpenAPI (Swagger 2.0)

Before Kubernetes 1.10, serves Swagger 1.2

全球分布统计如下

国内分布统计如下

暴露在外的数量已经十分可观,但并不是说这些服务器就受到该漏洞影响。

在实际生产应用中,Kubernetes属于大型框架服务, 影响面会比较广泛。 360-CERT建议相关用户,特别是互联网相关的企业,应该针对自身IDC线上环境、办公网环境进行安全评估,及时进行版本升级或者权限管控。以免遭受不必要的风险。

0x05 时间线

2018-12-03 @liggitt公布此漏洞影响

2018-12-04 360CERT进行分析资产统计

2018-12-05 360CERT发布预警

0x06 参考链接

  1. CVE-2018-1002105: proxy request handling in kube-apiserver can leave vulnerable TCP connections · Issue #71411 · kubernetes/kubernetes
  2. CVE-2018-1002105 - Red Hat Customer Portal
  3. Handle error responses from backends by liggitt · Pull Request #71412 · kubernetes/kubernetes
  4. The Kubernetes API - Kubernetes