以下内容为自己个人的学习笔记,因此内容不会多么详实;其中有些内容也许会存在错误,如有错误欢迎留言处指出,还望谅解。
这里以 Docker 为例,来学习学习容器基础设施中存在的一些风险问题。
下图是 Docker 官方给出的架构图,里面包括了 Docker 客户端、Docker 容器所在的宿主机和 Docker 镜像仓库三个部分。
其中宿主机包括了 Docker 守护进程、本地容器和本地镜像,Docker 守护进程(dockerd)的作用是侦听 Docker API 请求和管理 Docker 对象。
例如开发者在代码中引入了存在漏洞版本的 log4j2 组件,然后将其打包成了业务镜像。这样即使代码没有漏洞,但因为引入了不安全的第三方组件也变得有漏洞了。
再比如开发者在 Django 镜像的基础上,编写了自己的 Python 代码,然后将其打包成镜像。这样如果在 Django 镜像里引用了不安全的第三方组件或者 Django 自身存在漏洞,自己打包的镜像也同样会受到影响。
在公共镜像仓库比如 Docker Hub 里,会存在一些有漏洞的镜像或者恶意镜像,如果使用了这些镜像那就存在风险了。
如果开发者为了开发、调试方便,可能会将数据库账号密码、云服务密钥之类的敏感数据打包到了镜像里,那别人获取到这个镜像后,就会导致敏感信息泄露了。
在使用容器时,往往会需要进行端口映射,比如把 MySQL 的 3306 端口映射出来,如果 MySQL 被配置了弱密码,那就存在被利用的风险了。
除此之外,如果一个 Web 服务端口被映射出来,同时这个 Web 服务存在漏洞,那么也同样是存在风险的。
容器运行在宿主机上,容器必然要使用宿主机的各种 CPU、内存等资源,如果没有对容器进行资源使用限制,那么就存在宿主机被资源耗尽的风险。
如果为容器设定了不安全的配置,会导致容器本身的隔离机制失效,容器的两大隔离机制如下:
如果设定了以下配置就会导致相应的隔离机制失效:
Docker 守护进程主要监听 UNIX socket 和 TCP socket,默认情况下,Docker 只会监听 UNIX socket
UNIX socket 的风险主要在于 Docker 守护进程默认以宿主机的 root 权限运行,因此就可以借助这点进行提权或者容器逃逸。
这类风险主要有两个利用场景:
如果普通用户被加入到 Docker 用户组内,那么普通用户也将有权限访问 Docker UNIX socket,如果攻击者获得了这个普通用户权限,就可以借助 Docker 提权到 root 用户权限。
具体的做法可以简单描述为:使用普通用户创建一个 privileged 为 true 的容器,在该容器内挂载宿主机硬盘并写入定时任务,然后将宿主机的 root 权限反弹回来,后期将详细介绍这种方法的使用。
有时为了实现容器内部管理容器,可能会将 Docker UNIX socket 挂载到容器内部,那么如果该容器被入侵,RT 就可以借助这个 socket 进行容器逃逸获得宿主机 root 权限。
现在 Docker 守护进程默认不会监听 TCP socket,不过有时可能用户会因为方便开启 TCP socket 的监听,一般默认监听端口是 2375
默认情况下,Docker 守护进程 TCP socket 是无加密无认证的,因此如果发现宿主机 Docker 开放了 TCP socket,就可以直接使用 docker -H 接管目标的容器
虽然默认情况下,容器内部的网络与宿主机是隔离的,但是每个容器之间是彼此互相连通的,理论上在容器之间是存在内网横向的风险的。
容器通常与宿主机共享内核,也就是说如果宿主机内核存在漏洞,意味着容器可能也会存在相同的漏洞。
例如如果宿主机存在脏牛漏洞,那么拿到容器权限后,使用脏牛漏洞就可以获得宿主机权限,实现容器逃逸。
Docker 自身存在的一些漏洞,比如 CVE-2019-14271、CVE-2019-5736 等都可以导致容器逃逸,这些也都是风险点,后面会对这些漏洞进行尝试复现。
原文链接:https://www.teamssix.com/220307-162000.html 参考资料: 《云原生安全-攻防实践与体系构建》 https://docs.docker.com/get-started/overview/ https://www.freebuf.com/articles/web/258398.html https://cloud.tencent.com/developer/article/1428102