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)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Ця сторінка документує детермінований out-of-bounds write у обробці ksmbd streams, який дозволяє надійне підвищення привілеїв у Linux kernel на Ubuntu 22.04 LTS (5.15.0-153-generic), обходячи KASLR, SMEP та SMAP за допомогою стандартних kernel heap примітивів (msg_msg + pipe_buffer).
- Постраждалий компонент: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
- Примітив: page-overflow OOB write за межі 0x10000-байтного kvmalloc() буфера
- Передумови: ksmbd запущений з аутентифікованим, доступним для запису share, який використовує vfs streams_xattr
Приклад smb.conf
[share]
path = /share
vfs objects = streams_xattr
writeable = yes
Коренева причина (виділення обмежене, memcpy за необмеженим зсувом)
- Функція обчислює size = *pos + count, обмежує size до XATTR_SIZE_MAX (0x10000) при перевищенні, і повторно обчислює count = (*pos + count) - 0x10000, але все ще виконує memcpy(&stream_buf[*pos], buf, count) у буфер розміром 0x10000 байт. Якщо *pos ≥ 0x10000, вказівник призначення вже знаходиться поза межами виділення, що призводить до OOB write на count байтів.
Фрагмент уразливої функції (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 і довжиною OOB
- Приклад: встановіть file offset (pos) в 0x10018 і початкову довжину (count) в 8. Після clamping, count’ = (0x10018 + 8) - 0x10000 = 0x20, але memcpy записує 32 байти, починаючи з stream_buf[0x10018], тобто на 0x18 байтів за межі виділення в 16 сторінок.
Triggering the bug via SMB streams write
- Використовуйте те саме автентифіковане SMB-з’єднання, щоб відкрити файл на шарі і виконати write в іменований стрім (streams_xattr). Встановіть file_offset ≥ 0x10000 з малою довжиною, щоб згенерувати детермінований OOB write керованого розміру.
- libsmb2 можна використати для аутентифікації та формування таких write-операцій через SMB2/3.
Мінімальна досяжність (концепція)
// 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) запитує алокацію order-4 (16 contiguous pages) від buddy allocator, коли size > KMALLOC_MAX_CACHE_SIZE. Це не SLUB cache object.
- memcpy occurs immediately after allocation; post-allocation spraying is ineffective. Ви повинні pre-groom фізичну пам’ять так, щоб обраний target лежав відразу після виділеного 16-page блоку.
- On Ubuntu, GFP_KERNEL often pulls from the Unmovable migrate type in zone Normal. Виснажте order-3 і order-4 freelists, щоб змусити аллокатор розбити order-5 блок на суміжну пару order-4 + order-3, потім розмістіть order-3 slab (kmalloc-cg-4k) безпосередньо після stream buffer.
Practical page shaping strategy
- Spray ~1000–2000 msg_msg objects of ~4096 bytes (fits kmalloc-cg-4k) щоб заповнити order-3 slabs.
- Receive some messages to punch holes and encourage adjacency.
- Trigger the ksmbd OOB repeatedly until the order-4 stream buffer lands immediately before a msg_msg slab. Використовуйте eBPF tracing щоб підтвердити адреси та вирівнювання, якщо доступно.
Useful 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
План експлуатації (msg_msg + pipe_buffer), адаптований з CVE-2021-22555
- Розпорошити велику кількість System V msg_msg первинних/вторинних повідомлень (розмір 4KiB, щоб поміститися в kmalloc-cg-4k).
- Спровокувати ksmbd OOB для пошкодження поля next у первинному повідомленні так, щоб два первинних поділяли одну вторинну.
- Виявити пошкоджену пару, тегуючи черги і скануючи за допомогою msgrcv(MSG_COPY) для знаходження невідповідних тегів.
- Звільнити реальну вторинну, щоб створити UAF; повторно захопити її контрольованими даними через UNIX sockets (скрафтити fake msg_msg).
- Leak вказівників купи ядра, зловживаючи over-read m_ts у copy_msg, щоб отримати mlist.next/mlist.prev (SMAP bypass).
- За допомогою sk_buff spray відновити коректний fake msg_msg з валідними лінками і звільнити його звичайним способом для стабілізації стану.
- Повторно захопити UAF об’єктами struct pipe_buffer; leak anon_pipe_buf_ops для обчислення бази ядра (подолати KASLR).
- Розпорошити fake pipe_buf_operations з release, що вказує на stack pivot/ROP gadget; закрити pipes для виконання і отримання root.
Bypasses and notes
- KASLR: leak anon_pipe_buf_ops, обчислити базу (kbase_addr) та адреси гаджетів.
- SMEP/SMAP: виконати ROP у контексті ядра через pipe_buf_operations->release; уникати userspace derefs до виконання disable/prepare_kernel_cred/commit_creds chain.
- Hardened usercopy: не застосовується до цього page overflow primitive; корупція торкається полів, що не є usercopy.
Reliability
- Висока після досягнення adjacency; поодинокі пропуски або паніки (<10%). Налаштування кількостей spray/free підвищує стабільність. Було повідомлено, що ефективним є перезапис двох LSB вказівника для викликання специфічних колізій (наприклад, запис патерну 0x0000_0000_0000_0500 у 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: 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
- ksmbd - Exploiting CVE-2025-37947 (3/3) — Doyensec
- libsmb2
- KSMBD-CVE-2025-37947: proof-of-concept.c
- KSMBD-CVE-2025-37947: CVE-2025-37947.c (full exploit)
- bpf-tracer.sh
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
HackTricks

