Metarget / cloud-native-security-book

《云原生安全:攻防实践与体系构建》资料仓库

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

(勘误) P56 - 3.4.1.3 CVE-2019-5736:覆盖宿主机上的 runC 文件

XDTG opened this issue · comments

commented

书中攻击步骤中,对 #!/proc/self/exe 的作用理解存在问题:

5)runc 最后将执行用户通过 docker exec 指定的 /bin/sh,它的内容在第 1 步中已经被替换成 #!/proc/self/exe,因此实际上将执行宿主机上的 runc,而 runc 也已经在第 4 步中被我们覆盖掉了。

#!/proc/self/exe 的作用在这里应该是: 向容器中的监听进程提供一个 non-dumpable 的 runc 进程,以便对其 /proc/<pid>/exe 符号链接解引用,也就是第 3 步成功的前提。

至于最终 shellcode 的执行,需要等待宿主机上下一次执行已被修改的 runc 时直接触发。

https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/

commented

@XDTG 感谢反馈。首先,祝你新年快乐!

你的意思应该是“提供一个dumpable”的runC进程吧?你的理解是正确的,关于non-dumpable这一点我们在KCon 2022的议题《进退维谷:runC的阿克琉斯之踵》中也有提到。

我仔细看了下原文的表述,文中确实略去了更早的CVE-2016-9962漏洞和对应的non-dumpable修复方式,但是在对#!/proc/self/exe的解释上似乎不存在直接问题。原文中从下面引用部分开始介绍漏洞原理:

我们在执行功能类似于 docker exec 的命令(其他如 docker run 等类似,不再讨论)时, 底层实际上是容器运行时在操作。 例如 runC, 相应地,runc exec 命令会被执行。 它的最终效果是在容器内部执行用户指定的程序。 进一步讲,就是在容器的各种命名空间内, 受到各种限制(如 Cgroups)的情况下, 启动一个进程。 除此以外, 这个操作与在宿主机上执行一个程序并无二致。执行过程大体如下:runC 启动并加入到容器的命名空间, 接着以自身(“ /proc/self/ exe”, 后面会解释)为范本启动一个子进程, 最后通过 exec 系统调用执行用户指定的二进制程序。

在这一上下文背景下,后面介绍了/proc/self/exe作为magic links无视namespaces限制的特性,接着介绍了1-5的漏洞利用步骤。你提到的#!/proc/self/exe的作用没有问题,不过另一方面这个magic links的直接语义也确实是执行宿主机上的runC,从这一点来讲原文的攻击步骤并无问题。

关于你提到的另外一点,shellcode的执行,这里原文确实存在一些语义不清的问题。一开始的上下文其实是docker exec,而这条命令的底层其实对应着两次runC的执行,这也是为什么执行一次docker exec就能触发漏洞的原因。然而,后面攻击步骤的描写过于偏重runC,容易被误解成一次runC执行中实现覆盖和shellcode执行。

因此,参考你的解读,我觉得可以对原文作以下两处修正:

  1. 增加对#!/proc/self/exe的必要性的解释(non-dumpable -> dumpable),这里或可提到CVE-2016-9962漏洞。
  2. 在攻击步骤中明确给出上下文,消除“一次runC执行中实现覆盖和shellcode执行”的歧义。

你觉得这样修正是否合理?如有不同理解,欢迎继续讨论。

书中攻击步骤中,对 #!/proc/self/exe 的作用理解存在问题:

5)runc 最后将执行用户通过 docker exec 指定的 /bin/sh,它的内容在第 1 步中已经被替换成 #!/proc/self/exe,因此实际上将执行宿主机上的 runc,而 runc 也已经在第 4 步中被我们覆盖掉了。

#!/proc/self/exe 的作用在这里应该是: 向容器中的监听进程提供一个 non-dumpable 的 runc 进程,以便对其 /proc//exe 符号链接解引用,也就是第 3 步成功的前提。

至于最终 shellcode 的执行,需要等待宿主机上下一次执行已被修改的 runc 时直接触发。

https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/

commented

hi @brant-ruan , 抱歉我没有及时看到你的回复~

你的意思应该是“提供一个dumpable”的runC进程吧?

是的,这里我说错了

我觉得你的修改很合理,这两条也是我分析时候关注的内容,感谢你的耐心回复 ;)