介绍

CVE-2022-36109是一个存在于Moby的中危漏洞,利用条件苛刻,利用后果有限。漏洞曝光后有同事收到客户关于此漏洞的询问,需求转到我这里,以下为当时的简要分析。

漏洞性质

该漏洞是存在于若干容器运行时的一个权限配置不当漏洞。可能导致的后果是,在特定条件下,容器内的攻击者能够绕过容器内敏感文件对特定用户组的限制,访问该敏感文件。Docker官方判定该漏洞为低危。该漏洞需要在比较苛刻的条件下触发,场景非常少见,且影响有限。

简要分析

在Linux中,一个文件的常见访问控制属性分为面向所属者、面向某群组、面向其他人三类。例如,/etc/shadow文件的权限通常设置为640,这意味着文件所属者(也就是root)可以读写,群组成员可以读,其他用户既不能写也不能读。因此,对于某个普通用户执行的进程来说,能否访问一个文件依次取决于他是不是该文件的所属者、群组成员。如果是该文件所属者,则使用前述文件属性中“面向所属者”部分判定该用户的访问权限;如果该用户是群组成员之一,则使用前述文件属性中“面向某群组”部分判定该用户的访问权限;如果以上两条均不符合,则该用户属于“其他”类型,使用前述文件属性中“面向其他人”部分判定该用户的访问权限。

然而,在Linux系统中,同一用户可以属于多个组(一个首选用户组+若干补充用户组)。在某用户执行的进程具有的权限中,首选用户组egid和补充用户组也均存在。因此,对于上一段我们描述的文件访问检查流程来说,Linux将依次检查该访问进程的首选用户组和补充用户组,只要有一个命中,则可以使用文件属性中“面向某群组”部分判定。

现在考虑一种特殊的情况:如果某文件的访问属性被设置为606,也就是允许所属者读写、允许其他人读写,但是不允许所属群组读写。这种情况非常少见,但是客观上是能够这样设置的,某些场景下可能会借助这种机制实现基于用户群组的黑名单。在这种情况下,如果某个访问进程不是该文件的所属者,同时该进程的首选用户组和补充用户组中却包含该文件所属用户组,那么该用户将不能对该文件具有任意读写操作。

另外注意,Linux允许进程修改自己的首选用户组为进程用户所属的补充用户组范围内的用户组ID。

我们假设某UID为1000的用户A,首选用户组为1000,补充用户组包括1001、1002;假设存在一个文件secret的所属者为root用户,所属群组为1000,但是该文件设置的文件访问属性为606,也就是说不允许所属群组1000访问。那么,用户A直接访问该文件将被拒绝。但是如果该用户创建了一个程序prog,该程序能够将自己的首选用户组临时修改为用户A的补充用户组之一(比如1001),然后再去向文件secret发起访问。此时,如果在Linux系统上,在程序prog启动并修改自己的首选用户组为1001后,系统将自动把原来的首选用户组1000加入到补充用户组。这样一来,即使程序prog的首选用户组已经不是1000,但是在访问文件时系统发现文件所属组1000依然在程序prog的补充用户组中,因此按照文件的“面向群组”属性判断该程序无法访问该文件。也就是说,在正常情况下,用户A无法绕过自己的用户组限制去访问文件secret。

但是,在存在漏洞的容器环境中,如果某容器镜像文件中按照上一段描述的场景设置了相同的用户、用户组和文件,那么容器中的程序prog启动进程一旦把自己的首选用户组切换为1001后,原首选用户组1000不会被容器运行时加入到该进程的补充用户组,因此此时程序prog在访问文件secret时,系统发现文件所属群组1000既不在该进程的首选用户组,也不在补充用户组范围,因此将按照文件的“面向其他人”属性判定访问权限。由于文件secret的访问属性为606,因此其他人实际上有权限读写该文件。最终,用户A绕过了文件所属组的“黑名单”限制,成功以其他人身份读写文件。

修复方案

修复后,容器运行时管理程序在处理上述容器时,将按照Linux系统的处理规则,同样自动把原来的首选用户组1000加入到补充用户组。

缓解方案

如果暂时无法升级相关容器运行时组件,可以检查一下业务使用的Dockerfile中是否以USER $USERNAME形式设置了启动用户,如果有,建议替换为ENTRYPOINT ["su", "-", "user"]的方式设置启动用户[2]。另外,我们建议也可以排查容器内是否存在“所属组权限”小于“其他人权限”的敏感文件,该漏洞的利用效果只影响容器内的这些文件。

相关资料

  1. NVD描述:https://nvd.nist.gov/vuln/detail/CVE-2022-36109
  2. Docker官方通告:https://github.com/moby/moby/security/advisories/GHSA-rc4r-wh2q-q6c4
  3. PoC: https://github.com/sjmurdoch/permission-experiment/