CVE-2025-37899: let me try try
彩贝是这样的,没复现出来还恬不知耻地发Blog…(记录一些踩的坑)
KSMBD - SMB3 内核服务器
KSMBD是一个Linux内核服务器,它在内核空间中实现了SMB3协议,用于在网络上共享文件。
KSMBD 架构
与性能相关的操作属于内核空间,而另一部分属于与性能无关的用户空间操作。因此,历史上导致缓冲区溢出问题和危险安全漏洞的DCE/RPC管理以及用户账户管理在用户空间实现为ksmbd.mounted。与性能相关的文件操作(如open/read/write/close
等)在内核空间(ksmbd)中实现。这也使得所有文件操作更容易与VFS(虚拟文件系统)接口集成。
ksmbd (kernel daemon)
ksmbd(Kernel SMB Daemon)是Linux系统中的一个内核级守护进程,负责实现和管理SMB(Server Message Block)协议的文件共享功能,通常用于网络文件共享服务。它在内核层面运行,能够提供比传统用户空间SMB实现(如Samba)更高性能,因为它避免了用户空间和内核空间之间的频繁数据传输。具体的工作流程为:
启动和初始化。
当
ksmbd
初始化时会启动一个forker
线程。该线程会监听来自客户端的SMB请求。ksmbd
使用端口445,负责接收客户端的连接请求。处理客户端连接
每当有新客户端连接时,
forker
线程会接受连接,并为每个客户端请求创建一个新的线程。处理命令的并行性
ksmbd
支持并行处理多个客户端请求。每当接收到一个新的SMB命令时,ksmbd
会根据请求的类型决定是否将命令传递给用户空间的ksmbd.mountd
进程。例如,DCE/RPC命令会被识别并通过用户空间处理。这种处理方式允许
ksmbd
动态决定哪些请求可以直接由内核处理,哪些需要通过用户空间处理。利用Linux内核进行任务调度
ksmbd
将命令处理任务作为工作项(workitems)进行排队,并由ksmbd-io
内核工作线程处理。这种方式使得能够动态增加或减少工作线程。当负载增加时,内核启动更多的工作线程;当负载降低时,则会销毁多余的工作线程。命令的并行处理
在与客户端建立连接后,
ksmbd
会为每个SMB命令串接一个独立的内核工作项,并将其排入ksmbd-io
的工作队列。以实现并行处理多个客户端的请求。
CVE-2025-37778
环境配置
所需环境为:linux内核(v6.15-rc4
版本为没有应用补丁的最新版),
编译内核
内核源码:
1 |
|
内核增加SMB3 server support
模块:
首先执行:
1 |
|
依次选择File System
,Network File System
,然后选择smb3 server
以模块(按M
)形式编译,而不是内核的一部分编译。最后Save
配置,保存为.config
。开始编译:
1 |
|
直接用
make -j$(nproc)
也能够生成bzImage
,但会编译出额外的东西。
编译成功后出现如下:
1 |
|
关注一下这俩文件:vmlinux
和arch/x86/boot/bzImage
。其中,vmlinux
是未经压缩的完整内核映像 ,其包含所有内核代码,数据段,调试信息,所有内核符号;是一个ELF可执行文件 ,主要用于调试(如gdb vmlinux
),不能直接被QEMU
直接使用来引导系统。
而bzImage
(bootable zImage)是经过压缩处理、用于引导的内核镜像 。 可被QEMU
直接用来引导系统。
接下来还需要编译模块:
1 |
|
内核模块会被放在./modules
下,模块的扩展名通常为.ko
。
笔者认为到这儿已经可以了,因为
.ko
文件其实就可以通过insmod /path/to/module.ko
进行加载,只不过缺少相关依赖会报错。
紧接着安装内核模块:
1 |
|
这个命令会把编译好的内核模块安装到/lib/modules/$(kernel_version)
中。这里的$(kernel_version)
就是内核版本号,在此情况下就是/lib/modules/6.15.0-rc4
。
至此,我们有了内核镜像(bzImage
)和安装好的内核模块目录(/lib/modules/6.15.0-rc4
)。一个是为了qemu启动对应版本的linux内核,一个是为了在qemu模拟的系统中加载ksmbd
模块。
构建文件系统
在linux流传着一句话:万物皆文件
对文件系统的概念笔者通过pwn.college接触到的,认为确实讲解清晰,实践做题过程中确实理解加深。
这里需要为我们的内核构建一个文件系统,一开始笔者使用的是 busybox,但有点太mini了。因为还得安装用户空间ksmbd守护进程。
所以,用debootstrap
构建一个精简的文件系统吧:
1 |
|
这条命令是:选择架构和版本后,以当前目录为文件系统根目录进行构建。或许需要挂全局代理,笔者不挂全局代理发现不走代理。
构建完成后,先进入该文件系统进行一些简单的初始化操作。首先执行以下命令进入根文件系统:
1 |
|
然后设置root密码:
1 |
|
我们需要将内核模块cp进该文件系统。 也就是将安装到宿主机的/lib/modules/6.15.0-rc4
目录直接复制进我们创建好的文件系统。
1 |
|
最后用cpio
打包成一个文件系统,供qemu
使用:
1 |
|
至此,我们有了一个文件系统,且这个文件系统可以自定义很多东西(通过chroot
,借助宿主机内核自定义)。且这个文件系统已经安装好了内核模块。
QEMU模拟系统
以bzImage
为镜像,以打包的rootfs.cpio
为根文件系统,用qemu进行模拟。
qemu启动该linux内核命令脚本:
1 |
|
进入后的网络配置(具体网卡号用ip address
查看):
1 |
|
可以通过
apt update
来确定是否有网络
如果是bridge
模式,那么就是这样的(宿主机为192.168.100.1/24
):
1 |
|
宿主机的配置为:
1 |
|
推荐使用tag,因为后面为了支持Kerberos认证。qemu的user模式端口转发不支持高级协议的数据包转发。
加载ksmbd模块
随后,可以加载ksmbd
模块:
1 |
|
最终成功加载:
1 |
|
此刻,内核空间现在支持使用smb server
了。现在需要一个用户空间的smb
守护进程,即安装ksmbd-tools
。
启动ksmbd服务
建议在根文件系统里安装好
ksmbd-tools
,而不是qemu模拟的系统中。
具体需要安装的依赖有:apt-get install git make autoconf libtool pkg-config libkrb5-dev libglib2.0-dev libnl-3-dev libnl-genl-3-dev
。安装过程很简单:
1 |
|
安装好了之后,配置ksmbd
共享。其中配置文件ksmbd.conf
是用于定义SMB共享的核心文件。可以参考/usr/local/etc/ksmbd/ksmbd.conf.example
文件,需要配置一个ksmbd.conf
文件。
1 |
|
然后自定义里面的内容。后续再创建用户/密码。
1 |
|
创建好之后,就是启动ksmdb用户空间守护进程:
1 |
|
安装一个smbclient进行测试:
1 |
|
证明qemu模拟的系统成功启动了ksmbd服务,值得一提的是,验证服务是否启动成功直接查看进程,而不是用systemctl。因为这里并不是使用systemd
启动的ksmbd
:
1 |
|
上述状态显示:
ksmbd.mountd
正在运行并监听共享配置;内核层的ksmbd
模块已经在处理来自lo
(本地回环)和enp0s3
(实际网卡)的SMB请求;
由于笔者只想用qemu模拟一个ksmbd Server
,因此大部分的依赖和软件包都是在文件系统借助宿主机完成的。最终实际到qemu启动的系统中,只需要简单加载模块modprobe ksmdb
和运行用户空间ksmbd
。修改conf
时也在模拟的根文件系统中完成。
倘若有需要,可申请一个虚拟磁盘给该系统,使得每次qemu启动该系统后做的操作由该虚拟磁盘保留,这样重启系统后状态就不会被重置。
关于原博客的简单分析
CVE-2025-37778是一个UAF漏洞。该问题发生在处理远程客户端发送的”session setup”请求时的Kerberos认证路径中。
如果krb5_authenticate
检测到到会话状态是SMB2_SESSION_VALID
,那么它就会释放sess->user
。根据以下代码逻辑:
1 |
|
这段代码认为当释放sess->user
后,要么ksmbd_krb5_authenticate
会将其重新初始化为一个新的有效值,要么不重新初始化时,返回-EINVAL
后,sess->user
不会再其他地方被使用。然而,事实证明这个假设是错误的。
可以强制ksmbd_krb5_authenticate
不重新初始化sess->user
,并且即使krb5_authenticate
返回-EINVAL
,依然可以继续访问sess->user
。
作者想办法用这个漏洞来验证LLM的能力,LLM需要理解并完成以下需求才能发现漏洞:
- 想办法触发
free
操作以获得sess->state == SMB2_SESSION_VALID
- 意识到在
ksmbd_krb5_authenticate
中存在不会重新初始化sess->user
的路径,并思考如何触发这些路径 - 意识到在
sess->user
被释放后,代码库的其他部分可能仍然可以访问它
此外,作者还公开了[o3](o3_finds_cve-2025-37899/o3_finds_CVE-2025-37778.txt at master · SeanHeelan/o3_finds_cve-2025-37899)和[claude3.7](o3_finds_cve-2025-37899/claude_3_7_finds_CVE-2025-37778.txt at master · SeanHeelan/o3_finds_cve-2025-37899)发现这个漏洞的分析报告。
漏洞分析与验证
这一切是发生在smb2_sess_setup
函数中,前文提及它是在远程客户端发送”session setup”时触发的,然后需要触发krb5_authenticate()
函数中的free
操作,同时进入ksmbd_krb5_authenticate()
后,触发goto out
代码路径,从而避免sess->user
的重新初始化操作。然后回到smb2_sess_setup()
中的out_err
路径,第1912
行出现sess->user
对已经释放的指针进行再次地使得,从而达成use after free
后续进一步分析分析源码….仔细看看调用链。尝试写个PoC试试。
Kerberos认证
Kerberos不过多介绍,因为漏洞涉及的其实并不多,主要需要使得用qemu搭建的ksmbd
服务器支持Kerberos
认证。

