使用o3发现CVE-2025-37899:Linux内核SMB实现中的远程零日漏洞
引言
最近我一直在审计ksmbd中的漏洞。ksmbd是“一个在内核空间实现SMB3协议的Linux内核服务器,用于通过网络共享文件”。我启动这个项目原本是为了暂时远离与LLM相关的工具开发,但在o3发布后,我忍不住用我在ksmbd中找到的漏洞作为o3能力的快速基准测试。在未来的文章中,我将讨论o3在所有这些问题上的表现,但这里我们将重点放在o3在我的基准测试过程中如何发现一个零日漏洞上。
漏洞概述
o3发现的漏洞是CVE-2025-37899(修复在此),这是SMB“注销”命令处理程序中的一个释放后使用(use-after-free)漏洞。理解这个漏洞需要推理服务器上的并发连接,以及它们如何在特定情况下共享各种对象。o3能够理解这一点,并发现一个特定对象在没有引用计数的情况下被释放,而另一个线程仍然可以访问它。
基准测试:使用CVE-2025-37778
首先讨论CVE-2025-37778,这是一个我手动发现的漏洞,我正在用它作为o3能力的基准测试,当时它发现了零日漏洞CVE-2025-37899。
CVE-2025-37778是一个释放后使用漏洞。问题发生在Kerberos认证路径中,当处理来自远程客户端的“会话设置”请求时。为了节省引用CVE编号的时间,我将此漏洞称为“kerberos认证漏洞”。
根本原因如下:
|
|
如果krb5_authenticate检测到会话状态为SMB2_SESSION_VALID,则它会释放sess->user。这里的假设似乎是,之后ksmbd_krb5_authenticate会将其重新初始化为一个新的有效值,或者在krb5_authenticate返回-EINVAL后,sess->user不会在其他地方使用。事实证明,这个假设是错误的。我们可以强制ksmbd_krb5_authenticate不重新初始化sess->user,并且即使krb5_authenticate返回-EINVAL,我们也可以访问sess->user。
o3的表现
o3在100次运行中,有8次找到了kerberos认证漏洞。在另外66次运行中,o3得出结论认为代码中没有错误(假阴性),其余28份报告是假阳性。相比之下,Claude Sonnet 3.7在100次运行中找到了3次,而Claude Sonnet 3.5在100次运行中没有找到。因此,至少在这个基准测试中,o3比Claude Sonnet 3.7有2-3倍的改进。
o3发现零日漏洞(CVE-2025-37899)
在确认o3可以在给定会话设置命令处理程序的代码时找到kerberos认证漏洞(CVE-2025-37778)后,我想看看如果给它所有命令处理程序的代码,它是否还能找到它。这是一个更难的问题,因为所有命令处理程序都在smb2pdu.c中,该文件有约9k行代码。然而,如果o3在一次性给出所有处理程序时仍然能够找到漏洞,那么这表明我们可以为o3构建一个更简单的包装器,只需将整个文件交给它,覆盖各种功能,而不是逐个处理程序进行。
将所有处理程序的代码与连接设置和拆除代码以及命令处理程序调度例程结合起来,最终达到约12k行代码(约100k输入令牌),和之前一样,我运行了实验100次。
o3在这个更大的输入令牌数量下,在100次运行中有1次找到了kerberos认证漏洞,因此性能明显下降,但它仍然找到了它。然而,更有趣的是,在其他运行的输出中,我找到了一个类似但新颖的漏洞报告,这是我之前不知道的。这个漏洞也是由于释放了sess->user,但这次是在会话注销处理程序中。
|
|
o3的解释
简短描述
当一个ksmbd工作线程仍在执行使用sess->user的请求时,另一个处理同一会话的SMB2 LOGOFF的线程释放了该结构。没有同步保护指针,因此第一个线程解引用了已释放的内存——一个典型的释放后使用,导致内核内存损坏和内核上下文中的任意代码执行。
受影响代码路径
- 第二个传输绑定到现有会话(SMB 3.0或更高版本,
conn->binding == true
)。 - 工作线程A(在连接C2上运行)接收任何正常请求(例如WRITE)。
•
smb2_check_user_session()
存储指向已存在的struct ksmbd_session
的指针在work->sess
中,并增加会话引用计数,但它不对sess->user
采取任何引用。 • 指向sess
的指针在整个请求处理过程中保持;每个需要认证数据的辅助函数直接访问sess->user
。 - 在工作线程A完成之前,工作线程B(在第一个连接C1上运行)处理同一会话的SMB2 LOGOFF并执行
smb2_session_logoff()
(smb2pdu.c)。
smb2_session_logoff()的相关部分
|
|
ksmbd_free_user()
最终以简单的kfree(user)
结束。
4. 工作线程B不等待仍在使用的其他连接;它只等待自己连接上运行的请求(ksmbd_conn_wait_idle(conn)
)。
5. 工作线程A继续执行(例如在smb2_open()
、smb2_write()
内部……)并解引用sess->user
:
|
|
因为内存已在步骤(1)中被kfree()
释放,访问的是已释放的内存。根据确切的时间,它要么是:
• 释放后使用(指针仍然指向现在重用的slab对象),启用受控的内核内存覆盖,或
• NULL解引用(如果工作线程A在步骤(2)之后读取),仍然是DoS。
结论
LLMs存在于程序分析技术能力空间的一个点,比我们见过的任何东西都更接近人类。考虑到创造力、灵活性和通用性等属性,LLMs更类似于人类代码审计员,而不是符号执行、抽象解释或模糊测试。自GPT-4以来,LLMs在漏洞研究中的潜力已有暗示,但真实问题的结果从未完全达到希望或炒作。随着o3的出现,这种情况已经改变,我们有一个模型在代码推理、问答、编程和问题解决方面做得足够好,可以真正增强人类在漏洞研究中的表现。
o3并非万无一失。远非如此。仍然有相当大的机会它会生成无意义的结果并让你沮丧。不同的是,这是第一次获得正确结果的机会足够高,值得你花时间和精力尝试在真实问题上使用它。