ksmbd streams_xattr OOB write → local LPE (CVE-2025-37947)
Tip
学习并实践 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并实践 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并实践 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
浏览用于评估路线的 完整 HackTricks Training 目录(ARTA/GRTA/AzRTA)以及 Linux Hacking Expert (LHE)。
支持 HackTricks
- 查看 订阅方案!
- 加入 💬 Discord 群组、telegram 群组,关注 X/Twitter 上的 @hacktricks_live,或查看 LinkedIn 页面 和 YouTube 频道。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR,分享 hacking 技巧。
本页记录了 ksmbd streams 处理中的一个确定性越界写,这个问题可在 Ubuntu 22.04 LTS (5.15.0-153-generic) 上实现可靠的 Linux kernel 权限提升,并通过标准 kernel heap 原语(msg_msg + pipe_buffer)绕过 KASLR、SMEP 和 SMAP。
- 受影响组件: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
- 原语: 在一个 0x10000 字节的 kvmalloc() buffer 之后发生 page-overflow OOB write
- 前提条件: ksmbd 以已认证、可写 share 运行,并使用 vfs streams_xattr
Example smb.conf
[share]
path = /share
vfs objects = streams_xattr
writeable = yes
根本原因(allocation 被截断,memcpy 在未截断的 offset 处执行)
- 该函数计算
size = *pos + count,当超过XATTR_SIZE_MAX(0x10000)时将size截断到0x10000,并重新计算count = (*pos + count) - 0x10000,但仍然会对一个 0x10000 字节的 buffer 执行memcpy(&stream_buf[*pos], buf, count)。如果*pos ≥ 0x10000,目标指针已经超出 allocation,从而产生count字节的 OOB write。 streams_xattr将 SMB alternate data streams 存储在 POSIX extended attributes 中,所以这个 0x10000 上限来自 Linux 单个 xattr 的大小限制,而不是来自 SMB protocol 的某个字段。因此,只有在 share 明确启用vfs objects = streams_xattr且 filesystem 支持 xattrs 时,这个 bug 才具备实际可利用性。
为什么写入 offset 很重要
- 漏洞路径并不只是“写入超过 64KiB”。真正缺失的是:在 append/copy 逻辑执行前,没有检查
*pos是否相对于当前 stream length(v_len)有效。 - 上游修复方式是:当
*pos >= v_len时直接返回-EINVAL。在修复前,攻击者可以复用一个已认证的有效 handle 打开一个命名 stream,并发送原始的 SMB2 WRITE,使其file_offset已经指向或超过现有 stream 的末尾,从而把截断后的memcpy()变成确定性的 page overflow。 - 公共 PoC 通过
libsmb2完成认证,打开类似1337:这样的 stream path,提取SessionId/TreeId/FileId,然后发送一个手工构造的 SMB2 WRITE,其中file_offset = 0x10018,并使用一个很小的Length。
Vulnerable function snippet (ksmbd_vfs_stream_write)
```c // https://elixir.bootlin.com/linux/v5.15/source/fs/ksmbd/vfs.c#L411 static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, size_t count) { char *stream_buf = NULL, *wbuf; size_t size; ... size = *pos + count; if (size > XATTR_SIZE_MAX) { // [1] clamp allocation, but... size = XATTR_SIZE_MAX; count = (*pos + count) - XATTR_SIZE_MAX; // [1.1] ...recompute count } wbuf = kvmalloc(size, GFP_KERNEL | __GFP_ZERO); // [2] alloc 0x10000 stream_buf = wbuf; memcpy(&stream_buf[*pos], buf, count); // [3] OOB when *pos >= 0x10000 ... kvfree(stream_buf); return err; } ```Offset steering 和 OOB length
- Example: 将 file offset (pos) 设为 0x10018,原始 length (count) 设为 8。经过 clamping 后,count’ = (0x10018 + 8) - 0x10000 = 0x20,但 memcpy 会从 stream_buf[0x10018] 开始写入 32 bytes,也就是超出 16-page allocation 0x18 bytes。
通过 SMB streams write 触发 bug
- 使用同一个已认证的 SMB connection,在 share 上打开一个 file,并对一个 named stream (streams_xattr) 发起 write。设置 file_offset ≥ 0x10000 且 length 较小,可生成一个可控 size 的 deterministic OOB write。
- libsmb2 可用于认证并通过 SMB2/3 构造此类 writes。
- 实践中,重用已协商的 SMB session 很方便,因为 exploit 只需要在 WRITE request 中 patch 少量动态字段(
TreeId、SessionId、FileId),然后就可以在同一个 socket 上直接发送 malformed packet。
Minimal reachability (concept)
// Pseudocode: send SMB streams write with pos=0x0000010018ULL, len=8
smb2_session_login(...);
smb2_open("\\\\host\\share\\file:stream", ...);
smb2_pwrite(fd, payload, 8, 0x0000010018ULL); // yields 32-byte OOB
分配器行为以及为何需要 page shaping
kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO)在size > KMALLOC_MAX_CACHE_SIZE时,会从 buddy allocator 请求一个 order-4(16 个连续 pages)分配。这不是一个 SLUB cache object。memcpy在分配后会立即发生;事后 spraying 无效。你必须预先 groom physical memory,使某个选定 target 紧挨着已分配的 16-page block。- 在 Ubuntu 上,
GFP_KERNEL常常会从zone Normal的Unmovablemigrate type 中取页。耗尽 order-3 和 order-4 freelists,迫使分配器把一个 order-5 block 拆成相邻的 order-4 + order-3 对,然后把一个 order-3 slab(kmalloc-cg-4k)直接放在 stream buffer 后面。
实用的 page shaping 策略
- spray 约 1000–2000 个大小约 4096 bytes 的
msg_msgobjects(可落入kmalloc-cg-4k)来填充 order-3 slabs。 - 接收一些 messages 以打出 holes 并促进相邻布局。
- 反复触发
ksmbdOOB,直到 order-4 stream buffer 正好落在一个msg_msgslab 之前。如果可用,使用 eBPF tracing 来确认 addresses 和 alignment。
有用的可观测性
# Check per-order freelists and migrate types
sudo cat /proc/pagetypeinfo | sed -n '/Node 0, zone Normal/,/Node/p'
# Example tracer (see reference repo) to log kvmalloc addresses/sizes
sudo ./bpf-tracer.sh
调试时需要跟踪的内容
kvmalloc_node(0x10000)用于确认 vulnerable stream write 何时真正消耗了一个 order-4 分配。load_msg/kretprobe:load_msg让你能够估算每个 sprayed message 上挂接了多少个msg_msgseg分配,这在针对特定 kernel build 调整 primary/secondary message 大小时很有用。- 如果 exploit 被移植到不同的 distro/kernel,重新检查 cache 名称、inline
msg_msgpayload 大小、anon_pipe_buf_ops偏移以及 gadget 地址,不要假设 Ubuntu 22.04 LTS5.15.0-153-generic的常量仍然匹配。
Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555
- Spray many System V msg_msg primary/secondary messages (4KiB-sized to fit kmalloc-cg-4k).
- Trigger ksmbd OOB to corrupt a primary message’s next pointer so that two primaries share one secondary.
- Detect the corrupted pair by tagging queues and scanning with msgrcv(MSG_COPY) to find mismatched tags.
- Free the real secondary to create a UAF; reclaim it with controlled data via UNIX sockets (craft a fake msg_msg).
- Leak kernel heap pointers by abusing m_ts over-read in copy_msg to obtain mlist.next/mlist.prev (SMAP bypass).
- With an sk_buff spray, rebuild a consistent fake msg_msg with valid links and free it normally to stabilize state.
- Reclaim the UAF with struct pipe_buffer objects; leak anon_pipe_buf_ops to compute kernel base (defeat KASLR).
- Spray a fake pipe_buf_operations with release pointing to a stack pivot/ROP gadget; close pipes to execute and gain root.
Bypasses and notes
- KASLR: leak anon_pipe_buf_ops, compute base (kbase_addr) and gadget addresses.
- SMEP/SMAP: execute ROP in kernel context via pipe_buf_operations->release flow; avoid userspace derefs until after disable/prepare_kernel_cred/commit_creds chain.
- Hardened usercopy: not applicable to this page overflow primitive; corruption targets are non-usercopy fields.
Reliability
- Once adjacency is achieved, reliability is high; occasional misses or panics (<10%). Tuning spray/free counts improves stability. Overwriting two LSBs of a pointer to induce specific collisions was reported as effective (e.g., write 0x0000_0000_0000_0500 pattern into the overlap).
Key parameters to tune
- Number of msg_msg sprays and hole pattern
- OOB offset (pos) and resulting OOB length (count’)
- Number of UNIX socket, sk_buff, and pipe_buffer sprays during each stage
Mitigations and reachability
- Fix: 同时限制 allocation 和 destination/length,或者对 allocated size 约束 memcpy;upstream patches 以 CVE-2025-37947 跟踪。
- 远程 exploitation 还需要一个可靠的 infoleak 和远程 heap grooming;本文重点是本地 LPE。
另见
Ksmbd Attack Surface And Fuzzing Syzkaller
References PoC and tooling
- 用于 SMB auth 和 streams writes 的 libsmb2
- 用于记录 kvmalloc 地址并生成分布直方图的 eBPF tracer script(例如,grep 4048 out-4096.txt)
- 最小化 reachability PoC 和完整的本地 exploit 都已公开(见 References)
References
- ksmbd - Exploiting CVE-2025-37947 (3/3) — Doyensec
- Linux upstream fix:
ksmbd: prevent out-of-bounds stream writes by validating *pos - KSMBD-CVE-2025-37947 PoC repository
Tip
学习并实践 AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学习并实践 GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学习并实践 Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
浏览用于评估路线的 完整 HackTricks Training 目录(ARTA/GRTA/AzRTA)以及 Linux Hacking Expert (LHE)。
支持 HackTricks
- 查看 订阅方案!
- 加入 💬 Discord 群组、telegram 群组,关注 X/Twitter 上的 @hacktricks_live,或查看 LinkedIn 页面 和 YouTube 频道。
- 通过向 HackTricks 和 HackTricks Cloud github 仓库提交 PR,分享 hacking 技巧。


