CVE-2019-5736 Docker逃逸
前言: 最近公开了一个 Docker逃逸的漏洞,在35c3 ctf结束后,由 dragonsecto 发现。CVE-2019-5736: Escape from Docker and Kubernetes containers to root on host就此自己稍微分析了一下原理。
0x01 RunC
众所周知,RunC 是一个轻量级的工具,它是用来运行容器的,只用来做这一件事,并且这一件事要做好。我们可以认为它就是个命令行小工具,可以不用通过 docker 引擎,直接运行容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运行容器。而 OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准。
换一句话说,其实 Docker 在管理容器的时候,其实底层就是跑的RunC
1 | root@VM-118-78-ubuntu:~# docker info | grep "runc" |
从图中就可以得知,runc 和docker 的命令执行效果其实是差不多的。
0x02 PID NameSpace
PID Namespace 隔离进程pid之后,ns中的进程无法发现外界的进程。而外部ns中进程可以发现ns中进程。
0x03 漏洞利用点
另外一个值得注意的是 /proc/self/exe
可以发现 proc/pid/exc
正常是会被指向所运行文件。而这个漏洞的漏洞利用点正在于此,如果使用此时用 docker exec binfile
。此时如果能在容器内,拿到 runc 的pid 从而获取 runc 的符号链接。
那么我们就能通过覆盖 runc 为恶意程序来达到 Docker 逃逸的目的。
0x04 漏洞利用
- 容器内想办法获取 Runc PID。
- 得到 PID 后,获取文件描述符
- 对 fd 进行写操作,覆盖原有 runc
- 获取 RunC的PID,我们知道 容器内的PID 是通过namespace 特殊隔离的,通常而言,如果此时有进程 A ,进程 A 的PID为 233,那么下一步我们运行个进程 B,那么此时进程 B 的PID理应为 234
- 获取文件操作符
1 | if 'runc' exe_name: |
- 然后就可以 通过打开 fd 的形式,对 runc 文件进行操作。
演示效果如下:
请全屏观看!!!
0x05 补丁分析
可以看到 添加了一个 ensure_cloned_binary 函数。
1 | int ensure_cloned_binary(void) |
首先判断 exe 是否被clone
1 | static int is_self_cloned(void) |
如果否,则执行 clone_binary 函数
1 | static int clone_binary(void) |
return 一个新的 fd
0x06 参考链接
CVE-2019-5736 docker image and exploit
CVE-2019-5736: Escape from Docker and Kubernetes containers to root on host