Linux文件系统层中的本地提权漏洞(CVE-2021-33909)

  • A+
所属分类:安全漏洞
Linux文件系统层中的本地提权漏洞(CVE-2021-33909)点击上方蓝字关注我们


Linux文件系统层中的本地提权漏洞(CVE-2021-33909)

概述


Qualys研究人员在Linux内核文件系统层中,发现了一个影响大多数Linux系统的size_t-to-int类型转换漏洞。通过在默认配置中利用此漏洞,任何非特权(本地)用户都可以在易受攻击的主机上获得root权限。

文件系统是对一个存储设备上的数据和元数据进行组织的机制,其目的是易于实现数据的查询和存取。Linux文件系统接口实现为分层的体系结构,将用户接口层、文件系统实现和操作存储设备的驱动程序分开。它是任何操作系统中最重要的功能,并且存在于所有主要的Linux操作系统中。


影响


成功利用此漏洞,可使任何非特权(本地)用户在易受攻击的主机上获得root权限。Qualys研究人员已经能够独立验证该漏洞,开发多种利用方式,并在Ubuntu 20.04、Ubuntu 20.10、Ubuntu 21.04、Debian 11和Fedora 34 Workstation上获得的完整的root用户权限。其他Linux发行版也可能会被利用。以下是该漏洞的概念验证(PoC)视频:


技术细节


Linux内核的seq_file接口生成包含记录序列的虚拟文件,例如/proc中的许多文件是 seq_files,而记录通常是行。每个记录都必须放入一个seq_file缓冲区,因此可以根据需要扩大缓冲区大小,方法是在第242行对其大小进行加倍,seq_buf_alloc()是kvmalloc()的简单封装器:


168 ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)169 {170         struct seq_file m = iocb->ki_filp->private_data;  205         / grab buffer if we didn't have one */206         if (!m->buf) {207                 m->buf = seq_buf_alloc(m->size = PAGE_SIZE);210         }220         // get a non-empty record in the buffer223         while (1) {227                 err = m->op->show(m, p);236                 if (!seq_has_overflowed(m)) // got it237                         goto Fill;238                 // need a bigger buffer240                 kvfree(m->buf);242                 m->buf = seq_buf_alloc(m->size <<= 1);246         }


该大小乘法本身并不是一个漏洞,因为m->size是一个size_t(在x86_64上是一个无符号的64位整数),并且在此乘法溢出整数m->size之前,系统将耗尽内存。不幸的是,这个size_t也会被传递给size参数是int(有符号的32位整数)而不是size_t的函数。例如,在第227行为格式化/proc/self/mountinfo中的记录而调用的show_mountinfo()函数,将在第150行调用seq_dentry(),seq_dentry()将在第530行调用dentry_path(),最终dentry_path()将在第387行调用prepend():


135 static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)136 {150                 seq_dentry(m, mnt->mnt_root, " tn");------------------------------------------------------------------------523 int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)524 {525         char *buf;526         size_t size = seq_get_buf(m, &buf);529         if (size) {530                 char *p = dentry_path(dentry, buf, size);------------------------------------------------------------------------380 char *dentry_path(struct dentry *dentry, char *buf, int buflen)381 {382         char *p = NULL;385         if (d_unlinked(dentry)) {386                 p = buf + buflen;387                 if (prepend(&p, &buflen, "//deleted", 10) != 0)------------------------------------------------------------------------11 static int prepend(char **buffer, int *buflen, const char *str, int namelen)12 {13         *buflen -= namelen;14         if (*buflen < 0)15                 return -ENAMETOOLONG;16         *buffer -= namelen;17         memcpy(*buffer, str, namelen);


因此,如果无特权的本地攻击者创建、挂载和删除总路径长度超过1GB的深层目录结构,并且如果攻击者打开和阅读/proc/self/mountinfo,则:


  • 在seq_read_iter()中,vmalloc()分配2GB缓冲区第242行,并调用show_mountinfo()第227行


  • 在show_mountinfo() 中,使用空的2GB缓冲区调用seq_dentry()(第150行);


  • 在seq_dentry() 中,dentry_path()以2GB大小被调用(第530行);


  • 因此在dentry_path() 中,int buflen为负数(INT_MIN,-2GB),p指向vmalloc()分配的缓冲区下方的-2GB偏移量(第386行),并调用prepend()(第387行);


  • 在prepend() 中,*buflen减少10个字节,并变成一个很大的正整数(第13行),*buffer减少10个字节并指向vmalloc()分配的缓冲区下方的-2GB-10B偏移量(第16行),并且10字节的字符串“//deleted”将被越界(第17行)。


缓解措施


鉴于鉴于上述漏洞影响范围大,潜在危害程度高,建议用户立即安装补丁以免受此漏洞导致的风险。


Linux文件系统层中的本地提权漏洞(CVE-2021-33909)

END



Linux文件系统层中的本地提权漏洞(CVE-2021-33909)


好文!必须在看

本文始发于微信公众号(SecTr安全团队):Linux文件系统层中的本地提权漏洞(CVE-2021-33909)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: