CVE-2019-14271
前置知识
linux
的shell
命令真的有点多。。。我的基础还是太薄弱。。
用一串命令跟踪docker-tar
进程的/proc/self/root
:
1 | root@ubuntu:~/escape/cve-2019-14271# docker cp test:/lib ./lib & while true; do ps -auxf|grep -v grep|grep docker-tar|tr -s ' '|cut -d ' ' -f 2|xargs -I{} ls -l /proc/{}/root; done |
了解lief
的用法,这个工具之前学过patch
的师傅肯定都会用。
mount
命令进阶用法:
https://www.cnblogs.com/sparkdev/p/9015312.html
https://www.cnblogs.com/sparkdev/p/9045563.html
https://xionchen.github.io/2016/08/25/linux-bind-mount/
搭建环境
此漏洞影响版本只有19.03.0
,使用脚本搭建环境:
1 | curl -fsSL https://get.docker.com -o get-docker.sh && \ |
1 | FROM ubuntu:16.04 |
漏洞分析
CVE-2019-14271
是一个宿主机docker cp
容器文件到宿主机导致的以宿主机root
权限任意命令执行的漏洞,目前已知的影响版本只有docker 19.03.0
(包含几个beta版),19.03.1
以上以及18.09
以下都不收影响。
漏洞起源于docker开源项目issue上docker19.03.0
版本docker cp
产生的报错,其因为容器中无libnss_files.so.2
报错,让安全人员发觉docker-tar
加载的是容器中的libnss_files
库:
Error response from daemon: error processing tar file: docker-tar: relocation error: /lib/arm-linux-gnueabihf/libnss_files.so.2: symbol __libc_readline_unlocked, version GLIBC_PRIVATE not defined in file libc.so.6 with link time reference : exit status 127
issue链接:https://github.com/moby/moby/issues/39449
docker cp
命令可以允许用户将文件在宿主机、容器之间来回复制,这个过程涉及到一个重要进程docker-tar
,docker-tar
的作用是chroot
到容器中,将请求复制的文件打包,然后传回给dockerd
并由其提取打包后的文件到宿主机上。需要注意的是docker-tar
进程是由dockerd
起的,验证如下:
此外还涉及到一个chroot
的动作,执行此动作主要是为了docker-tar
切入容器内部对复制文件进行打包,如果不chroot
,很有可能会造成符号链接攻击https://blog.csdn.net/weixin_34414650/article/details/91427942,导致宿主机cp的容器的符号链接指向自身,这有可能导致容器恶意构造符号链接来读写宿主机文件,所以新版的`docker`选择利用`docker-tar chroot进容器系统进行复制,这样复制时就难以出现符号链接问题了。但是,
19.03.0版本由于不严谨的
chroot导致
docker容器出了一个严重问题,
docker-tar进程依赖linux主机上的动态库文件,而动态链接库在不调用其中相关函数的时候是不进行链接的,这边
docker-tar未进行链接就先
chroot进容器内部,之后寻找路径过程中才会用到相关函数并进行动态链接,而这时
docker-tar进程已经切进容器内部了,这边就导致宿主机的进程会使用容器内部的so库,一旦此容器是恶意的(so库被提前更改)或者
docker`容器被入侵(攻击者替换so库),很容易导致宿主机被代码执行。
chroot
验证:
漏洞利用
先进入容器进行恶意构造,在/tmp
目录中构造/tmp/exp
程序(用于检测docker-tar
进程以及中转利用脚本),/tmp/escape
脚本(实际的利用脚本),patch.py
脚本(对libnss_files-2.23.so
进行patch
,将/tmp/exp
加入其依赖库中),具体内容如下:
/tmp/exp.c
:
用/proc/self/exe
来检测的原因是docker-tar
虽然chroot
到了容器中,但其本身还在宿主机的namespace
中,所以在容器中用/proc/self/exe
是看不到其路径的,也就是返回会为NULL
,而容器中的其他进程都可以成功看到,返回不为NULL
。
1 |
|
/tmp/escape
:
1 |
|
/tmp/patch.py
:
1 | import lief |
构造好之后,在容器中:
1 | cd /tmp |
然后在宿主机中触发漏洞:
1 | docker cp test:/var/log ./logs |
最终效果:
参考
https://bestwing.me/CVE-2019-14271-docker-escape.html#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90