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 для assessment tracks (ARTA/GRTA/AzRTA) і Linux Hacking Expert (LHE).

Підтримайте HackTricks

Ця сторінка документує детермінований out-of-bounds write у обробці streams в ksmbd, який забезпечує надійну ескалацію привілеїв у Linux kernel на Ubuntu 22.04 LTS (5.15.0-153-generic), обходячи KASLR, SMEP і SMAP за допомогою стандартних kernel heap primitives (msg_msg + pipe_buffer).

  • Уражений компонент: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
  • Primitive: page-overflow OOB write за межі 0x10000-byte kvmalloc() buffer
  • Передумови: ksmbd запущений з authenticated, writable share, що використовує vfs streams_xattr

Example smb.conf

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

Root cause (allocation clamped, memcpy at unclamped offset)

  • Функція обчислює size = *pos + count, обмежує size до XATTR_SIZE_MAX (0x10000) when exceeded, і перераховує count = (*pos + count) - 0x10000, але все одно виконує memcpy(&stream_buf[*pos], buf, count) у буфер 0x10000 bytes. Якщо *pos ≥ 0x10000, destination pointer already outside the allocation, що спричиняє OOB write of count bytes.
  • streams_xattr зберігає SMB alternate data streams всередині POSIX extended attributes, тому 0x10000 ceiling comes from the Linux single-xattr size limit rather than from an SMB protocol field. Це робить bug practical only when the share explicitly enables vfs objects = streams_xattr і filesystem supports xattrs.

Why the write offset matters

  • Вразливий шлях — це не просто “write more than 64KiB”. Відсутня перевірка того, що *pos не було validated against the current stream length (v_len) before the append/copy logic ran.
  • Upstream fixed this by rejecting writes where *pos >= v_len with -EINVAL. Pre-fix, attacker could reuse a valid authenticated handle to a named stream and send a raw SMB2 WRITE whose file_offset already points at or past the end of the existing stream, which turns the post-clamp memcpy() into a deterministic page overflow.
  • Публічний PoC demonstrates this by authenticating with libsmb2, opening a stream path such as 1337:, extracting SessionId/TreeId/FileId, and then sending a handcrafted SMB2 WRITE with file_offset = 0x10018 and a small 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 and OOB length

  • Приклад: set file offset (pos) to 0x10018 and original length (count) to 8. After clamping, count’ = (0x10018 + 8) - 0x10000 = 0x20, but memcpy writes 32 bytes starting at stream_buf[0x10018], i.e., 0x18 bytes beyond the 16-page allocation.

Triggering the bug via SMB streams write

  • Use the same authenticated SMB connection to open a file on the share and issue a write to a named stream (streams_xattr). Set file_offset ≥ 0x10000 with a small length to generate a deterministic OOB write of controllable size.
  • libsmb2 can be used to authenticate and craft such writes over SMB2/3.
  • In practice, reusing the negotiated SMB session is convenient because the exploit only needs to patch a few dynamic fields in the WRITE request (TreeId, SessionId, FileId) and can then transmit the malformed packet directly on the same socket.

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

Поведінка allocator і чому потрібне page shaping

  • kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO) запитує allocation порядку 4 (16 contiguous pages) у buddy allocator, коли size > KMALLOC_MAX_CACHE_SIZE. Це не об’єкт SLUB cache.
  • memcpy відбувається одразу після allocation; spraying після allocation неефективний. Потрібно заздалегідь groom фізичну memory так, щоб обраний target лежав безпосередньо після виділеного 16-page block.
  • На Ubuntu, GFP_KERNEL часто бере з Unmovable migrate type у zone Normal. Виснажте freelists порядку 3 і порядку 4, щоб змусити allocator розділити order-5 block на суміжну пару order-4 + order-3, а потім розмістити order-3 slab (kmalloc-cg-4k) прямо після stream buffer.

