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) assessment tracks (ARTA/GRTA/AzRTA) और Linux Hacking Expert (LHE) के लिए full HackTricks Training catalog ब्राउज़ करें।

HackTricks का समर्थन करें

यह पेज ksmbd streams handling में एक deterministic out-of-bounds write को दस्तावेज़ करता है, जो Ubuntu 22.04 LTS (5.15.0-153-generic) पर reliable Linux kernel privilege escalation सक्षम बनाता है, और standard kernel heap primitives (msg_msg + pipe_buffer) का उपयोग करके KASLR, SMEP, और SMAP को bypass करता है।

  • प्रभावित component: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
  • Primitive: 0x10000-byte kvmalloc() buffer के बाद page-overflow OOB write
  • Preconditions: ksmbd authenticated, writable share के साथ running हो, जिसमें vfs streams_xattr उपयोग हो

Example smb.conf

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

Root cause (allocation clamped, memcpy at unclamped offset)

  • The function computes size = *pos + count, clamps size to XATTR_SIZE_MAX (0x10000) when exceeded, and recomputes count = (*pos + count) - 0x10000, but still performs memcpy(&stream_buf[*pos], buf, count) into a 0x10000-byte buffer. If *pos ≥ 0x10000 the destination pointer is already outside the allocation, producing an OOB write of count bytes.
  • streams_xattr POSIX extended attributes के अंदर SMB alternate data streams store करता है, इसलिए 0x10000 ceiling Linux single-xattr size limit से आता है, न कि किसी SMB protocol field से। इससे bug व्यावहारिक रूप से सिर्फ तब होता है जब share explicitly vfs objects = streams_xattr enable करता है और filesystem xattrs support करता है।

Why the write offset matters

  • Vulnerable path सिर्फ “64KiB से ज़्यादा write” नहीं है। Missing check यह था कि append/copy logic चलने से पहले *pos को current stream length (v_len) के against validate नहीं किया गया था।
  • Upstream ने इसे *pos >= v_len होने पर -EINVAL देकर reject करके fix किया। Pre-fix, attacker एक valid authenticated handle to a named stream reuse कर सकता था और एक raw SMB2 WRITE भेज सकता था जिसका file_offset पहले से existing stream के end पर या उससे आगे point करता हो, जिससे post-clamp memcpy() deterministic page overflow बन जाता था।
  • Public PoC इसे libsmb2 से authenticate करके, 1337: जैसे stream path को open करके, SessionId/TreeId/FileId निकालकर, और फिर file_offset = 0x10018 तथा छोटे Length के साथ handcrafted SMB2 WRITE भेजकर दिखाता है।
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

  • Example: 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) size > KMALLOC_MAX_CACHE_SIZE होने पर buddy allocator से order-4 (16 contiguous pages) allocation request करता है। यह SLUB cache object नहीं है।
  • memcpy allocation के तुरंत बाद होता है; post-allocation spraying अप्रभावी है। आपको पहले से physical memory को groom करना होगा ताकि कोई चुना हुआ target allocated 16-page block के तुरंत बाद स्थित हो।
  • Ubuntu पर, GFP_KERNEL अक्सर zone Normal में Unmovable migrate type से pull करता है। order-3 और order-4 freelists को exhaust करें ताकि allocator order-5 block को split करके adjacent order-4 + order-3 pair बनाए, फिर एक order-3 slab (kmalloc-cg-4k) को stream buffer के ठीक बाद park करें।

Practical page shaping strategy

  • लगभग 1000–2000 msg_msg objects of ~4096 bytes (fits kmalloc-cg-4k) spray करें ताकि order-3 slabs populate हों।
  • कुछ messages receive करें ताकि holes बनें और adjacency encourage हो।
  • ksmbd OOB को बार-बार trigger करें जब तक order-4 stream buffer किसी msg_msg slab के ठीक पहले land न करे। यदि available हो, तो addresses और alignment confirm करने के लिए 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

