浅谈云上攻防——CVE-2020-8562 漏洞为 k8s 带来的安全挑战
前言
2021 年 4 月,Kubernetes 社区披露了一个编号为 CVE-2020-8562 的安全漏洞,授权用户可以通过此漏洞访问 Kubernetes 控制组件上的私有网络。
通过查阅此漏洞披露报告可发现,这个漏洞拥有较低的 CVSS v3 评分,其分值仅有 2.2 分,与以往披露的 Kubernetes 高危漏洞相比,这个拥有较低评分的漏洞极其容易被安全研究人员以及运维人员所忽视。但经过研发测试发现,在实际情况中,这个低风险的漏洞却拥有着不同于其风险等级的威胁:在与云上业务结合后,CVE-2020-8562 漏洞将会为云厂商带来不可忽视的安全挑战。
在这篇文章中,云鼎实验室将为大家带来业内首个 CVE-2020-8562 漏洞分析报告,一同来看一下这个被忽视的低风险漏洞引发的“血案”。
CVE-2020-8555 漏洞简述
Kubernetes 为了缓解 CVE-2020-8555 等历史漏洞带来的安全问题,对 APIServer Proxy 请求进行域名解析以校验请求的 IP 地址是否处于本地链路 (169.254.0.0/16) 或 localhost (127.0.0.0/8) 范围内,Kubernetes 通过此方式禁止由用户触发的对 Services,Pods,Nodes,StorageClass 对象的内网 Proxy 访问权限。
但是在完成校验并通过校验之后,Kubernetes 立即进行第二次域名解析,此次域名解析后并不再进行 IP 地址的校验,这将导致上述校验存在绕过问题,如果一个 DNS 服务器不断返回不同的非缓存解析请求,攻击者可以利用此方式绕过 Kubernetes 的 API Server Proxy IP 地址限制,并访问内网 ControlPlane 管控组件。
详细的漏洞细节可参见如下图 Issue 所示:
图 1 CVE-2020-8562 漏洞细节
Issue 地址如下:
https://github.com/kubernetes/kubernetes/issues/101493
在正式开始介绍这个漏洞是如何对 Kubernetes 集群带来危害之前,我们先来看看这个漏洞中应用到主要攻击技巧:DNS 重绑定攻击(DNS Rebinding)。
DNS 重绑定攻击 DNS 重绑定攻击技术的实现主要依赖于攻击者可将其自建的 DNS 服务器中 DNS TTL 配置为设置为 0 或者极小值。DNS TTL 表示 DNS 记录的生存时间,数值越小, DNS 记录在 DNS 服务器上缓冲的时间越小。
在攻击者将 DNS TTL 数值设置为一个极小值时,当受害目标第一次访问恶意域名时并发起域名解析请求时,恶意 DNS 服务器会返回一个 ip 地址 A;当受害目标第二次发起域名解析请求时,却会得到 ip 地址 B 的解析结果。具体的原理,我们可以通过一道 CTF 题目,深入了解一下:
}这道 CTF 题目需要参赛者访问内网 127.0.0.1 地址并获取存储于其中的 Flag。
从代码中可见,题目将会判断参赛者传入的域名解析后的 ip,并仅允许访问 54.87.54.87 地址的内容。
如何绕过题目中的条件语句,利用到的就是 DNS 重绑定攻击技术。
从上文代码段可见,程序通过以下代码来执行第一次 DNS 解析以获取 ip:
$ip = @dns_get_record($res['host'], DNS_A)[0]['ip'];
假设此时参赛者传入的域名为 www.a.com,将会进行如下的解析:
图 2 首次 DNS 解析流程
此时 www.a.com 域名解析出来的 ip 为 54.87.54.87。
程序继续往下执行,执行到了如下代码块:
$dev_ip = "54.87.54.87";
if(dev_ip){}
此时 ip 参数为 54.87.54.87,满足条件分支判断,程序执行进入 if 条件分支。
随后,程序执行到如下语句:
$content = file_get_contents($dst);
注意,此时 file_get_contents 方法内的参数为参赛者控制的域名 dst,而非 ip 地址。
也就是说,程序执行 file_get_contents 方法时,需要获取此域名的 ip 地址解析。由于攻击者将 DNS TTL 设置的数值极其小,从程序第一次获取 ip 到执行 file_get_contents 方法处时,DNS 缓存早已失效,CTF 服务器此时需要重新发起域名解析请求以获取 www.a.com 的 ip,此时参赛者修改 DNS 解析结果以完成 DNS 重绑定攻击,见下图:
图 3 重绑定 DNS 解析
此时获取到的解析 ip 值为 127.0.0.1,参赛者通过此方式绕过限制并访问 127.0.0.1 资源,实现重绑定攻击。
KuBernetes 中 DNS 重绑定攻击的应用 Kubernetes 为了防止用户对 Services,Pods,Nodes,StorageClass 对象的内网 Proxy 进行非法访问,采用了域名解析的方式解析并校验 Proxy 请求的 IP 地址是否位于本地链路 (169.254.0.0/16) 或 localhost (127.0.0.0/8) 范围内。
Kubernetes 通过此方式防止恶意内网资源的 Proxy 访问行为,但是 Kubernetes 在校验通过之后,会进行第二次域名解析,获取 IP 地址访问而不再进行 IP 地址的校验。
联想到上一章节的 DNS 重绑定攻击方式:攻击者可以控制 DNS 解析的 IP 地址,在第一次校验时返回一个合法值,随后在第二次获取 IP 地址时,返回一个本地链路或 localhost 地址,详见下图:
图 4 Kubernetes 中 DNS 重绑定流程
通过这个技术方式,攻击者可以绕过 apiserver proxy 的内网限制,构造恶意请求访问集群中的资源。
这种攻击技术将为云服务商带来了极大的安全问题:大多数云服务商提供 Kubernetes 托管版集群服务,采用此服务的用户 Master 节点将由云厂商创建并托管,如果攻击者通过方式访问到本地链路 (169.254.0.0/16) 或 localhost (127.0.0.0/8)地址,则有可能访问同为托管模式下其他用户的 apiserver。
CVE-2020-8562 漏洞原理首先,使用云厂商提供的 Kubernetes 托管版集群服务创建一个集群。在此场景下,我们创建的集群的 Master 节点将与其他采用托管服务的用户一并,由云厂商创建并托管管理,这为后续的利用提供了先决条件。
图 5 Kubernetes 托管版集群服务
在集群创建完毕后,通过编写如下 yaml 来创建一个名为 cve-2020-8562 的 node,见下图:
图 6 使用 yaml 创建 node
通过上图可见,在此 yaml 中,将只能在集群内进行路由的节点的 IP 地址 InternalIP 设置为攻击者可控的 www.attacker.com。
创建完毕后,可以通过 kubectl get nodes 查看到此节点:
图 7 通过 kubetctl 查看 cve-2020-8562 节点
从上图红框处可以发现,此时我们创建的 cve-2020-8562 节点的状态为 NotReady,但即使此时 cve-2020-8562 节点的状态为 NotReady,也并不影响后续的利用流程。
使用如下命令启动 Kubernetes API 服务器的代理:
kubectl proxy &
图 8 通过 kebuectl 开启代理
在成功启动 Kubernetes API 服务器的代理之后,通过如下命令使用 apiserver proxy 来访问 cve-2020-8562 节点的 apiserver:
图 9 访问 cve-2020-8562 节点的 apiserver
通过上文来看,cve-2020-8562 节点处于 NotReady,我们可以正常的访问其 apiserver 吗?
我们来看一下 Kubernetes 是如何完成接下来的访问:
首先,为了可以访问 cve-2020-8562 节点,Kubernetes 首先需要获取 cve-2020-8562 节点的 InternalIP,我们通过如下指令查看一下 cve-2020-8562 的 InternalIP:
图 10 查看 cve-2020-8562 节点详情
通过上图可知,cve-2020-8562 节点的 InternalIP 值与生成此节点 yaml 中配置项一致,为我们配置的 www.attacker.com。
由于 InternalIP 为域名而非 IP 地址,Kubernetes 需要对其进行域名解析,随后校验获取到的 IP 地址是否位于本地链路 (169.254.0.0/16) 或 localhost (127.0.0.0/8) 范围内,如果获取到的 IP 属于此范围,则禁止访问。
在第一次 DNS 解析时,攻击者自建的 DNS 服务器将会返回一个合法的 IP 地址(非本地链路或 localhost 范围),例如 172.x.x.x,流程见下图:
图 11 第一次 DNS 解析
通过此方式,可以绕过 k8s 的本地链路/localhost 范围 IP 校验。
在通过安全校验之后,K8s 将会发起第二次域名解析。由于攻击者将 DNS TTL 设置的数值极其小,此时 DNS 缓存已失效,k8s 需要重新发起域名解析请求以获取 www.attacker.com 的 ip 地址,流程见下图:
图 12 DNS 重绑定攻击
从上图可见,此时攻击者可以将 www.attacker.com 域名的 IP 解析为一个 localhost 范围内的 IP 地址并返回,在此例中,我们返回一个 127.x.x.x 地址。
此时,k8s apiserver proxy 访问情况可以类比于下图情况:
图 13 当前访问可抽象成此情况
如果 127.x.x.x 这个节点的 apiserver 存在未授权访问情况,我们就可以通过此方式直接访问其 apiserver,见下图:
图 14 攻击者访问托管服务中 Master
通过此方式,可以访问其他使用 Kubernetes 托管集群服务的租户的 apiserver。
总结在安全研究以及运维中,一些低风险的集群漏洞极其容易被安全以及运维人员所忽略,但是这些漏洞在一些特定场景中仍为云上安全带来了极大的安全挑战,正如本文中所举例的 CVE-2020-8562 安全漏洞,这个仅有 2.2 评分的 Kubernetes 安全漏洞,在与实际业务结合后,仍可为业务带来极大的安全风险。因此与云上安全相关的漏洞,无论严重与否,都应得到安全人员以及运维人员的相应重视。
参考链接https://github.com/kubernetes/kubernetes/issues/101493
https://zhuanlan.zhihu.com/p/89426041
评论