研究人员在Linux kernel中发现一个权限提升漏洞——CVE-2022-0492,该漏洞存在于Linux kernel 特征control groups(cgroups)中,漏洞CVSS评分7.0分。攻击者利用该漏洞可以实现容器逃逸,在容器主机上执行任意命令。
Cgroups是Linux的一个特征,允许进程进行分层分组,以限制和监控CPU、内存、硬盘I/O和网络等资源的使用。Linux支持2种cgroup架构,v1和v2。CVE-2022-0492漏洞影响的是应用最广泛的cgroup v1。
CVE-2022-0492漏洞根源分析
cgroups v1有一个特征——release_agent文件,该文件允许管理员配置release agent程序,通过写入目标release agent路径到release_agent文件,如下所示:
$ echo /bin/my-release-agent > /sys/fs/cgroup/memory/release_agent
release_agent文件只可在root cgroup目录下可见。每个子组(child group)可以通过写入notify_on_release文件来重新配置为触发或不触发release agent。
$ echo 1 > /sys/fs/cgroup/memory/a_child_cgroup/notify_on_release
进程终止后,kernel会检查其cgroups是否启用了notify_on_release,如果启用了就派生出配置的release_agent二进制文件。release agent会以最高的权限运行。配置release agent是被认为是一个特权操作,允许其决定哪个二进制文件可以以完全root权限来运行。
CVE-2022-0492 漏洞产生的根源是因为没有进行验证。Linux并不会检查设置release_agent 文件的进程是否有管理权限。
漏洞利用
因为Linux将release_agent 文件的所有者设置为root,只有root才可以写入。因此,该漏洞只允许root进程提升权限。
并不是每个容器都可以利用CVE-2022-0492 漏洞来实现逃逸,只有具有特定权限的才可以执行。Cgroup mounts挂载在容器内只读,所以release_agent 文件无法写入。想要利用该漏洞的恶意容器必须要挂载到另一个可写的cgroupfs。
图 Cgroupfs挂载在容器内是只读的(ro)
AppArmor和SELinux 都可以预防挂载,这表示运行的容器是受保护的。容器挂载cgroupfs的方式有2种:滥用用户命名空间或CAP_SYS_ADMIN能力。
默认情况下,容器是没有CAP_SYS_ADMIM能力的,也无法在初始的用户命名空间内挂载cgroupfs。但是通过unshare()系统调用,容器就可以创建具有CAP_SYS_ADMIN能力的新的用户和cgroup 命名空间,并可以挂载cgroupfs。
图 容器创建新的具有CAP_SYS_ADMIN能力的用户命名空间
也不是每一个容器都可以创建新的用户命名空间的,背后的主机必须有启用非特权的用户命名空间。比如,最新的Ubuntu版本就默认启用了。因为Seccomp 会拦截unshare() 系统调用,只有没有运行Seccomp的容器才能创建新的用户命名空间。下图中的容器就没有运行Seccomp、AppArmor或SELinux:
图 容器挂载内存cgroup到新用户和cgroup命名空间
如上图所示,容器成功挂载到了内存cgroup,但release_agent 文件并不包含在挂载的目录中。
release_agent 文件只有root cgroup才可见。为使release_agent文件可对cgroup mount可见,容器必须在子系统的root cgroup下运行。
为利用该漏洞,需要将恶意release agent 写入release_agent 文件。
图 设置release agent的root容器
图 非root容器无法设置release agent
逃逸的最后一步是调用配置的release_agent,这一步并不需要任何权限。
图 通过用户命名空间利用CVE-2022-0492实现容器逃逸
完整技术细节参见:https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/