配置Kerberos环境
安装必要的软件包:
1 |
|
然后宿主机和ksmbd
服务器(qemu模拟的)需要配置对应的域名解析。在各自的/etc/hosts
中加上:
1 |
|
验证是否配置域名解析成功,执行以下命令应当返回对应的域名即解析成功。当然,域名解析成功并不代表两端互通,需要配置相应的tap
管道作为qemu与宿主机的通信管道,因为qemu
默认是无法访问宿主机网络的。
1 |
|
然后qemu
启动时的脚本需要更改,利用tap
虚拟网卡搭建一个通信管道。
1 |
|
配置kdc server
首先需要创建Kerberos 数据库
1 |
|
这里需要提供口令,作为数据库的主密码。然后启动KDC服务:
1 |
|
再创建管理员和测试用户:
1 |
|
继续创建smb服务主体:
1 |
|
然后该服务主体需要导出到密钥中,这个密钥是服务端用于解密票据时用的:
1 |
|
此时会默认生成一个/etc/krb5.keytab
文件。
进一步在宿主机(客户端)配置/etc/krb5.conf
文件,设置其使用kerberos认证时访问的kdc
服务器以及其获取TGT的相关配置:
1 |
|
然后服务端的配置文件应当保持一致。最后为ksmbd
支持kerberos
作配置。通过官方文档ksmbd.conf对ksmbd.conf
文件的相关描述,可发现3个配置选项:
1 |
|
对其作相应配置如下:
1 |
|
然后再重启KSMBD
:
1 |
|
由于笔者的ksmbd
服务和kdc
服务同为qemu
模拟的ubuntu服务器,因此不需要额外再配置一台机器。
修改服务器主机名
由于我的qemu模拟的主机名为”dog”。而实际的SPN为kdc.example.com
。当ksmbd
收到客户端送来的票据(cifs/kdc.example.com@EXAMPLE.COM
),它会依次执行以下操作:
- 检查本地keytab是否有该SPN;
- 重要的是:它会默认使用本机的主机名(
dog
),构建成cifs/dog@EXAMPLE.COM
- 重要的是:它会默认使用本机的主机名(
- 尝试从keytab中找
cifs/dog@EXAMPLE.COM
,找不到; - 最终SPNEGO认证失败
修改服务器主机名为kdc.example.com
:
1 |
|
重新登陆shell:
1 |
|
验证:
1 |
|
重启ksmbd
:
1 |
|
测试
客户端执行kinit dog
可获得对应的票据。然后使用smbclient -k //kdc.example.com/share
即可通过kerberos
认证访问该服务。但目前为止一直没认证通过,正常口令认证是可访问成功的。…暂时跳过这一部分内容。
所以这是一个求助帖,或许有人能告知我为何Kerberos
认证不了~
除了这一点,或许有其他文章能够使得触发这类漏洞的一个前提条件:
kmalloc()
失败,To be continue…