作者 | Sean Heelan
编译 | 苏宓
出品 | CSDN(ID:CSDNnews)
在这个 AI 大模型流行的时代,有人对自动生成的代码感到厌烦,比如 Curl 项目的创始人 Daniel Stenberg 不久前就曾怒斥 AI 生成的漏洞报告泛滥,直言它们简直像 DDoS 攻击一样令人头疼。而与此同时,也有人开始借助 AI 工具深入探索安全问题,甚至挖出了真漏洞。
最近,安全研究员 Sean Heelan 分享了他利用 OpenAI 的 o3 大模型,在完全不依赖其他工具、框架或辅助代码的前提下,成功发现了 Linux 内核中的一个零日漏洞。这个漏洞现已被正式编号为 CVE-2025-37899,属于一种发生在 SMB 协议“logoff”命令处理路径中的 use-after-free(释放后使用)问题,官方修复补丁也已经发布。
那么,他到底是怎么发现的?我们不妨通过 Sean Heelan 发布的长文来一探究竟。
背景
Sean Heelan 透露,自己近期一直在审计 ksmbd 模块的安全性。ksmbd 是 Linux 内核中实现 SMB3 协议的服务端组件,主要用于实现文件共享服务。
之所以启动这项研究,Sean Heelan 本来是想要暂时远离大模型相关工具的开发工作,但在看到 o3 发布后,他还是没忍住,决定顺手用自己已掌握的 ksmbd 漏洞作为基准,想要测试一下 o3 的代码理解与分析能力。
没想到的是,测试中,o3 模型真实地识别出另一个名为 CVE-2025-37899 漏洞。该问题涉及服务器的并发连接及对象共享机制,理解起来需要较强的并发上下文推理能力。o3 成功识别出一处关键逻辑:某个对象未被引用计数保护的情况下被释放,而此时该对象可能仍被其他线程访问。这一能力超出了此前对大模型代码分析上限的普遍认知。
Sean Heelan 表示,这是首次有公开报道显示大型语言模型能够独立发现此类类型的内核级漏洞。他指出,o3 模型在代码理解和漏洞挖掘方面已经实现重要飞跃,值得安全研究者密切关注。尽管目前模型尚不能取代专业漏洞研究人员或利用开发者,但它们已具备显著增强专家效率的能力。如果一个安全问题可以被压缩到一万行代码以内,o3 很有可能能够直接解决,或提供关键帮助。
o3 在 CVE-2025-37778 上的基准测试表现
在 o3 模型意外发现 CVE-2025-37899 这一零日漏洞之前,Sean Heelan 原本正使用另一个自己手动发现的漏洞——CVE-2025-37778,来评估 o3 在漏洞检测方面的能力。
简单来看,CVE-2025-37778 是一个 “释放后使用”(use-after-free)类型的漏洞,问题出现在处理远程客户端发来的 “session setup”(会话建立)请求时,具体是在 Kerberos 认证的流程中。为了方便起见,Sean Heelan 把这个漏洞称作 “Kerberos 认证漏洞”。
它的根本原因大致如下:
static int krb5_authenticate(struct ksmbd_work *work,
struct smb2_sess_setup_req *req,
struct smb2_sess_setup_rsp *rsp)
{
...
if (sess->state == SMB2_SESSION_VALID)
ksmbd_free_user(sess->user);
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
out_blob, &out_len);
if (retval) {
ksmbd_debug(SMB, "krb5 authentication failed\n");
return -EINVAL;
}
...
如果 krb5_authenticate 检测到当前会话的状态是 SMB2_SESSION_VALID,它就会释放 sess->user(也就是把它清掉)。
它的假设是这样的:要么 ksmbd_krb5_authenticate 后面会重新初始化 sess->user,要么如果 krb5_authenticate 返回错误(比如返回 -EINVAL),那后续代码就不会再用到 sess->user。但问题是——这个假设不对。实际上我们可以让 ksmbd_krb5_authenticate 不去重新初始化 sess->user,而且即使 krb5_authenticate 返回了 -EINVAL,后面也还是有办法访问这个已经被释放的 sess->user,就出问题了。
这个漏洞很适合用来测试大模型的能力,原因有几点:
1. 首先,它属于 Linux 内核的远程攻击面的一部分,本身就挺有意思的。
2. 然后,它并不简单,想要发现它需要搞清楚三件事:
-
怎么让 sess->state 变成 SMB2_SESSION_VALID,以便触发释放;
-
意识到 ksmbd_krb5_authenticate 某些执行路径不会重新赋值 sess->user,并分析怎么走到这些路径;
-
发现代码里其他地方可能会在这个变量被释放后继续访问它。
3. 虽然不算简单,但也不复杂得离谱。Sean Heelan 称其可以花十分钟把整条触发路径讲给同事听,而且理解这个漏洞用不着深入了解 Linux 内核、SMB 协议或者 ksmbd 的全貌,只需要看懂连接处理和会话建立相关的代码就行。对此,Sean Heelan 还专门数了一下,从网络包到达 ksmbd 模块、再到漏洞被触发,沿着这条路径读一遍相关函数的代码,大概是 3300 行左右。
基于以上这些因素,Sean Heelan 想要用这个漏洞作为测试对象,接下来要决定的是:给大模型看什么代码,看看它能不能找出这个漏洞?
Sean Heelan 想模拟一下一个假想的自动化漏洞检测系统,在这种系统下,o3 作为后端模型的表现会如何。所以其必须明确:这样一个系统是怎么给 LLM 准备输入内容的。因为如果给模型看的代码方式不现实,现实中系统没法复制,那这个测试就没什么意义。
理想情况下,Sean Heelan 当然想直接把一个项目的完整代码扔给 LLM,模型分析完直接吐出结果。但受限于上下文长度(context window)和上下文越多性能越差的问题,现在还做不到。
于是 Sean Heelan 想了一个折中办法:模拟一个工具把每个 SMB 命令处理函数(handler)单独展开来喂给模型。比如他就把“session setup”这个命令处理器相关的代码给了 LLM——不仅是它本身的代码,还包括它调用的所有函数(最多展开到调用深度 3),这样模型才能看全逻辑。同时他也提供了那些从网络接收数据、解析请求、选择处理器和连接关闭相关的代码,否则模型就得自己猜这些结构是怎么设置的,那肯定会带来更多误报。
最后,这一堆代码加起来大约 3300 行(相当于 2.7 万个 token),正好可以作为一个标准用来对比 o3 和以往模型的能力。如果你感兴趣,这里有个单文件版本,是用 files-to-prompt 工具生成的(https://github.com/SeanHeelan/o3_finds_cve-2025-37899/blob/master/session_setup_code.prompt)。
最后一个要决定的就是用什么 Prompt。Sean Heelan 把用的 system prompt 和其它提示信息都整理在了这个 GitHub 仓库的 .prompt 文件里(https://github.com/SeanHeelan/o3_finds_cve-2025-37899)。关键点如下:
-
Sean Heelan 明确告诉 LLM 要找的是 use-after-free(释放后使用)类型的漏洞;
-
给了它一个简短的背景介绍,说明 ksmbd 是什么,它的架构大概如何,以及安全模型是怎样的;
-
他尽量引导模型不要报出误报,甚至宁愿不报漏洞也别报错的。不过对于这一点,Sean Heelan 也不确定这是否有效,只是希望能有效。说白了,这些提示尚未通过系统性实验验证其效果,Sean Heelan 坦言自己写的提示词:“这些更像是在祈祷,而不是科学。”
接下来,Sean Heelan 使用名为 llm 的工具(https://github.com/simonw/llm)执行推理请求,如下所示:$ llm --sf system_prompt_uafs.prompt \
-f session_setup_code.prompt \
-f ksmbd_explainer.prompt \
-f session_setup_context_explainer.prompt \
-f audit_request.prompt
在这次实验中,Sean Heelan 把测试流程跑了 100 次,并记录了每次的结果。他也提醒说,如果别人复现实验,可能得到的结果跟他不完全一样。因为他在写博客前不小心删了之前用来分析的那份代码,只能重新生成了一份,虽然内容应该几乎一样,但他并没有重新跑一遍全部测试验证。
那 o3 表现怎么样呢?
-
它在这 100 次测试中,有 8 次成功找到了那个 Kerberos 认证相关的漏洞;66 次啥也没发现(也就是说漏掉了漏洞);另外还有 28 次,它报告了错误的“漏洞”,其实并没有问题。这种情况在安全分析中叫“误报”。
为了比较效果,他也拿另外两个模型试了一下:Claude Sonnet 3.7 找到漏洞的次数是 3 次,Claude Sonnet 3.5 连一次都没找出来。所以从这次测试结果来看,o3 的表现大概是 Claude Sonnet 3.7 的 2 到 3 倍。
o3 模型发现新的零日漏洞(CVE-2025-37899)
在确认 o3 能够在给定 session setup 命令处理函数的代码时成功识别 Kerberos 身份验证漏洞(CVE-2025-37778)之后,Sean Heelan 进一步尝试提升挑战难度:这次,他将所有 SMB 命令处理函数的代码一并提供给 o3,测试其在更复杂、上下文更广的条件下是否仍能识别漏洞。
这项任务的难度明显更高:所有命令处理函数均位于 smb2pdu.c 文件中,该文件约有 9000 行代码。如果 o3 在此情况下仍能发现漏洞,将意味着可以构建更直接的封装工具,整体将完整源码文件交由模型处理,而不必逐个处理器地构造输入。
Sean Heelan 将所有命令处理器代码与连接初始化、关闭流程、命令调度逻辑等辅助函数整合后,总输入规模达到约 12k 行代码(约 10 万 tokens)。他同样进行了 100 次实验。
在这一大规模上下文下,o3 在 100 次运行中仅有一次识别出原本的 Kerberos 身份验证漏洞,显示出在上下文量显著增加时模型性能确实存在下降。但更令人惊喜的是,在其他运行结果中,Sean Heelan 注意到 o3 报告了一个此前未知的、类似但全新的漏洞。这个新漏洞也涉及 sess->user 的释放问题,但这次出现在会话注销(logoff)处理逻辑中。
int smb2_session_logoff(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
...
ksmbd_close_session_fds(work);
ksmbd_conn_wait_idle(conn);
...
down_write(&conn->session_lock);
sess->state = SMB2_SESSION_EXPIRED;
up_write(&conn->session_lock);
if (sess->user) {
ksmbd_free_user(sess->user);
sess->user = NULL;
}
...
发现之后,Sean Heelan 又让 o3 进一步解释一下这个漏洞:
简要描述
当一个 ksmbd worker 线程仍在执行依赖 sess->user 的请求时,另一个处理同一会话的 SMB2 LOGOFF 的线程会释放该结构。由于没有同步机制保护这个指针,第一个线程便会解引用已被释放的内存——这是一个典型的 use-after-free(释放后使用)漏洞,会导致内核内存损坏,甚至在内核上下文中执行任意代码。
受影响的代码路径
1. 一个额外的传输通道被绑定到一个已存在的会话上
(SMB 3.0 或更高版本,conn->binding == true)。
2. Worker‑A(在连接 C2 上运行)收到任意正常请求(例如 WRITE)。
-
-
smb2_check_user_session() 将已存在的 struct ksmbd_session 指针存入 work->sess,并增加会话引用计数,但不会对 sess->user 增加引用计数。
-
该指针在整个请求处理过程中保持不变;所有需要认证信息的辅助函数都会直接访问 sess->user。
-
3. 在 Worker‑A 尚未处理完时,Worker‑B(在第一个连接 C1 上运行)处理了同一会话的 SMB2 LOGOFF 请求,并调用了 smb2_session_logoff()(位于 smb2pdu.c)。
smb2_session_logoff() 中的相关代码段
if (sess->user) {
ksmbd_free_user(sess->user); /* (1) 释放内存 */
sess->user = NULL; /* (2) 清空字段 */
}
ksmbd_free_user() 最终会调用简单的 kfree(user) 来释放内存。
4. Worker‑B 不会等待其他仍在使用该会话的连接完成操作;它只会等待 自己这个连接 上正在运行的请求结束(通过 ksmbd_conn_wait_idle(conn) 实现)。
5. Worker‑A 继续执行(例如在 smb2_open()、smb2_write() 等函数中),并解引用了 sess->user:
/* 以下是部分示例(类似用法还有很多) */
if (user_guest(sess->user)) ← 释放后的解引用
ksmbd_compare_user(sess->user, …)
sess->user->uid
由于该内存已在步骤 (1) 中通过 kfree() 释放,因此这些访问操作实际访问了已释放的内存。具体后果取决于访问发生的时机:
-
如果指针仍指向被回收的 slab 对象,即发生 use-after-free,可能被攻击者利用修改内核内存;
-
如果 Worker‑A 在步骤 (2) 后访问,即 sess->user 已被置为 NULL,则会发生空指针解引用,导致拒绝服务(DoS)。
在读完 o3 模型生成的漏洞报告之后,Sean Heelan 意识到他原先的理解并不充分。虽然 logoff 处理函数确实将 sess->user 置为了 NULL,但这个措施仍然不够,因为 SMB 协议允许两个不同的连接“绑定”到同一个会话上,而在 Kerberos 认证路径上并没有机制能阻止其他线程在 sess->user 被释放与被置为 NULL 的那一小段时间内继续使用它。Heelan 指出,自己此前其实已经利用过这个特性触发 ksmbd 的另一个漏洞,但在分析此次 Kerberos 认证漏洞时却没有想到这一点。
在意识到问题后,Heelan 回过头去检查了 o3 在搜索 Kerberos 认证漏洞时生成的报告。他发现,o3 在部分结果中确实和他一样遗漏了这一点,但在其他一些报告中则准确地指出:仅仅将 sess->user 置为 NULL 并不足以彻底修复问题,因为会话绑定机制仍然可能导致竞态条件的发生。Heelan 认为,这一点相当令人印象深刻——如果他一开始就借助 o3 来定位并修复该漏洞,理论上本可以取得更好的结果。当然,他也坦言,目前 o3 的误报率仍偏高,不一定能保证他有足够的精力逐一甄别每条报告并从中发现这个关键点。但随着模型能力的提升,这一比例有望持续改善。
结论
最后,Sean Heelan 总结道,大型语言模型(LLMs)在程序分析能力空间中所处的位置,比我们以往见过的任何技术都更接近人类。就创造力、灵活性和通用性而言,LLM 更像是一位人类代码审计专家,而不是符号执行、抽象解释或模糊测试工具。自从 GPT-4 出现以来,人们就对 LLM 在漏洞研究中的潜力抱有期待,但它在现实问题中的表现一直没能真正达到人们的期望。而 o3 的出现改变了这一局面:我们终于有了一个在代码推理、问答、编程和问题解决方面足够优秀的模型,能够实实在在提升人类在漏洞研究中的效率。
当然,o3 远非万无一失。它仍有相当大的概率会生成荒谬的结果,令人沮丧。但不同的是,现在它给出正确答案的概率终于足够高,值得大家投入时间和精力,尝试将其应用于真实问题。
原文:https://sean.heelan.io/2025/05/22/how-i-used-o3-to-find-cve-2025-37899-a-remote-zeroday-vulnerability-in-the-linux-kernels-smb-implementation/
📢 2025 全球产品经理大会
2025 年 8 月 15–16 日
北京·威斯汀酒店
2025 全球产品经理大会将汇聚互联网大厂、AI 创业公司、ToB/ToC 实战一线的产品人,围绕产品设计、用户体验、增长运营、智能落地等核心议题,展开 12 大专题分享,洞察趋势、拆解路径、对话未来。
更多详情与报名,请扫码下方二维码。