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

本页记录了 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 少量动态字段(TreeIdSessionIdFileId),然后就可以在同一个 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 NormalUnmovable migrate 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_msg objects(可落入 kmalloc-cg-4k)来填充 order-3 slabs。
  • 接收一些 messages 以打出 holes 并促进相邻布局。
  • 反复触发 ksmbd OOB,直到 order-4 stream buffer 正好落在一个 msg_msg slab 之前。如果可用,使用 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_msg payload 大小、anon_pipe_buf_ops 偏移以及 gadget 地址,不要假设 Ubuntu 22.04 LTS 5.15.0-153-generic 的常量仍然匹配。

Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555

  1. Spray many System V msg_msg primary/secondary messages (4KiB-sized to fit kmalloc-cg-4k).
  2. Trigger ksmbd OOB to corrupt a primary message’s next pointer so that two primaries share one secondary.
  3. Detect the corrupted pair by tagging queues and scanning with msgrcv(MSG_COPY) to find mismatched tags.
  4. Free the real secondary to create a UAF; reclaim it with controlled data via UNIX sockets (craft a fake msg_msg).
  5. Leak kernel heap pointers by abusing m_ts over-read in copy_msg to obtain mlist.next/mlist.prev (SMAP bypass).
  6. With an sk_buff spray, rebuild a consistent fake msg_msg with valid links and free it normally to stabilize state.
  7. Reclaim the UAF with struct pipe_buffer objects; leak anon_pipe_buf_ops to compute kernel base (defeat KASLR).
  8. 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

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