版权声明:本文为「星云实验室 绿盟科技研究通讯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://mp.weixin.qq.com/s/q4xJtlO6iFpHQginGvVBDQ
简介
在2020年Black hat北美会议上,来自Palo Alto Networks的高级安全研究员Yuval Avrahami分享了利用多个漏洞成功从Kata containers逃逸的议题[1]。
作为一种轻量级虚拟化技术,传统容器与宿主机共享内核,这意味着系统内核权限提升漏洞往往也可用来实施容器逃逸。为了彻底解决这一问题,在轻量与安全性之间达到较好的平衡,安全容器应运而生。Kata Containers是一种安全容器的具体实现,其他主流的安全容器还有Google推出的gVisor[4]等。
Kata Containers项目最初由Hyper.sh的runV项目与Intel的Clear Container合并而来,并于2017年开源[2]。它的核心思想是,为每一个容器运行一个独立虚拟机,从而避免其与宿主机共享内核。这样一来,即使攻击者在容器内部成功利用了内核漏洞攻破内核,他依然被限制在虚拟机内部,无法逃逸到宿主机上。Kata Containers在官方介绍中[3]直观地展示了它与传统容器之间的异同:
从上图可以得出结论,在不考虑其他因素的情况下,如果Kata Containers内部的攻击者想要逃逸到宿主机上,他必须至少经过两次逃逸——「容器逃逸」和「虚拟机逃逸」,才能达到目的。也就是说,单一的漏洞可能将不再奏效,攻击者需要构建一条漏洞利用链。
事实上,Yuval Avrahami也是这么做的。他分享的议题中一共涉及四个漏洞:
- CVE-2020-2023:Kata Containers容器不受限地访问虚拟机的根文件系统设备[5],CVSS 3.x评分为6.3[11];
- CVE-2020-2024:Kata Containers运行时(runtime)在卸载(unmount)挂载点时存在符号链接解析漏洞,可能允许针对宿主机的拒绝服务攻击[6],CVSS 3.x评分为6.5[12];
- CVE-2020-2025:基于Cloud Hypervisor的Kata Containers会将虚拟机文件系统的改动写入到虚拟机镜像文件(在宿主机上)[7],CVSS 3.x评分为8.8[13];
- CVE-2020-2026:Kata Containers运行时在挂载(mount)容器根文件系统(rootfs)时存在符号链接解析漏洞,可能允许攻击者在宿主机上执行任意代码[8],CVSS 3.x评分为8.8[14]。
其中,CVE-2020-2024主要会导致拒绝服务攻击,对逃逸帮助不大。逃逸主要依靠其他三个漏洞形成的利用链条来实现。
这个议题精彩又富有意义。它让我们意识到,即使是采用了独立内核的“安全容器”,也存在逃逸风险。换句话说,安全没有银弹。
本文将对该议题中的逃逸过程(Container-to-Host)及相关的三个漏洞进行详解和复现。
注:
- 相关漏洞在新版本Kata Containers中均已得到修复。
- 文中涉及到的是Kata Containers 1.x系列版本,2.x有所差异但相关度不大,不再涉及,感兴趣的读者可以参考官方文档[19]。
- 后文过程中使用的Kata Containers组件、源码版本如无特殊说明,均为1.10.0。
背景知识
安全容器
「安全容器」一词,是相对于传统容器而言的。作为一种虚拟化技术,虽然容器本身已经提供了一定程度上的隔离性,但这种隔离性时不时就会被打破。问题的根源在于,传统容器与宿主机共享内核,内核漏洞势必会直接影响容器的安全性。然而由于内核的复杂度过高等原因,近年来,高危内核漏洞层出不穷。
那么,为什么不直接使用虚拟机呢?答案很明显,性能和资源开销问题使得传统虚拟机技术在现今很多场景和开发部署模式下并不适用,而这也恰恰是容器技术流行的主要原因之一。因此,人们引入了安全容器,希望在轻量化和安全性上达到较好的平衡。
随着云原生技术和生态的发展,开源安全容器项目也在陆续增多。下面,我们介绍两种主流、目标一致但原理各异的安全容器项目:Kata Containers和gVisor。
>>>>
Kata Containers
在「简介」部分,我们已经概括了Kata Containers项目的诞生和原理相关信息,这里不再重复。我们来深入了解一下Kata Containers,这对后面的漏洞分析和利用有帮助。Kata Containers符合OCI运行时规范[18],能够替换runC,与Docker引擎无缝对接,也支持Kubernetes。
下图[2]清晰展示了Kata Containers的组件及各自的角色位置:
我们来分别介绍一下各个组件及其作用:
- runtime:容器运行时,负责处理来自Docker引擎或Kubernetes等上层设施的命令(OCI规范定义)及启动kata-shim,程序名为kata-runtime。
- agent:运行在虚拟机中,与runtime交互,用于管理容器及容器内进程,程序名为kata-agent。
- proxy:负责宿主机与虚拟机之间的通信(对shim、runtime及agent之间的I/O流及信号进行路由),如果宿主机内核支持vsock,则proxy是非必要的,程序名为kata-proxy。
- shim:容器进程收集器,用来监控容器进程并收集、转发I/O流及信号,程序名为kata-shim。
- hypervisor:虚拟机监视器,负责虚拟机的创建、运行、销毁等管理,有多种选择,QEMU、Cloud Hypervisor等。
- 虚拟机:由高度优化过的内核和文件系统镜像文件创建而来,负责为容器提供一个更强的隔离环境。
欲了解更多关于Kata Containers的内容,可以参考官方文档[3][17]。
>>>>
gVisor
gVisor是由Google开源的一款安全容器,它在实现上与Kata Containers有明显不同。Kata Containers虽然同样避免了容器与宿主机共享内核,但它的思路是提供一个虚拟机,容器与虚拟机共享内核;而gVisor则直接在用户层实现了内核,用来拦截容器内程序对系统API的调用,处理并响应。
欲了解更多关于gVisor的内容,可以参考官方文档[20]。
Cloud Hypervisor
Cloud Hypervisor是一个开源的虚拟机监视器(VMM),基于KVM运行。该项目专注于在受限硬件基础架构和平台上运行现代云计算工作流。它采用Rust语言实现,基于rust-vmm创建。
从1.10.0版本起,Kata Containers支持采用Cloud Hypervisor作为它的虚拟机监视器。
欲了解更多关于Cloud Hypervisor的内容,可以参考官方文档[16]。
漏洞分析
如「简介」部分所述,从容器到宿主机的逃逸涉及三个漏洞的使用,由「容器逃逸」和「虚拟机逃逸」两部分组成。
其中,容器逃逸涉及到的漏洞是CVE-2020-2023,虚拟机逃逸涉及到的漏洞是CVE-2020-2025和CVE-2020-2026。其中,前两个是权限控制的问题,最后一个漏洞则是云原生环境下的“常客”——未限制符号链接解析导致的文件系统逃逸问题,类似的漏洞还有CVE-2019-14271[21]等。
下面我们分别进行简单分析。
CVE-2020-2023
这个漏洞是典型的权限控制问题——容器内部可以访问并修改虚拟机的文件系统。其根源之一在于,Kata Containers并未通过Device Cgroup[21]限制容器对虚拟机设备的访问,因此容器能够通过创建设备文件的方式来访问到虚拟机设备。
创建设备文件需要用到mknod系统调用,而mknod需要Capabilities中的CAP_MKNOD权限[23]。那么容器是否拥有这个权限呢?不同引擎的规定不一定相同,但至少默认情况下Docker引擎是支持此权限的[24]:
1 | // moby/oci/caps/defaults.go |
为了进一步确定,我们可以在Kata Containers创建的容器中来验证一下:
1 | docker run --rm -it ubuntu /bin/bash |
首先从容器中/proc/self/status文件获取到Capabilities的具体值,然后对其进行解析。结果显示,容器确实拥有CAP_MKNOD权限。
既然如此,再结合CVE-2020-2023,我们进一步来尝试下能否在容器内通过创建设备文件来访问、甚至修改设备。
在存在漏洞的环境中(后文「逃逸复现-环境准备」小节给出了搭建漏洞环境的方法,读者可参考),创建一个容器;在容器内,首先我们需要找到底层虚拟机块设备的设备号,然后创建设备文件。
/sys/dev/block/目录下是各种块设备的符号链接,文件名即为目标块设备的主次设备号,我们要找到目标块设备为vda1的符号链接文件名,从而获得主次设备号。
例如,在笔者的环境下:
1 | root@7d30fe24da7e:/# ls -al /sys/dev/block/ | grep vda1 |
找到主设备号为254,次设备号为1。在获取设备号后,即可使用mknod创建设备文件:
1 | mknod --mode 0600 /dev/guest_hd b 254 1 |
接着,就可以对该设备进行访问和操作了。这里我们可以借助debugfs工具来实现:
1 | root@7d30fe24da7e:/# /sbin/debugfs -w /dev/guest_hd |
果然,漏洞存在时,我们的确能够访问虚拟机文件系统。那么,能否修改呢?可以的,例如,kata-agent就在usr/bin目录下:
1 | debugfs: cd usr/bin |
我们可以直接删除它:
1 | debugfs: rm kata-agent |
可以看到,操作执行成功,kata-agent被删除了。
我们能够修改文件系统,说明它以读写模式挂载,这是漏洞根源之二。