安全研究员Asim Manizada盯着一行行内核代码,忽然停了下来。他发现,当CIFS客户端向内核请求一个SPNEGO认证密钥时,内核压根没检查这个密钥的描述字符串是不是真的来自CIFS子系统——谁都可以捏造一串参数扔进去,而内核会老老实实把它当作可信请求交给root权限的cifs-upcall处理。

这个后来被命名为“CIFSwitch”的本地提权漏洞,让一个普通用户只需精心构造一次请求,就能把恶意代码塞进sudoers配置文件,直接拿下root。Manizada用AI辅助的多跳推理方法,在安全相关对象和流之间建立语义图,把一串细微的逻辑缺陷串成了一条完整的利用链。

打开网易新闻 查看精彩图片

整个漏洞的根源,远在2007年就已埋下。但直到现在,依靠着cifs-utils的特定版本和允许非特权用户命名空间的环境,它才变成一个可被实际触发的安全缺口。上游内核补丁已随协调披露发布,如果你手上还跑着未修补的系统,这条攻击路径依旧敞开着。

下面用清单的方式,拆开这条从伪造密钥到劫持root的完整链路。

一、密钥描述完全受控,内核毫无验证
CIFS/SMB在Linux上依赖内核CIFS客户端处理文件系统操作,Kerberos/SPNEGO身份认证则交给cifs-utils提供的cifs-upcall完成。两者之间通过Linux密钥环通信:内核调用request_key()请求CIFS.spnego密钥,传进去的描述字符串里包含着服务器地址、UID、凭据UID、PID和命名空间目标等信息。随后/sbin/request-key策略以root身份启动cifs-upcall来处理这个请求。

Manizada发现整个流程缺了一个关键检查——内核从来不去确认这个cifs.spnego密钥的描述是不是真的来自CIFS子系统。任何非特权进程都可以直接调用request_key("cifs.spnego", 自行构造的描述, ...)。因为密钥类型是cifs.spnego,默认的request-key规则依旧会以root权限启动cifs-upcall,此时描述内容完全由攻击者说了算。

二、两个参数决定攻击走向:pid与upcall_target
在攻击者伪造的描述中,pid和upcall_target决定了后续利用的方向。当把upcall_target设为app并提供一个恶意进程的pid,cifs-upcall在执行基于NSS(名称服务交换)的账户查找之前,会先切换到攻击者控制的进程所在的命名空间。原本应该为系统进行身份解析的root权限进程,就这样悄无声息地跑进了攻击者布置好的陷阱里。

三、伪造的NSS模块直接写sudoers
一旦cifs-upcall进入攻击者控制的挂载命名空间,一切就变得异常简单。攻击者可以提前在这个空间中放置篡改过的nsswitch.conf,并部署一个恶意的libnss_*.so.2共享库。当root权限的NSS查找触发时,这个库被加载并执行任意代码。在Manizada的概念验证中,恶意NSS模块所做的唯一一件事,就是往/etc/sudoers.d里添了一行,让攻击者直接获得有效的root权限。

四、利用需要多条件配合,通用性受限
虽然这个设计缺陷从2007年就存在,要成功实施CIFSwitch攻击,仍需满足几个硬性条件:首先,内核本身存在漏洞,其次必须搭配一个兼容的cifs-utils版本——6.14以上或者某些回传了补丁的旧版本。此外,系统还需允许非特权用户命名空间的创建。缺少任何一环,这条利用链都无法走通。

五、协调披露与修复进度
Manizada在与各Linux发行版协商的保密期结束后才公开了这份技术报告与概念验证代码。上游内核补丁已经就绪,相关发行版也正在推送修复。但由于涉及的cifs-utils组件更新路径不一,部分环境可能仍在暴露窗口期中。对于依赖SMB/CIFS挂载的服务器和工作站而言,即便攻击条件稍显苛刻,这条从用户空间直达root的通道依然值得高度关注。