ksmbd streams_xattr OOB write → local LPE (CVE-2025-37947)
Reading time: 7 minutes
tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
Esta página documenta um out-of-bounds write determinístico no tratamento de streams do ksmbd que permite uma escalada de privilégios confiável no kernel do Linux no Ubuntu 22.04 LTS (5.15.0-153-generic), contornando KASLR, SMEP e SMAP usando primitivas padrão do heap do kernel (msg_msg + pipe_buffer).
- Componente afetado: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
 - Primitiva: page-overflow OOB write past a 0x10000-byte kvmalloc() buffer
 - Pré-requisitos: ksmbd em execução com um compartilhamento autenticado e gravável usando vfs streams_xattr
 
Exemplo smb.conf
[share]
path = /share
vfs objects = streams_xattr
writeable = yes
Causa raiz (alocação limitada, memcpy em deslocamento não limitado)
- A função calcula size = *pos + count, limita size para XATTR_SIZE_MAX (0x10000) quando excede, e recalcula count = (*pos + count) - 0x10000, mas ainda assim executa memcpy(&stream_buf[*pos], buf, count) em um buffer de 0x10000 bytes. Se *pos ≥ 0x10000 o ponteiro de destino já está fora da alocação, produzindo um OOB write de count bytes.
 
Trecho da função vulnerável (ksmbd_vfs_stream_write)
// 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;
}
Direcionamento de offset e comprimento OOB
- Exemplo: definir o file offset (pos) para 0x10018 e o comprimento original (count) para 8. Após o clamping, count' = (0x10018 + 8) - 0x10000 = 0x20, mas memcpy escreve 32 bytes começando em stream_buf[0x10018], ou seja, 0x18 bytes além da alocação de 16 páginas.
 
Disparando o bug via SMB streams write
- Use a mesma conexão SMB autenticada para abrir um arquivo no share e emitir uma escrita para um stream nomeado (streams_xattr). Defina file_offset ≥ 0x10000 com um comprimento pequeno para gerar uma escrita OOB determinística de tamanho controlável.
 - libsmb2 pode ser usado para autenticar e construir essas escritas sobre SMB2/3.
 
Alcance mínimo (conceito)
// 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
Comportamento do allocator e por que page shaping é necessário
- kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO) requests an order-4 (16 contiguous pages) allocation from the buddy allocator when size > KMALLOC_MAX_CACHE_SIZE. Isso não é um objeto de cache SLUB.
 - memcpy ocorre imediatamente após a alocação; post-allocation spraying é ineficaz. Você deve pre-groom a memória física para que um alvo escolhido fique imediatamente após o bloco de 16 páginas alocado.
 - On Ubuntu, GFP_KERNEL often pulls from the Unmovable migrate type in zone Normal. Esgote os freelists order-3 e order-4 para forçar o allocator a dividir um bloco order-5 em um par adjacente order-4 + order-3, então posicione um order-3 slab (kmalloc-cg-4k) diretamente após o stream buffer.
 
Practical page shaping strategy
- Spray ~1000–2000 msg_msg objects de ~4096 bytes (fits kmalloc-cg-4k) para popular order-3 slabs.
 - Receba algumas mensagens para punch holes e encorajar adjacency.
 - Trigger o ksmbd OOB repetidamente até que o order-4 stream buffer fique imediatamente antes de um msg_msg slab. Use eBPF tracing para confirmar endereços e alinhamento, se disponível.
 
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
Plano de exploração (msg_msg + pipe_buffer), adaptado de CVE-2021-22555
- Spray de muitas mensagens System V msg_msg primárias/secundárias (tamanho 4KiB para caber em kmalloc-cg-4k).
 - Disparar OOB do ksmbd para corromper o ponteiro next de uma primary message de forma que duas primárias compartilhem uma secondary.
 - Detectar o par corrompido tagueando filas e escaneando com msgrcv(MSG_COPY) para encontrar tags que não batem.
 - Free da secondary real para criar um UAF; reclaim com dados controlados via UNIX sockets (construir um fake msg_msg).
 - Leak ponteiros do kernel heap abusando de over-read em m_ts dentro de copy_msg para obter mlist.next/mlist.prev (SMAP bypass).
 - Com um spray de sk_buff, reconstruir um fake msg_msg consistente com links válidos e freeá-lo normalmente para estabilizar o estado.
 - Reclaim do UAF com objetos struct pipe_buffer; leak anon_pipe_buf_ops para calcular kernel base (derrotar KASLR).
 - Spray de um fake pipe_buf_operations com release apontando para um stack pivot/gadget ROP; fechar pipes para executar e obter root.
 
Bypasses and notes
- KASLR: leak anon_pipe_buf_ops, compute base (kbase_addr) and gadget addresses.
 - SMEP/SMAP: execute ROP in kernel context via pipe_buf_operations->release flow; avoid userspace derefs until after disable/prepare_kernel_cred/commit_creds chain.
 - Hardened usercopy: not applicable to this page overflow primitive; corruption targets are non-usercopy fields.
 
Reliability
- Alta uma vez que a adjacência é obtida; falhas ocasionais ou panics (<10%). Ajustar counts de spray/free melhora a estabilidade. Sobrescrever dois LSBs de um ponteiro para induzir colisões específicas foi reportado como efetivo (por exemplo, escrever o padrão 0x0000_0000_0000_0500 no overlap).
 
Key parameters to tune
- Número de sprays de msg_msg e padrão de holes
 - OOB offset (pos) e OOB length resultante (count')
 - Número de sprays de UNIX socket, sk_buff e pipe_buffer em cada estágio
 
Mitigations and reachability
- Fix: clamp both allocation and destination/length or bound memcpy against the allocated size; upstream patches track as CVE-2025-37947.
 - Exploração remota exigiria adicionalmente um infoleak confiável e remote heap grooming; este write-up foca em LPE local.
 
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
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: 
HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure: 
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
 - Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
 - Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
 
HackTricks