Closed XDTG closed 1 year ago
@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执行。
因此,参考你的解读,我觉得可以对原文作以下两处修正:
#!/proc/self/exe
的必要性的解释(non-dumpable -> dumpable),这里或可提到CVE-2016-9962漏洞。你觉得这样修正是否合理?如有不同理解,欢迎继续讨论。
书中攻击步骤中,对
#!/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/
hi @brant-ruan , 抱歉我没有及时看到你的回复~
你的意思应该是“提供一个dumpable”的runC进程吧?
是的,这里我说错了
我觉得你的修改很合理,这两条也是我分析时候关注的内容,感谢你的耐心回复 ;)
书中攻击步骤中,对
#!/proc/self/exe
的作用理解存在问题:#!/proc/self/exe
的作用在这里应该是: 向容器中的监听进程提供一个 non-dumpable 的 runc 进程,以便对其 /proc/\<pid>/exe 符号链接解引用,也就是第 3 步成功的前提。至于最终 shellcode 的执行,需要等待宿主机上下一次执行已被修改的 runc 时直接触发。
https://unit42.paloaltonetworks.com/breaking-docker-via-runc-explaining-cve-2019-5736/