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
- Перевірте плани підписки!
- Приєднуйтесь до 💬 Discord group, telegram group, слідкуйте за @hacktricks_live на X/Twitter, або перегляньте сторінку LinkedIn і YouTube channel.
- Діліться hacking tricks, надсилаючи PRs до репозиторіїв github HackTricks і HackTricks Cloud.
Ця сторінка документує детермінований 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 enablesvfs 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_lenwith-EINVAL. Pre-fix, attacker could reuse a valid authenticated handle to a named stream and send a raw SMB2 WRITE whosefile_offsetalready points at or past the end of the existing stream, which turns the post-clampmemcpy()into a deterministic page overflow. - Публічний PoC demonstrates this by authenticating with
libsmb2, opening a stream path such as1337:, extractingSessionId/TreeId/FileId, and then sending a handcrafted SMB2 WRITE withfile_offset = 0x10018and a smallLength.
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_msgsegallocations приєднано до кожного sprayed message, що корисно під час tuning розмірів primary/secondary message для конкретного kernel build.- Якщо exploit ported на інший distro/kernel, перевір заново cache names, inline
msg_msgpayload sizes,anon_pipe_buf_opsoffsets і gadget addresses, а не припускай, що константи Ubuntu 22.04 LTS5.15.0-153-genericі далі збігаються.
План exploitation (msg_msg + pipe_buffer), адаптований з CVE-2021-22555
- Spray багато System V msg_msg primary/secondary messages (розмір 4KiB, щоб вміститися в kmalloc-cg-4k).
- Trigger ksmbd OOB, щоб пошкодити next pointer primary message так, щоб два primaries ділили один secondary.
- Detect пошкоджену пару через tagging queues і scanning за допомогою msgrcv(MSG_COPY), щоб знайти mismatched tags.
- Free справжній secondary, щоб створити UAF; reclaim його контрольованими даними через UNIX sockets (створити fake msg_msg).
- Leak kernel heap pointers, зловживаючи m_ts over-read у copy_msg, щоб отримати mlist.next/mlist.prev (обхід SMAP).
- Зі spray
sk_buffrebuild consistent fake msg_msg з валідними links і free його нормально, щоб стабілізувати state. - Reclaim UAF за допомогою об’єктів struct pipe_buffer; leak anon_pipe_buf_ops, щоб обчислити kernel base (обхід KASLR).
- 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
kvmallocaddresses і histogram allocations (наприклад,grep 4048 out-4096.txt) - Minimal reachability PoC і full local 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 для assessment tracks (ARTA/GRTA/AzRTA) і Linux Hacking Expert (LHE).
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 Discord group, telegram group, слідкуйте за @hacktricks_live на X/Twitter, або перегляньте сторінку LinkedIn і YouTube channel.
- Діліться hacking tricks, надсилаючи PRs до репозиторіїв github HackTricks і HackTricks Cloud.


