ksmbd streams_xattr OOB write โ local LPE (CVE-2025-37947)
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 ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
์ด ํ์ด์ง๋ ksmbd streams ์ฒ๋ฆฌ์์ ๋ฐ์ํ๋ ๊ฒฐ์ ๋ก ์ out-of-bounds write๋ฅผ ๋ฌธ์ํํ๋ฉฐ, ํ์ค ์ปค๋ ํ ํ๋ฆฌ๋ฏธํฐ๋ธ (msg_msg + pipe_buffer)๋ฅผ ์ฌ์ฉํด KASLR, SMEP, SMAP์ ์ฐํํ์ฌ Ubuntu 22.04 LTS (5.15.0-153-generic)์์ ์ ๋ขฐํ ์ ์๋ Linux kernel privilege escalation์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- ์ํฅ๋ฐ๋ ๊ตฌ์ฑ์์: fs/ksmbd/vfs.c โ ksmbd_vfs_stream_write()
- ํ๋ฆฌ๋ฏธํฐ๋ธ: page-overflow OOB write past a 0x10000-byte kvmalloc() buffer
- ์ ์ ์กฐ๊ฑด: vfs streams_xattr๋ฅผ ์ฌ์ฉํ๋ ์ธ์ฆ๋ ์ฐ๊ธฐ ๊ฐ๋ฅํ ๊ณต์ ๊ฐ ์ค์ ๋ ์ํ์์ ksmbd๊ฐ ์คํ ์ค
Example smb.conf
[share]
path = /share
vfs objects = streams_xattr
writeable = yes
๊ทผ๋ณธ ์์ธ (ํ ๋น์ด ์ ํ๋๊ณ , ์ ํ๋์ง ์์ ์คํ์ ์์ memcpy ๋ฐ์)
- ํจ์๋ size = *pos + count ๋ฅผ ๊ณ์ฐํ๊ณ , ์ด๊ณผํ๋ฉด size๋ฅผ XATTR_SIZE_MAX (0x10000)์ผ๋ก ์ ํ(clamp)ํ๋ฉฐ, count๋ฅผ (*pos + count) - 0x10000 ์ผ๋ก ์ฌ๊ณ์ฐํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฌ์ ํ memcpy(&stream_buf[*pos], buf, count)๋ฅผ 0x10000-๋ฐ์ดํธ ๋ฒํผ์ ์ํํฉ๋๋ค. ๋ง์ฝ *pos โฅ 0x10000 ์ด๋ฉด ๋ชฉ์ ์ง ํฌ์ธํฐ๋ ์ด๋ฏธ ํ ๋น ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ฏ๋ก count ๋ฐ์ดํธ์ OOB write๊ฐ ๋ฐ์ํฉ๋๋ค.
์ทจ์ฝํ ํจ์ ์ค๋ํซ (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; } ```์คํ์ ์กฐ์ ๋ฐ OOB ๊ธธ์ด
- ์: file offset (pos)๋ฅผ 0x10018๋ก ์ค์ ํ๊ณ ์๋ ๊ธธ์ด (count)๋ฅผ 8๋ก ์ค์ . ํด๋จํ ํ, countโ = (0x10018 + 8) - 0x10000 = 0x20 ์ด์ง๋ง memcpy๋ stream_buf[0x10018]์์ ์์ํด 32๋ฐ์ดํธ๋ฅผ ์ฐ๋ฏ๋ก 16-ํ์ด์ง ํ ๋น๋ณด๋ค 0x18 ๋ฐ์ดํธ ์ด๊ณผํ๋ค.
SMB streams write๋ฅผ ํตํด ๋ฒ๊ทธ ์ ๋ฐ
- ๋์ผํ ์ธ์ฆ๋ SMB ์ฐ๊ฒฐ์ ์ฌ์ฉํด share์ ํ์ผ์ ์ด๊ณ named stream (streams_xattr)์ write๋ฅผ ์คํํ๋ค. file_offset โฅ 0x10000๋ก ์ค์ ํ๊ณ ์์ ๊ธธ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ด ๊ฐ๋ฅํ ํฌ๊ธฐ์ ๊ฒฐ์ ๋ก ์ OOB write๋ฅผ ์์ฑํ๋ค.
- libsmb2๋ 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) requests an order-4 (16 contiguous pages) allocation from the buddy allocator when size > KMALLOC_MAX_CACHE_SIZE. This is not a SLUB cache object.
- memcpy occurs immediately after allocation; post-allocation spraying is ineffective. You must pre-groom physical memory so that a chosen target lies immediately after the allocated 16-page block.
- On Ubuntu, GFP_KERNEL often pulls from the Unmovable migrate type in zone Normal. Exhaust order-3 and order-4 freelists to force the allocator to split an order-5 block into an adjacent order-4 + order-3 pair, then park an order-3 slab (kmalloc-cg-4k) directly after the stream buffer.
ํ ๋น์ ๋์ ๋ฐ ์ page shaping์ด ํ์ํ๊ฐ
- kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO)๋ size > KMALLOC_MAX_CACHE_SIZE์ผ ๋ buddy allocator๋ก๋ถํฐ order-4(์ฐ์๋ 16ํ์ด์ง) ํ ๋น์ ์์ฒญํฉ๋๋ค. ์ด๋ SLUB cache ๊ฐ์ฒด๊ฐ ์๋๋๋ค.
- memcpy๋ ํ ๋น ์งํ์ ๋ฐ์ํ๋ฏ๋ก, ํ ๋น ํ์ ์คํ๋ ์ดํ๋ ๊ฒ์ ํจ๊ณผ๊ฐ ์์ต๋๋ค. ์ ํํ ํ๊น์ด ํ ๋น๋ 16ํ์ด์ง ๋ธ๋ก ๋ฐ๋ก ๋ค์์ ์ค๋๋ก ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ ์ ์ ๋ฆฌ(pre-groom)ํด์ผ ํฉ๋๋ค.
- Ubuntu์์๋ GFP_KERNEL์ด zone Normal์ Unmovable migrate ํ์ ์์ ํ ๋น๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. order-3๊ณผ order-4 freelist๋ฅผ ๊ณ ๊ฐ์์ผ allocator๊ฐ order-5 ๋ธ๋ก์ ์ธ์ ํ order-4 + order-3 ์์ผ๋ก ๋ถํ ํ๋๋ก ๊ฐ์ ํ ๋ค์, stream buffer ๋ฐ๋ก ๋ค์ order-3 slab(kmalloc-cg-4k)๋ฅผ ๋ฐฐ์นํ์ธ์.
Practical page shaping strategy
- Spray ~1000โ2000 msg_msg objects of ~4096 bytes (fits kmalloc-cg-4k) to populate 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. Use eBPF tracing to confirm addresses and alignment if available.
์ค์ page shaping ์ ๋ต
- order-3 slab์ ์ฑ์ฐ๊ธฐ ์ํด ์ฝ 4096๋ฐ์ดํธ ํฌ๊ธฐ์ msg_msg ๊ฐ์ฒด๋ฅผ ๋๋ต 1000โ2000๊ฐ ์ ๋ Sprayํ์ธ์(์ด๋ kmalloc-cg-4k์ ์ ํฉํฉ๋๋ค).
- ์ผ๋ถ ๋ฉ์์ง๋ฅผ ์์ ํ์ฌ punch holes๋ฅผ ๋ง๋ค๊ณ ์ธ์ ์ฑ์ ์ ๋ํ์ธ์.
- order-4 stream buffer๊ฐ msg_msg slab ๋ฐ๋ก ์์ ์ฌ ๋๊น์ง ksmbd OOB๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ํธ๋ฆฌ๊ฑฐํ์ธ์. ๊ฐ๋ฅํ๋ฉด 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
Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555
- Spray many System V msg_msg primary/secondary messages (4KiB-sized to fit kmalloc-cg-4k).
- Trigger ksmbd OOB to corrupt a primary messageโs next pointer so that two primaries share one secondary.
- Detect the corrupted pair by tagging queues and scanning with msgrcv(MSG_COPY) to find mismatched tags.
- Free the real secondary to create a UAF; reclaim it with controlled data via UNIX sockets (craft a fake msg_msg).
- Leak kernel heap pointers by abusing m_ts over-read in copy_msg to obtain mlist.next/mlist.prev (SMAP bypass).
- With an sk_buff spray, rebuild a consistent fake msg_msg with valid links and free it normally to stabilize state.
- Reclaim the UAF with struct pipe_buffer objects; leak anon_pipe_buf_ops to compute kernel base (defeat KASLR).
- Spray a fake pipe_buf_operations with release pointing to a stack pivot/ROP gadget; close pipes to execute and gain root.
์ฐํ ๋ฐ ๋ ธํธ
- KASLR: anon_pipe_buf_ops๋ฅผ leakํ์ฌ base(kbase_addr)์ gadget ์ฃผ์ ๊ณ์ฐ.
- SMEP/SMAP: pipe_buf_operations->release ํ๋ฆ์ ํตํด kernel ์ปจํ ์คํธ์์ ROP๋ฅผ ์คํ; disable/prepare_kernel_cred/commit_creds ์ฒด์ธ ์ด์ ๊น์ง userspace derefs๋ฅผ ํผํจ.
- Hardened usercopy: ์ด page overflow primitive์๋ ์ ์ฉ๋์ง ์์; ์์ ๋์์ non-usercopy ํ๋.
์ ๋ขฐ์ฑ
- ์ธ์ ์ฑ(adjacency)์ ํ๋ณดํ๋ฉด ์ ๋ขฐ๋ ๋์; ๊ฐ๋ ์คํจ๋ panic ๋ฐ์(<10%). spray/free ํ์ ์กฐ์ ์ผ๋ก ์์ ์ฑ ํฅ์. ํน์ ์ถฉ๋์ ์ ๋ํ๊ธฐ ์ํด ํฌ์ธํฐ์ ๋ LSBs๋ฅผ ๋ฎ์ด์ฐ๋ ๋ฐฉ๋ฒ์ด ํจ๊ณผ์ ์ด๋ผ๊ณ ๋ณด๊ณ ๋จ(์: ๊ฒน์นจ ์์ญ์ 0x0000_0000_0000_0500 ํจํด์ ์).
์กฐ์ ํด์ผ ํ ์ฃผ์ ํ๋ผ๋ฏธํฐ
- 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
์ํ ๋ฐ ๋๋ฌ์ฑ
- 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.
์ฐธ๊ณ : PoC ๋ฐ ๋๊ตฌ
- 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 ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


