近年来随着信息技术的发展与需求,容器技术获得了大规模的应用,它带来的便利和高效改变了服务器的软件环境,write oncerun anywhere一次打包到处运行,这句话也正实际行动影响着软件的世界,devops云原生也在快速到来,但与此同时,安全问题也如影随形。

在谈容器安全问题之前,先简单的了解一下容器技术的历史和结构。容器的出现最早可以追溯到1979年,在unix版本7中,人们需要父进程和子进程的文件系统进行分离,从而提出了chroot,后来有了solaris zonebsd jail一系列早期的容器系统,逐步发到现在的dockerpodman等,从他们的发展路线可以看出,它是一种在操作系统层进行系统轻量级虚拟化的方案,它不再依赖传统的虚拟化技术,就可以快速的进行操作系统虚拟化,从本质上来讲,它是一种通过操作系统自身进行资源隔离系统虚拟的一种技术,它不依赖于任何指令模拟翻译甚至硬件模拟。

上面这2张图分别表示虚拟机和容器的运行结构,可以看出,容器技术更加的轻量级,不需要虚拟机监视器的支持,而只需要操作系统划分出隔离的空间来运行应用程序即可,所以它的高效是与生俱来的,不过容器较差安全性也与它的高效性如出一辙:

容器安全性差的问题几乎就是天生的,和虚拟机相比,容器更加容易发生逃逸,传统的虚拟机由于有hypervisor层的隔离,虽然理论上虚拟机也存在逃逸的可能,但就近几年来看虚拟机漏洞的情况,仅仅hypervisor来说,逃逸的漏洞还是非常少的,但容器不同,因为它共享宿主机的资源和内核,如果出现隔离不当或者内核出现漏洞,则会很容易发生逃逸,比如以下4种常见的容器逃逸场景:

一、特权容器

特权原本是为了方便开发人员,它允许特权容器访问系统的所有设备资源,从隔离性角度来说,这种容器会给系统带来极大的安全风险,下面这些操作将会轻松从容器中进行逃逸:

      # docker run privileged -it run centos bash

          [root@f733e8cafcbd] # mount /dev/dm-0 /mnt

      这里使用/dev/dm-0来进行mount是因为测试在宿主机采用devicemapper来管理的

          [root@f733e8cafcbd] # cd /mnt

 此时由于在重新在容器内部挂载了宿主机的root,在/mnt中已经是宿主机的根文件系统了,逃逸已完成,下一步可以通过访问宿主机文件系统进一步扩大访问权限,如添加ssh后门程序、爆破shadow文件等等。

二、危险的配置

docker容器允许启动时挂载宿主机的目录到容器中,所以一些危险的资源被挂载进容器后将会导致逃逸的发生,如/var/run/docker.sock/proc等等目录,当这些资源进入容器时,攻击者就可以利用这些资源逃逸容器

例如在docker容器中,如果/var/run/docker.sock被错误的映射进容器,那么攻击者只需要在容器内安装docker命令行,就可以利用/var/run/docker.sock操作容器,例如在容器内使用docker run -it -v /:/mnt apline bash重新映射宿主机的根目录到新容器的/mnt目录。docker除了可以映射目录到容器,docker还可以为容器添加一些权限,这些权限在使用的时候也需特别的注意,这些权限包括:

CAP_CHOWN:修改文件属主的权限

CAP_DAC_OVERRIDE:忽略文件的DAC访问限制

CAP_DAC_READ_SEARCH:忽略文件读及目录搜索的DAC访问限制

CAP_FOWNER忽略文件属主ID必须和进程用户ID相匹配的限制

CAP_FSETID:允许设置文件的setuid

CAP_KILL:允许对不属于自己的进程发送信号

CAP_SETGID:允许改变进程的组ID

CAP_SETUID:允许改变进程的用户ID

CAP_SETPCAP:允许向其他进程转移能力以及删除其他进程的能力

CAP_LINUX_IMMUTABLE:允许修改文件的IMMUTABLEAPPEND属性标志

CAP_NET_BIND_SERVICE:允许绑定到小于1024的端口

CAP_NET_BROADCAST:允许网络广播和多播访问

CAP_NET_ADMIN:允许执行网络管理任务

CAP_NET_RAW:允许使用原始套接字

CAP_IPC_LOCK:允许锁定共享内存片段

CAP_IPC_OWNER:忽略IPC所有权检查

CAP_SYS_MODULE:允许插入和删除内核模块

CAP_SYS_RAWIO:允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备

CAP_SYS_CHROOT:允许使用chroot()系统调用

CAP_SYS_PTRACE:允许跟踪任何进程

