moby容器逃逸-CVE-2019-14271复现
2023-2-18
| 2024-2-3
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password

漏洞环境

环境部署
漏洞影响版本
  • Docker < 19.03.1
拉一个 alpine 镜像
这里如果用 ubuntu 镜像会出现问题
不过后面利用的时候好像 ubuntu 镜像又好了,很神奇…
漏洞描述
The vulnerability can be exploited, provided that a container has been compromised by a previous attack (e.g. through any other vulnerability, leaked secrets, etc.), or when a user runs a malicious container image from an untrusted source (registry or other). If the user then executes the vulnerable cp command to copy files out of the compromised container, the attacker can escape and take full root control of the host and all other containers in it.

前置知识

docker cp 命令是用来在容器和宿主机之间拷贝文件的,比如把容器中的 /var/logs 目录拷贝到本机
这里在容器内通过 dd/var/log 新建了个大文件,以便于捕捉复制文件时的进程。如下,当我们执行 docker cp 时,通过 ps 看到运行了一个 docker-tar 的进程从容器内打包文件
notion image
/var/lib/docker/overlay2/3f5442ab960e56e8e34cfda288b5ec4d313b51b53319e4671a8d8add0c397369/merged/ 为容器文件系统根目录,var/log 即为日志目录
notion image
通过查看进程的根目录发现 ls -l /proc/29989/root ,执行 docker-tar 时会 chroot 至容器目录,因为这可以避免一些恶意软链接文件至宿主问题。尽管 chroot 至容器可以避免恶意软链接,但通过CVE-2019-14271 仍可进行逃逸

漏洞分析

Docker主要是通过Go编写,存在 漏洞Docker版本通过Go 1.11 编译,这个版本一些包含嵌入式C代码(cgo)会在运行时动态加载共享库。docker-tar 使用了 net 和 os/user 包,它们在运行时都会加载 libnss_*.so 动态链接库,本来是没有问题的,因为是加载宿主机上的 .so ,但打包容器内的文件时,会通过 chroot 进入容器内,导致加载了容器内的 .so,但容器内的 .so 是可被篡改的,而运行打包命令是宿主机环境,从而导致逃逸。
 
docker-tar 调用栈
  1. https://github.com/docker/docker-ce/blob/v19.03.0/components/engine/pkg/chrootarchive/init_unix.go#L17
  1. https://github.com/docker/docker-ce/blob/v19.03.0/components/engine/pkg/chrootarchive/archive_unix.go#L178
  1. https://github.com/docker/docker-ce/blob/v19.03.0/components/engine/pkg/chrootarchive/archive_unix.go#L135
  1. https://github.com/docker/docker-ce/blob/v19.03.0/components/engine/pkg/chrootarchive/chroot_linux.go#L105
 
经分析我们需要构造一个恶意的 .so库,用于加载我们的恶意代码。报错信息写的是加载 libnss_files.so.2 那我们就改这库的源码。查阅文档得知可通过构造方法让进程在加载动态链接库时先初始化构造函数,也就是说 docker-tar 执行时会动态加载我们的恶意库中的恶意函数,简化后的代码如下
此函数通过检测 /proc 目录是否为空来判断自己是否运行在 docker-tar 上下文中,如为空则是运行在 docker-tar 上下文中,如非空则为其他正常的容器进程加载这个动态链接库,因为 /proc 上的procfs挂载只存在于容器挂载上下文中。
 
如果是通过 docker-tar 调用的此库,先把恶意库恢复为原来的,防止其他进程再一次出发我们的脚本,其中 /breakout 是我们要运行的shell脚本,方便我们改要运行的命令
 
据说漏洞发现是由一个外国老哥遇到一个docker cp 复制文件问题引起的https://github.com/moby/moby/issues/39449 ,报错信息写着加载到了 libnss_files.so.2 文件

漏洞利用

执行docker cp后即触发漏洞主要有两种方式
  1. 拉取一个攻击者构造恶意 libnss_*.so 动态链接库的容器
  1. 攻击者获取到容器内一定权限,可以替换 libnss_*.so
notion image

漏洞修复

在 chrootarchive 包初始化时先加载 libnss 动态链接库,因为 usernet 这两个包的方法会加载到,只要调用了, 这时加载是从宿主机加载 libnss 动态链接库,宿主机的库从容器内无法更改,从而避免逃逸问题。
 
关于漏洞修复 ssst0n3 师傅分析的更为深入,膜拜

参考

  • 云安全
  • 漏洞复现
  • 容器逃逸之AppArmor绕过-CVE-2019-16884复现runC容器逃逸-CVE-2019-5736复现
    • GitTalk
    目录