ट्यूनिंग करते समय क्या ट्रेस करें

  • kvmalloc_node(0x10000) तब पुष्टि करता है जब vulnerable stream write वास्तव में order-4 allocation को consume करता है।
  • load_msg/kretprobe:load_msg आपको यह अनुमान लगाने देता है कि हर sprayed message से कितने msg_msgseg allocations जुड़े हैं, जो किसी specific kernel build के लिए primary/secondary message sizes ट्यून करते समय उपयोगी है।
  • अगर exploit को किसी अलग distro/kernel पर port किया जाता है, तो Ubuntu 22.04 LTS 5.15.0-153-generic constants अभी भी match करते हैं, ऐसा मानने के बजाय cache names, inline msg_msg payload sizes, anon_pipe_buf_ops offsets, और gadget addresses फिर से check करें।

Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555

  1. बहुत सारे System V msg_msg primary/secondary messages spray करें (kmalloc-cg-4k में fit होने के लिए 4KiB-sized)।
  2. ksmbd OOB trigger करके primary message के next pointer को corrupt करें ताकि दो primaries एक secondary share करें।
  3. queues को tag करके और msgrcv(MSG_COPY) से scan करके corrupted pair detect करें ताकि mismatched tags मिलें।
  4. real secondary को free करके UAF बनाएं; controlled data के साथ UNIX sockets के जरिए इसे reclaim करें (एक fake msg_msg craft करें)।
  5. copy_msg में m_ts over-read का abuse करके kernel heap pointers leak करें ताकि mlist.next/mlist.prev मिलें (SMAP bypass)।
  6. एक sk_buff spray के साथ, valid links वाला consistent fake msg_msg फिर से बनाएं और state को stabilize करने के लिए इसे normally free करें।
  7. struct pipe_buffer objects के साथ UAF reclaim करें; kernel base compute करने के लिए anon_pipe_buf_ops leak करें (KASLR defeat)।
  8. release को stack pivot/ROP gadget की ओर point करने वाले fake pipe_buf_operations spray करें; execute करके root पाने के लिए pipes close करें।

Bypasses and notes

  • KASLR: anon_pipe_buf_ops leak करें, base (kbase_addr) और gadget addresses compute करें।
  • SMEP/SMAP: pipe_buf_operations->release flow के जरिए kernel context में ROP execute करें; disable/prepare_kernel_cred/commit_creds chain के बाद तक userspace derefs से बचें।
  • Hardened usercopy: यह page overflow primitive पर लागू नहीं होता; corruption targets non-usercopy fields हैं।

Reliability

  • adjacency achieve होने के बाद high; occasional misses या panics (<10%)। spray/free counts ट्यून करने से stability improve होती है। specific collisions induce करने के लिए pointer के दो LSBs overwrite करना effective बताया गया है (जैसे overlap में 0x0000_0000_0000_0500 pattern write करना)।

Key parameters to tune

  • msg_msg sprays की संख्या और hole pattern
  • OOB offset (pos) और resulting OOB length (count')
  • हर stage के दौरान UNIX socket, sk_buff, और pipe_buffer sprays की संख्या

Mitigations and reachability

  • Fix: allocation और destination/length दोनों clamp करें या allocated size के खिलाफ memcpy को bound करें; upstream patches इसे CVE-2025-37947 के रूप में track करते हैं।
  • Remote exploitation के लिए additionally एक reliable infoleak और remote heap grooming की आवश्यकता होगी; यह write-up local LPE पर focus करता है।

See also

Ksmbd Attack Surface And Fuzzing Syzkaller

References PoC and tooling

  • SMB auth और streams writes के लिए libsmb2
  • kvmalloc addresses log करने और allocations histogram करने के लिए eBPF tracer script (e.g., grep 4048 out-4096.txt)
  • Minimal reachability PoC और full local exploit publicly available हैं (see 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) assessment tracks (ARTA/GRTA/AzRTA) और Linux Hacking Expert (LHE) के लिए full HackTricks Training catalog ब्राउज़ करें।

HackTricks का समर्थन करें