Практична strategія page shaping

  • Spray ~1000–2000 msg_msg objects розміром ~4096 bytes (підходить для kmalloc-cg-4k), щоб заповнити order-3 slabs.
  • Отримайте деякі messages, щоб зробити holes і сприяти adjacency.
  • Запускайте ksmbd OOB повторно, доки order-4 stream buffer не опиниться безпосередньо перед msg_msg slab. Використовуйте eBPF tracing, щоб підтвердити addresses і alignment, якщо доступно.

Корисна observability

# 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

Що трасувати під час tuning

  • kvmalloc_node(0x10000) підтверджує, коли вразливий stream write фактично споживає allocation order-4.
  • load_msg/kretprobe:load_msg дає змогу оцінити, скільки msg_msgseg allocations приєднано до кожного sprayed message, що корисно під час tuning розмірів primary/secondary message для конкретного kernel build.
  • Якщо exploit ported на інший distro/kernel, перевір заново cache names, inline msg_msg payload sizes, anon_pipe_buf_ops offsets і gadget addresses, а не припускай, що константи Ubuntu 22.04 LTS 5.15.0-153-generic і далі збігаються.

План exploitation (msg_msg + pipe_buffer), адаптований з CVE-2021-22555

  1. Spray багато System V msg_msg primary/secondary messages (розмір 4KiB, щоб вміститися в kmalloc-cg-4k).
  2. Trigger ksmbd OOB, щоб пошкодити next pointer primary message так, щоб два primaries ділили один secondary.
  3. Detect пошкоджену пару через tagging queues і scanning за допомогою msgrcv(MSG_COPY), щоб знайти mismatched tags.
  4. Free справжній secondary, щоб створити UAF; reclaim його контрольованими даними через UNIX sockets (створити fake msg_msg).
  5. Leak kernel heap pointers, зловживаючи m_ts over-read у copy_msg, щоб отримати mlist.next/mlist.prev (обхід SMAP).
  6. Зі spray sk_buff rebuild consistent fake msg_msg з валідними links і free його нормально, щоб стабілізувати state.
  7. Reclaim UAF за допомогою об’єктів struct pipe_buffer; leak anon_pipe_buf_ops, щоб обчислити kernel base (обхід KASLR).
  8. Spray fake pipe_buf_operations з release, що вказує на stack pivot/ROP gadget; close pipes, щоб виконати і отримати root.

Bypasses and notes

  • KASLR: leak anon_pipe_buf_ops, обчислити base (kbase_addr) і gadget addresses.
  • SMEP/SMAP: execute ROP у kernel context через flow pipe_buf_operations->release; уникати userspace derefs до chain disable/prepare_kernel_cred/commit_creds.
  • Hardened usercopy: не застосовується до цього page overflow primitive; targets corruption — це non-usercopy fields.

Reliability

  • Висока після досягнення adjacency; інколи бувають misses або panics (<10%). Tuning spray/free counts підвищує stability. Overwriting двох LSBs pointer, щоб спричинити specific collisions, було reported як ефективне (наприклад, запис патерна 0x0000_0000_0000_0500 у overlap).

Ключові параметри для tuning

  • Кількість msg_msg sprays і hole pattern
  • OOB offset (pos) та resulting OOB length (count’)
  • Кількість UNIX socket, sk_buff і pipe_buffer sprays під час кожного stage

Mitigations and reachability

  • Fix: clamp як allocation, так і destination/length або bound memcpy відносно allocated size; upstream patches tracked as CVE-2025-37947.
  • Remote exploitation додатково вимагав би reliable infoleak і remote heap grooming; цей write-up зосереджується на local LPE.

Дивіться також

Ksmbd Attack Surface And Fuzzing Syzkaller

References PoC and tooling

  • libsmb2 для SMB auth і streams writes
  • eBPF tracer script, щоб log kvmalloc addresses і histogram allocations (наприклад, grep 4048 out-4096.txt)
  • Minimal reachability PoC і full local 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 для assessment tracks (ARTA/GRTA/AzRTA) і Linux Hacking Expert (LHE).

Підтримайте HackTricks