文| Tencent Blade Team

周炽金、leonwxqian、cradmin

前言

随着云计算平台的成熟和分布式框架的普及,应用上云已经是不可逆转的趋势。而新的技术形态会带来新的安全问题,云原生的安全也开始引起业界的广泛关注。

Kubernetes和容器技术是云原生的基础设施,现有的公开资料大多是对业务上的配置漏洞进行梳理,少有对这两个基础设施代码层面的漏洞分析、攻击面总结。

本文是笔者对Kubernetes和Docker进行安全调研的一个总结,包括对已有漏洞和攻击面的梳理。在这过程中,笔者发现了两个Kubernetes的漏洞,我们于2020年6月通过官方渠道通报了这两个漏洞,官方已于2020年8月确认漏洞存在,并给出CVE:CVE-2020-8560和CVE-2020-8556。

笔者会在本文中分享这两个CVE的细节。文中的一些观点旨在抛砖引玉,欢迎大家一起探讨。

攻击面与已知漏洞

目前,云厂商都十分重视云原生安全。在云原生计算基金会的资助下,Kubernetes提出了漏洞悬赏项目[1],以丰厚的奖金激励安全研究员在Kubernetes生态中挖掘漏洞。

除此之外,Google也在GKE上设立了一个CTF题(称作kCTF),并以丰厚的奖励悬赏在GKE上的提权漏洞[2]。微软Azure安全中心[3] 和阿里云安全[4] 也都发布了自己的云上攻防矩阵,总结了Kubernetes生态以及自建的服务场景中的攻击面。

在笔者看来,大多数的云原生安全问题来自于配置漏洞。上述几个云上安全矩阵的详解中,给出的大部分安全风险的场景都是配置漏洞,例如:

(1) 创建容器时,将容器配置成为特权容器。攻击者从特权容器逃逸是非常容易实现的;

(2) 创建容器时,将docker.sock挂载在容器内部。攻击者可以通过该socket与docker daemon 通信,启动一个高权限的容器,从而提权;

(3) 未正确配置kubelet 10250端口的鉴权。攻击者能通过伪装api server来控制该节点。而配置漏洞的发现需要大量的人力,需要开发工程师与安全工程师协作完成。

因而,在平台开发的过程中让开发工程师了解云上可能存在的攻击面是必要的。

另一方面,笔者作为安全团队的一员,更关心的是依赖的开源框架的安全性问题。Kubernetes作为云原生的基础设施,其安全性事关重大;其底层默认使用的容器管理引擎Docker,更是安全研究者关注的热点。

因而笔者总结了Kubernetes和Docker的一些攻击场景以及影响较大的已知漏洞,来提供一些攻防思路。

2.1 Kubernetes 历史漏洞

CVE-2019-1002101

1. 攻击场景

攻击者拥有一个pod的控制权,目标是以host上高权限账户执行攻击者代码。

2. 漏洞背景

"kubectl cp" 支持从pod中拷贝,或者拷贝文件到pod中。执行时,是用pod内的 tar 二进制打包容器内的文件,然后将打包好的 tar 包传给host来解压这个 tar 包。

3. 漏洞复现[5]

(1) 攻击者劫持一个pod后,修改pod内的/bin/tar二进制;

(2) 集群管理者执行”kubectl cp”命令从pod中拷贝文件到本机;

(3) 由于解压tar包时会写文件,攻击者可以传一个精心构造的恶意tar包,利用符号链接可以任意对集群管理者本机的文件进行写操作。

4. 攻击前提

用户要调用”kubectl cp”来复制攻击者劫持的pod中的文件。

CVE-2018-1002105

1. 攻击场景

攻击者能通过鉴权,可以向apiserver发送请求,目标是控制其他用户的容器。

2. 漏洞背景

用户执行一个命令的数据流向是:client->apiserver->kubelet。有漏洞版本的 k8s 中, kubelet 返回处理失败后, apiserver 没有关闭连接。

3. 漏洞复现[6]

攻击者发起一次失败的请求后,由于连接没关闭,可以继续通过该链接发送请求使得控制同一kubelet 的不同容器。

4. 攻击前提

攻击者有能通过鉴权;同一个kubelet 的机器上有其他用户的container。

CVE-2019-11254

1. 攻击场景

攻击者能通过鉴权,可以向apiserver发送请求,目标是控制让集群拒绝服务。

2. 漏洞复现 [7]

攻击者构造一个yaml文件,传给apiserver,使得apiserver 在解析该文件时花费大量时间。

3. 攻击前提

攻击者有能通过鉴权。

CVE-2020-8557

1. 攻击场景

攻击者拥有一个pod的控制权,对文件系统有写权限。目标是让pod所在的节点拒绝服务。

2. 漏洞背景

k8s中,一个pod如果占用的存储空间超过限定的存储大小,则会被kubelet的驱逐管理器驱逐出该机器;/etc/hosts路径是pod外挂载在pod内的。

3. 漏洞复现[8]

攻击者在pod中向/etc/hosts文件写入大数据,即使超过限定的存储大小,k8s的驱逐管理器也不会驱逐该pod,所以可以造成该节点的磁盘空间被占满,进而导致拒绝服务。

4. 攻击前提

攻击者拥有一个pod的控制权。

2.2 Docker 已知漏洞

CVE-2019-14271

1. 攻击场景

攻击者拥有一个容器的控制权,目标是以host的高权限执行攻击者的代码。

2. 漏洞背景

"docker cp" 命令允许从容器、向容器中、或容器之间复制文件;执行"docker cp" 时, dockerd 会起起名为 docker-tar 的帮助进程;docker-tar 通过 chroot 到容器,然后打包目标文件;但docker-tar 除了 chroot 到容器文件系统外,并没有被容器化。它是在 host 命名空间运行的,权限为 root 且不受限于 cgroups 或 seccomp。

3. 漏洞复现[9]

docker-tar 依赖于一些动态加载库(libnss_*.so),因为 docker-tarchroot 到了容器,因此会从容器文件系统中加载库。攻击者在容器内创建一个恶意 libnss 库即可以 root 权限执行自己的代码。

4. 攻击前提

拥有 root 权限的用户要调用"docker cp" 来复制恶意容器内的文件。

CVE-2019-5736

1. 攻击场景

攻击者拥有一个容器的控制权,目标是以host的高权限执行攻击者的代码。

2. 漏洞背景[10]

docker 在 container 内创建一个进程,一般是通过"docker exec" 命令;执行过程是:runc 启动,加入到容器的命名空间,接着启动一个子进程,最后通过exec 系统调用执行用户指定的二进制程序;/proc/[PID]/exe 是个特殊的符号链接,如果打开这个文件,在权限检查通过的情况下,内核将直接返回一个指向该文件的 fd。

3. 漏洞复现

(1) 将容器内的/bin/sh 程序覆盖为 #!/proc/self/exe;

(2) 持续遍历容器内/proc 目录,找到 runc 进程号;

(3) 以只读方式打开/proc/[runc-PID]/exe,拿到文件描述符 fd;

(4) 持续尝试以写方式打开 fd,一旦可以写时,立即通过该 fd 写攻击者的恶意代码;

(5) host 用户执行 runc 时,就会触发步骤 2 以后的逻辑,执行恶意代码。

4. 攻击前提

攻击者有容器的控制权,且host用户要调用runc。

CVE-2020-11492

1. 攻击场景

攻击者拥有host上的低权限账户,目标是以 host 上高权限账户执行攻击者的代码。

2. 漏洞背景

Windows下, Docker Desktop应用开启后,会创建多个子进程,使用 Windows命名管道与 Docker Desktop Service 交互;Windows一些账户组权限很小,对计算机资源的访问就非常有限(比如Network Service)。

3. 漏洞复现[11]

攻击者在低权限的账户下,建立一个名为 \\\\\\\\.\\\\pipe\\\\dockerLifecycleServer 的命名管道,并等待连接。当 Docker Desktop 启动后,子进程会连接恶意管道,于是低权限账户就可以获得SYSTEM 权限。

4. 攻击前提

攻击者建立恶意管道要在 SYSTEM 权限账户启动 Docker Desktop 之前。

2.3 攻击面总结

通过上述的已知历史漏洞,我们可以总结出以下的攻击面:

(1) 内核层面

如果内核本身有能提权的漏洞(例如CVE-2016-5195 脏牛漏洞),那么在容器内是会利用内核漏洞进行逃逸的;又或者内核的cgroups、seccomp等机制不完善,也有可能造成非法访问;

(2) Docker层面

在外部命令(如docker commit, docker cp, docker diff, docker exec)执行时,所产生的辅助进程有可能是host用户的权限,在容器内如果有办法注入自己的恶意代码在辅助进程内,那么就可以以host权限执行自己的逻辑;

(3) Docker层面

Docker 本身的管理进程众多,攻击这些进程间的通信,可能可以获取敏感信息;

(4) Kubernetes层面

向外暴露的网络服务都可能受到攻击,鉴权与否是关键;

(5) Kubernetes层面

用户与容器内部的交互的命令(目前只有 cp 命令)可能会造成容器内部对容器外部的非法写操作。

新的0day:漏洞真的被补上了么?

在探索云原生安全性的过程中,笔者发现许多攻击面很别出心裁,非常有借鉴意义。

然而深入调研这些漏洞的细节与修复漏洞的记录后,笔者发现一些漏洞并没有真正的被修复,一些修复漏洞的代码在特定条件下能够被绕过。

在一番努力下,笔者基于已披露的漏洞,发现了两个新的漏洞:CVE-2020-8560与CVE-2020-8556。

CVE-2020-8560

1. 漏洞背景