CAP_SYS_PACCT:允许执行进程的BSD式审计

CAP_SYS_ADMIN:允许执行系统管理任务如加载或卸载文件系统、设置磁盘配额等

CAP_SYS_BOOT:允许重新启动系统

CAP_SYS_NICE:允许提升优先级及设置其他进程的优先级

CAP_SYS_RESOURCE:忽略资源限制

CAP_SYS_TIME:允许改变系统时钟

CAP_SYS_TTY_CONFIG:允许配置TTY设备

CAP_MKNOD:允许使用mknod()系统调用

CAP_LEASE:允许修改文件锁的FL_LEASE标志

这些权限的错误使用也会导致严重的后果例如下面的命令:

# docker run cap-add=SYS_ADMIN -v /proc:/mnt ubuntu bash

[root@8ed982b95b57] # mount —bind /mnt /proc

          [root@8ed982b95b57] # ps -ef  

这将使容器内可以观察到容器外进程的情况,另外因为/proc被映射进容器,那么可以利用procfs进行逃逸操作,因为篇幅关系,这里不再阐述。

三、容器相关程序存在漏洞

docker的运行时runc, CVE-2019-5736,它是2019年时,波兰CTF战队Dragon Sector发现的一个漏洞,通过这个漏洞可以成功的逃逸docker容器。

相关PoC传送门(https://github.com/Frichetten/CVE-2019-5736-PoC)有兴趣的同学可以自己下载下来进行验证,调试。

四、linux内核漏洞

由于容器宿主机共享一个操作系统内核,如果linux内核出现漏洞,将威胁整个系统,任意一个可利用的可执行内核代码的漏洞都可以进行容器逃逸,即使无法运行代码的拒绝服务类漏洞也会导致整个宿主机出现宕机。例如大名鼎鼎的脏牛漏洞,通过脏牛漏洞可以修改VDSO内存空间中的代码,导致共享页中的payload得以执行,因为vdso为共享代码页,所以运行的代码大概率会在容器外运行,所以也就顺理成章的进行了逃逸

传送门(https://github.com/scumjr/dirtycow-vdso)

在以上威胁中, linux内核漏洞是容器面临的最大威胁,每年linux都会报告大量的来自内核的漏洞,在过去的十年间,linux内核的漏洞数量超过2500个,而在这些漏洞中,凡是能执行内核代码的漏洞都可以进行容器逃逸,而内核的拒绝服务类漏洞可以瘫痪整个宿主机。传统模式下,攻击者控制了单台节点后,仍需横向对其他节点进行缓慢渗透,才可慢慢控制整个系统,而在容器环境下,当攻击者进行容器逃逸成功后,攻击者将可以访问宿主机以及在上面的运行的所有容器业务,原本一次打包,到处运行的容器变成了一次入侵,控制一切。这些都给容器安全带来了巨大的挑战

对于应用越来越广泛的容器,各个厂商又是如何应对的呢?奇安信云与服务器安全BG【天择实验室】,提出2种加强容器安全性的思路:

1. 采用基于硬件虚拟化的方式来解决这一问题,可以理解为在容器的外层添加了一个虚拟机,让容器跑在虚拟机里,这样当发生容器逃逸时,因为有硬件虚拟机的隔离,使容器无法脱离虚拟环境,最终导致逃逸失败使用虚拟化技术隔离容器后的结构如下

2. 舍弃当前容器另起炉灶,例如google公司的gVisor,它是一款新型的沙箱,能够为容器提供安全隔离措施。gVisor的核心为一套运行非特权普通进程的内核,通过拦截应用程序系统调用来提供隔离边界,这相当于gVisor自己在应用层实现了兼容posix语义的内核,这个内核仅仅通过IPC和外界通信来获取资源,所以它的隔离性相当的好,但与此同时带来了兼容性差的新问题,gVisor沙箱结构如下

除了虚拟化和构建安全沙箱外,一些厂商也在尝试使用轻量级的虚拟机代替docker来满足自身的业务需求,如AWS的firecracker等,从上面这些厂商的努力可以看到一个共识:要有良好的安全隔离,就要阻断容器内程序对物理机内核的依赖。针对容器的保护技术近些年在蓬勃发展,未来让我们拭目以待。

文献参考:

http://www.dockone.io/article/9803

https://www.freebuf.com/articles/container/242763.html

关于作者:天择实验室,隶属于奇安信集团-云与服务器安全BG,实验室专注于针对云、服务器、容器等工作负载的攻击技术、恶意代码、威胁情报研究,并输出该领域的最前沿安全技术和产品原型。

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