ksmbd streams_xattr OOB write → local LPE (CVE-2025-37947)

Reading time: 8 minutes

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

本页记录了 ksmbd streams 处理中的一个确定性 out-of-bounds write,该漏洞可在 Ubuntu 22.04 LTS (5.15.0-153-generic) 上可靠地触发 Linux kernel privilege escalation,同时通过标准内核堆原语(msg_msg + pipe_buffer)绕过 KASLR、SMEP 和 SMAP。

  • 受影响的组件:fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
  • 原语:page-overflow OOB write 越过 0x10000 字节的 kvmalloc() 缓冲区
  • 前提条件:ksmbd 以支持 vfs streams_xattr 的已认证、可写 share 运行

示例 smb.conf

ini
[share]
path = /share
vfs objects = streams_xattr
writeable = yes

根本原因(分配大小被限制,memcpy 在未被限制的偏移处)

  • 该函数计算 size = *pos + count,当超过 XATTR_SIZE_MAX (0x10000) 时将 size 限制为该值,并重新计算 count = (*pos + count) - 0x10000,但仍然执行 memcpy(&stream_buf[*pos], buf, count) 到一个大小为 0x10000 字节的缓冲区。如果 *pos ≥ 0x10000,则目标指针已经位于分配之外,从而产生 count 字节的 OOB 写入。
易受攻击的函数片段 (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

  • 示例:将 file offset (pos) 设置为 0x10018,原始长度 (count) 为 8。经过 clamping 后,count' = (0x10018 + 8) - 0x10000 = 0x20,但 memcpy 会从 stream_buf[0x10018] 开始写入 32 字节,即比 16 页分配多出 0x18 字节。

  • Triggering the bug via SMB streams write

    • 使用相同的已认证 SMB 连接打开共享上的文件,并对命名流 (streams_xattr) 发起写操作。将 file_offset ≥ 0x10000 并使用较小的长度,可产生可控大小的确定性 OOB 写入。
    • 可以使用 libsmb2 在 SMB2/3 上进行认证并构造此类写入。
  • Minimal reachability(概念)

c
// 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

Allocator behavior and why page shaping is required

  • kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO) 在 size > KMALLOC_MAX_CACHE_SIZE 时向 buddy allocator 请求一个 order-4(16 个连续页面)的分配。这不是一个 SLUB cache 对象。
  • memcpy 在分配后立即发生;post-allocation spraying 无效。你必须 pre-groom 物理内存,以使选定目标位于分配的 16 页块的紧接其后。
  • 在 Ubuntu 上,GFP_KERNEL 通常从 zone Normal 的 Unmovable migrate type 中获取页面。耗尽 order-3 和 order-4 freelist 以强制分配器将一个 order-5 块拆分为相邻的 order-4 + order-3 对,然后在 stream buffer 之后直接放置一个 order-3 slab(kmalloc-cg-4k)。

Practical page shaping strategy

  • Spray ~1000–2000 个约 4096 字节的 msg_msg 对象(fits kmalloc-cg-4k)以填充 order-3 slabs。
  • Receive 一些消息以 punch holes 并鼓励相邻性。
  • 重复触发 ksmbd OOB,直到 order-4 stream buffer 紧挨着位于 msg_msg slab 之前。如果可用,使用 eBPF tracing 确认地址和对齐。

Useful observability

bash
# 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

利用计划 (msg_msg + pipe_buffer),改编自 CVE-2021-22555

  1. Spray many System V msg_msg primary/secondary messages (4KiB-sized to fit kmalloc-cg-4k).
  2. 触发 ksmbd OOB 以破坏 primary message 的 next pointer,使两个 primaries 共享一个 secondary。
  3. 通过给队列打标签并使用 msgrcv(MSG_COPY) 扫描以找到标签不匹配,从而检测被破坏的对。
  4. 释放真实的 secondary 以创建 UAF;通过 UNIX sockets 使用可控数据回收它(craft a fake msg_msg)。
  5. 通过滥用 copy_msg 中的 m_ts 过读来 leak 内核 heap 指针以获取 mlist.next/mlist.prev(绕过 SMAP)。
  6. 使用 sk_buff spray,重建具有有效链接的一致 fake msg_msg,并正常 free 它以稳定状态。
  7. 使用 struct pipe_buffer 对象回收 UAF;leak anon_pipe_buf_ops 以计算 kernel base(击败 KASLR)。
  8. Spray a fake pipe_buf_operations with release pointing to a stack pivot/ROP gadget;关闭 pipes 以触发执行并获取 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

  • 一旦达到 adjacency,可靠性高;偶有 miss 或 panic(<10%)。调整 spray/free 次数可提高稳定性。报告指出,通过覆盖指针的两个 LSB 来引发特定碰撞是有效的(例如,在重叠处写入 0x0000_0000_0000_0500 模式)。

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: clamp both allocation and destination/length or bound memcpy against the allocated size; upstream patches track as CVE-2025-37947.
  • Remote exploitation would additionally require a reliable infoleak and remote heap grooming; this write-up focuses on local LPE.

References PoC and tooling

  • libsmb2 for SMB auth and streams writes
  • eBPF tracer script to log kvmalloc addresses and histogram allocations (e.g., grep 4048 out-4096.txt)
  • Minimal reachability PoC and full local exploit are publicly available (see References)

References

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks