当前位置: 首页 > Linux

CVE-2019-18276GunBash条件竞争漏洞

时间:2023-04-06 21:35:09 Linux

最近在看K8S漏洞。分析漏洞后,看到一个GunBash条件竞争漏洞。漏洞成因和复现都比较简单,但是里面包含了一些条件竞争TOCTOU和一些linux基础知识文件,感觉值得记录一下,所以有了这篇文章:1.漏洞描述Bash是一个shell(命令语言解释)为GNU项目编写并在类Unix操作系统上运行。设备)。它可以从标准输入设备或文件中读取和执行命令。Bash5.0patch11及之前版本的shell.c文件的disable_priv_mode存在安全漏洞。攻击者可以利用此漏洞获取特权。请注意,此漏洞是Bash组件中的漏洞。虽然很多操作系统都自带这个Bash程序,但不能说是操作系统的漏洞。并且经过分析该漏洞的实际作用有限,下面是对该漏洞的完整分析2.漏洞分析定位到漏洞发生时的commit,发现漏洞的要点在于shell的disable_priv_mode()函数。c,离程序入口很远。最近是Bash刚执行时的权限检查功能。按照bash设计者的设计思路,哪个用户启动了bash,那么这个用户进入bash后就有了权限,但是linux文件权限权限里面有一个SetUID标志位:SetUID标志位:SetUID:当一个可执行文件程序具有SetUID权限,当用户执行该程序时,将以程序所有者的身份执行。前提是这个文件是一个可执行文件,但是它有x权限(必须给组设置相应的x权限)。操作系统中的许多命令都默认设置了SetUID标志,以方便非root用户操作系统的某些功能。例如/usr/bin/sudo、/usr/bin/passwd等。虽然设置了SetUID标志,但其他用户也可以调用只有root用户才能调用的passwd命令。setUID标志我理解,但是在实际中,虽然root用户和普通用户都可以调用root命令,但是普通用户在执行passwd命令后只能修改自己的密码,而root用户在执行passwd命令后才能修改root账户的密码密码命令。密码,这里又涉及到linux进程权限的内容:linux进程credential(权限)进程的trustcredentials放在进程描述符的几个字段中,这些字段包括:字段名字段描述ruid(实际用户id)进程是哪个用户启动的euid(effectiveuserid)为有效用户ID。当前进程运行的用户ID一般与UID相同,但设置SUID权限后,可执行程序所有者的ID将无法执行。系统使用EUID决定权限suid(saveuserid)有效用户UID的副本fuid(filesystemuserid)决定文件系统的访问权限或以passwd命令为例。如果以root权限运行,则ruid、euid、suid和fuid都是具有root权限的id;如果是普通权限用户运行,则euid、suid、fuid都为0,ruid为普通用户的用户ID。那么如果以普通用户的权限运行带SetUID标志的bash(虽然系统默认的bash是没有SetUID标志的),那会是怎样的权限呢?答案是普通用户的权限。因为bash在启动时会获取当前进程的创建者的id(ruid),并以实际创建者的权限运行。setuid函数用于权限更改过程中。setuid函数看一下官方对setuid()函数的解释:个人理解,调用setuid()函数时调用的代码可以简单分析为以下几种情况:以root权限启动进程,可以设置ruid,uuid、suid、fsuid是函数参数uid的值;启动所有者为root且包含普通用户权限的s标志的进程,可以将ruid、uuid、suid、fsuid设置为函数参数uid的值,以普通用户权限启动进程为所有者传入没有s标志的进程/进程的uid必须等于UID或SUID。可以设置EUID和FSUID。这一点不应该被提及,因为EUID必须等于UID。以普通用户权限启动进程,拥有者为其他普通用户setuid()传入的uid必须等于UID或SUID,传入参数uid的值可以设置EUID和FSUID。下面看一下bash开头的实现。在disable_priv_mode()函数中,直接调用setuid(current_user.uid),如果bash的拥有者是root并且包含setuid标志,那么ruid、uuid、suid、fsuid都会被改成uid。在这种情况下,没有越界。当bash的所有者是另一个用户,并且包含setuid标志时,setuid函数执行完后会把euid设置为传入的参数uid,suid的值不会改变。然而,问题就出在这个地方。bash中disable_priv_mode()函数中调用setuid(current_user.uid)的目的是调整bash对启动bash的用户的权限(通过函数名disable_priv_mode也可以验证调用setuid()的目的函数是这个),但是修改了euid后,suid没有修改,后续函数可以再次调用setuid()函数恢复权限,所以这里存在权限控制不当的漏洞。该漏洞的利用过程比较诡异。创建两个用户A和B,然后设置bash的所有者为B,然后设置bash可执行程序setuid标志,这样用户A调用bash可执行程序后,bash进程本身调用setuid函数后,如果程序再次调用setuid,传入用户B的UID,bash进程会将进程EUID权限恢复为用户B的权限,用户A现在可以访问一些用户A无法访问的资源。setuid()的源码如下:#include#include#includevoid__attribute((constructor))initLibrary(void){printf("Escapelib已初始化\n");printf("[LO]uid:%d|euid:%d\n",getuid(),geteuid());setuid($euid);printf("[LO]uid:%d|euid:%d\n\n\n",getuid(),geteuid());}具体测试详情请参考:https://github.com/M-ensimag/...总结最近在做Linux和虚拟化相关的漏洞研究,发现除了传统的内存破坏性漏洞外,还有很多这样的逻辑漏洞。我也搭建了syzkaller来fuzz内核,但是感觉无论怎么修改syzkaller,应该都不会产生大量的漏洞。相反,这种无法被fuzzed的逻辑漏洞,可能还是有点笑话。准备好以后每周都会写点类似的东西,和大家一起成长!参考资料漏洞验证POC:https://github.com/M-ensimag/...文件路径条件竞争初探:http://whip1ash.cn/2021/06/16...