返回介绍

4 相关程序漏洞导致的容器逃逸

发布于 2024-09-13 00:02:18 字数 2739 浏览 0 评论 0 收藏 0

4.1 CVE-2019-5736

影响版本: Docker version <= 18.09.2 & RunC version <= 1.0-rc6

4.1.1 原理

CVE-2019-5736 一个能够覆盖宿主机 runc 程序的容器逃逸漏洞。

在执行功能类似于 docker exec 等命令时,底层实际上是容器运行时在操作。例如 runC,相应地, runc exec 命令会被执行。它的最终效果是在容器内部执行用户指定的程序。进一步讲,就是在容器的各种命名空间内,受到各种限制(如 Cgroups)的情况下,启动一个进程。除此以外,这个操作与在宿主机上执行一个程序并无二致。

执行过程大体如下:runC 启动并加入到容器的命名空间,接着以自身 ( /proc/self/ exe )为范本启动一个子进程,最后通过 exec 系统调用执行用户指定的二进制程序。

proc 伪文件系统,即 /proc。关于这个概念,这里我们主要关注 proc 下的两类文件:

  • /proc/[PID]/exe :它是一种特殊的符号链接,又被称为 magic links , 指向进程自身 对应的本地程序文件(例如我们执行 ls /proc/[ls-PID]/exe 就指向 /bin/ls )。
  • /proc/[PID]/fd/ :这个目录下包含了进程打开的所有文件描述符。

/proc/[PID]/exe 的特殊之处在于,当打开这个文件时,在权限检查通过的情况下,内核将 直接返回一个指向该文件的描述符,而非按照传统的打开方式做路径解析和文件查找。这样 一来,它实际上绕过了 mnt 命名空间及 chroot 机制对一个进程能够访问到的文件路径的限制。

那么,设想如下攻击场景:在 runc exec 加入到容器的命名空间之后,容器内进程已经能够 通过内部 /proc 观察到它,此时如果打开 /proc/runc-[PID]/exe 并写入一些内容,就能够实现 将宿主机上的 runc 二进制程序覆盖掉。这样一来,下一次用户调用 runc 来执行命令时,实 际执行的将是攻击者放置的指令。

在存在漏洞的容器环境内,上述思路是可行的,但是攻击者想要在容器内实现宿主机 上的代码执行(逃逸),还需要突破两个限制:

  1. 用户权限限制,需要具有容器内部 root 权限。
  2. Linux 不允许修改正在运行的进程对应的本地二进制文件。

事实上,很多容器就是以 root 身份启动服务的。

攻击步骤:

  • 将容器内的 /bin/sh 程序覆盖为 #!/proc/self/exe
  • 持续遍历容器内 /proc 目录,读取每一个 /proc/[PID]/cmdline ,对 runc 做字符串 匹配,直到找到 runc 进程号。
  • 以只读方式打开 /proc/[runc-PID]/exe ,拿到文件描述符 fd。
  • 持续尝试以写方式打开第 3 步中获得的只读 fd ( /proc/self/fd/[fd] ),一开始总是返回失败,直到 runc 结束占用后写方式打开成功,立即通过该 fd 向宿主机上的 /usr/bin/runc ,(名字也可能是 /usr/bin/docker/runc )写入攻击载荷
  • runc 最后将执行用户通过 docker exec 指定的 /bin/sh ,它的内容在第 1 步中已经被替换成 #/proc/self/exe ,因此实际上将执行宿主机上的 runc,而 runc 也已经在第 4 步中被覆盖掉了。

4.1.2 复现

./metarget cnv install cve-2019-5736

POC

payload 的内容:

var payload = "#!/bin/bash \n cat /etc/shadow > /tmp/shadow && chmod 777 /tmp/shadow"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文