CVE-2024-21626 从容器内逃逸到宿主机文件系统

最近很火的一个 CVE,核心问题是 docker (runc) 在运行用户的代码之前,会 O_CLOEXEC 关闭所有的 fd——这是正确的——但是运行用户代码之前,在 setcwd(2) 的时候,fd 还没有被关闭。这就导致 docker rundocker exec 的时候,去通过 -w 参数设置 working directory, 并且设置成一个还没有关闭的 fd ,就能拿到宿主机上的文件路径,从而进入到宿主机。

这个攻击有两个依赖:

  • 能够在容器内部执行代码;
  • 能够设置容器的 working directory (docker run, docker exec, 甚至 docker build 都可以)

演示

在一个全新的 Linux 机器上复现这个攻击。

环境准备

准备一个新的 VM,需要安装的依赖有:

  1. 依赖 golang 1.22 和 libseccomp-dev 来编译指定版本的 runc;
  2. 依赖 build-essential 编译 runc;
  3. 依赖 docker engine,指定版本的 runc;

第一步:按照官方文档安装最新版本的 docker。

第二步:替换 runc (最新版已经解决这个问题了)到旧版本,这里我们使用 v1.0.0-rc10. 编译脚本如下:

安装完成旧版本的 runc 之后需要重启 docker engine:sudo systemctl restart docker.

攻击演示

创建一个 Dockerfile:

编译这个 docker image: docker build . -t test

最后运行这个 docker image: docker run --rm -ti test.

可能一次运行不会成功,多运行几次会成功。

进入 container,此时 cwd 显示 .

通过相对路径,我们可以回到 Host 上面的 / 了:

打开 Host 上面的文件

如果我们安装运行 htop,会发现只有自己的容器里面的进程:

htop 只显示自己容器的 pid

但是如果我们改变当前容器的 fs root: chroot . ,再次运行 htop,就可以看到所有的进程了。

chroot ps 可以显示所有的 pid
htop 也可以显示所有的 pid

但是试了下发送 signal 开 kill 进程是不行的,我猜是因为 pid namespace 仍然是对进程隔离的?

甚至可以在容器内运行docker 命令,看到所有的 container。因为有了 docker binary 的路径(和权限,因为容器进程也是 root)和 docker socket 的路径。

在容器内 docker ps

相关链接:



CVE-2024-21626 从容器内逃逸到宿主机文件系统”已经有2条评论

Leave a comment

您的电子邮箱地址不会被公开。 必填项已用 * 标注