与CVE-2019-11246, CVE-2019-11249类似,”kubectl cp” 仍旧有安全性问题。

"kubectl cp" 支持从pod中拷贝,或者拷贝文件到pod中。执行时,是用pod内的 tar 二进制打包容器内的文件,然后将打包好的 tar 包传给host来解压这个 tar 包。

2. 版本信息

Kubernetes v1.18.5 (released in 26 June 2020)。

2. 漏洞分析

之前的修复补丁中,主要添加了两个检查:

(1) 利用path.Clean() 方法,将要解压的路径转化为不带有”../”的形式,然后判断是否会穿越到上层目录;

(2) 判断解压的文件是否是符号链接,如果是的话则不解压。

但是笔者发现,这样修复路径穿越,只能防止”../”的路径穿越,却不能防止”..\\\\”的路径穿越,即在Windows下,”kubectl cp”仍旧有路径穿越的可能。

于是很简易地构造了一个恶意的tar二进制,将该二进制拷贝到pod的/bin/tar,然后用Windows的机器连接到集群,调用kubectl cp命令从该pod中拷贝文件到本机上(命令:kubectl cp shell-demo:/any/path/you/like ./ )。

于是恶意文件便写在了当前目录之外的地方。恶意tar的二进制逻辑如下(rust代码):

CVE-2020-8556

1. 漏洞背景

与CVE-2020-8557类似,攻击者仍可以在pod内通过对某个路径写大文件来让节点DoS。

k8s中,一个pod如果占用的存储空间超过限定的存储大小,则会被kubelet的驱逐管理器驱逐出该机器,如果没有正确驱逐,则会造成节点无法加入新的pod,导致拒绝服务;

/etc/hosts和/dev/termination-log路径是pod外挂载在pod内的。

2. 版本信息

Kubernetes v1.18.6 (released in 15 July 2020)。

3. 漏洞分析

在之前的修复补丁中,为了防止pod内的攻击者向/etc/hosts路径下写大文件,开发者加了额外的逻辑统计该路径的文件的大小,如图所示。加入这段逻辑以后,可以保证如果pod内占用的磁盘空间(包括/etc/hosts)大于预设的值的话,该pod会被驱逐管理器驱逐。

但是,笔者在集群中测试时,发现不仅/etc/hosts路径是pod外挂载的,/dev/termination-log也是pod外挂载在pod内的。

/dev/termination-log本意是用于pod异常关闭时写临终遗言,方便集群管理者查看日志。

发现这一问题后,笔者验证了自己的猜想:在一个存储限制为200M 的pod中,向/dev/termination-log 路径写入大文件

(命令:dd if=/dev/zero of=/dev/termination-log bs=1M count=1000)。

之后,驱逐管理器并没有将该pod驱逐,攻击成功。

结语与展望

总的来说,Kubernetes与Docker都是非常成熟、安全的项目。一方面,Kubernetes、 Docker (moby)、 runc 都是由 go 语言写的,少了很多内存安全问题;另一方面,项目的维护者也很重视安全性,专门聘请安全团队进行代码审计,同时发布漏洞悬赏。

笔者在调研过程中,感受到诸如模糊测试一类的自动化漏洞挖掘技术在这样的项目上难以找到合适的应用场景,主要原因是Kubernetes 层面的数据流在多进程、 多机器间传播, 命令时延大, 消息异步,而模糊测试适合单进程、低时延、消息同步的场景。因而,代码审计可能是最适合研究这类项目的安全性的方法。

最后,笔者认为在云原生场景下,有三个可能产生漏洞的风险点需要特别关注:

(1) 跟踪历史漏洞,查看修复补丁是否有绕过的可能;

(2) 审计Kubernetes的业务(诸如驱逐管理器、卷管理器等逻辑复杂业务)的代码,找寻逻辑漏洞;

(3) 利用自动化测试的方法对内核容器隔离的底层支持技术(如cgroups,seccomp等)等进行正确性检查,如果有正确性问题,则容器的隔离性就无法保证。

参考资料

[1]https://hackerone.com/kubernetes

[2]https://security.googleblog.com/2020/05/expanding-our-work-with-open-source.html

[3]https://www.microsoft.com/security/blog/2020/04/02/attack-matrix-kubernetes/

[4] https://developer.aliyun.com/article/765449

[5]https://unit42.paloaltonetworks.com/disclosing-directory-traversal-vulnerability-kubernetes-copy-cve-2019-1002101/

[6]https://xz.aliyun.com/t/3542?from=timeline&isappinstalled=0

[7]https://github.com/kubernetes/kubernetes/issues/89535

[8]https://github.com/kubernetes/kubernetes/issues/93032

[9] https://xz.aliyun.com/t/6806

[10]https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/

[11]https://www.pentestpartners.com/security-blog/docker-desktop-for-windows-privesc-cve-2020-11492/

声明:本文来自腾讯安全应急响应中心,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。