ksmbd streams_xattr OOB write → local LPE (CVE-2025-37947)
Tip
Apprenez et pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Parcourez le catalogue complet de HackTricks Training pour les parcours d’évaluation (ARTA/GRTA/AzRTA) et Linux Hacking Expert (LHE).
Support HackTricks
- Consultez les subscription plans!
- Rejoignez 💬 le groupe Discord, le groupe telegram, suivez @hacktricks_live sur X/Twitter, ou consultez la page LinkedIn et la chaîne YouTube.
- Partagez des hacking tricks en soumettant des PRs aux dépôts github HackTricks et HackTricks Cloud.
Cette page documente une écriture hors limites déterministe dans la gestion des streams de ksmbd, qui permet une élévation de privilèges fiable dans le kernel Linux sur Ubuntu 22.04 LTS (5.15.0-153-generic), en contournant KASLR, SMEP et SMAP à l’aide de primitives standard du kernel heap (msg_msg + pipe_buffer).
- Composant affecté: fs/ksmbd/vfs.c — ksmbd_vfs_stream_write()
- Primitive: page-overflow OOB write au-delà d’un buffer kvmalloc() de 0x10000 octets
- Préconditions: ksmbd en cours d’exécution avec un share authentifié et inscriptible utilisant vfs streams_xattr
Exemple smb.conf
[share]
path = /share
vfs objects = streams_xattr
writeable = yes
Cause racine (allocation clamped, memcpy à un offset non clamped)
- La fonction calcule size = *pos + count, clamp size à XATTR_SIZE_MAX (0x10000) quand il est dépassé, et recalcule count = (*pos + count) - 0x10000, mais effectue quand même memcpy(&stream_buf[*pos], buf, count) dans un buffer de 0x10000 bytes. Si *pos ≥ 0x10000, le pointeur de destination est déjà en dehors de l’allocation, ce qui produit un OOB write de count bytes.
streams_xattrstocke les SMB alternate data streams à l’intérieur des POSIX extended attributes, donc le plafond de 0x10000 vient de la limite de taille d’un seul xattr Linux plutôt que d’un champ du protocole SMB. Cela rend le bug pratique uniquement lorsque le partage active explicitementvfs objects = streams_xattret que le filesystem supporte les xattrs.
Pourquoi l’offset d’écriture compte
- Le chemin vulnérable n’est pas juste “write plus de 64KiB”. La vérification manquante était que
*posn’était pas validé par rapport à la longueur actuelle du stream (v_len) avant l’exécution de la logique d’ajout/copie. - Upstream a corrigé cela en rejetant les writes où
*pos >= v_lenavec-EINVAL. Avant le fix, un attaquant pouvait réutiliser un handle authentifié valide vers un named stream et envoyer un SMB2 WRITE brut dontfile_offsetpointe déjà à la fin ou au-delà du stream existant, ce qui transforme lememcpy()après clamp en un overflow de page déterministe. - Le PoC public le démontre en s’authentifiant avec
libsmb2, en ouvrant un chemin de stream comme1337:, en extrayantSessionId/TreeId/FileId, puis en envoyant un SMB2 WRITE forgé avecfile_offset = 0x10018et unLengthfaible.
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
- Exemple : définissez le file offset (pos) à 0x10018 et la longueur d’origine (count) à 8. Après le clamping, count’ = (0x10018 + 8) - 0x10000 = 0x20, mais memcpy écrit 32 bytes à partir de stream_buf[0x10018], soit 0x18 bytes au-delà de l’allocation de 16 pages.
Triggering the bug via SMB streams write
- Utilisez la même connexion SMB authentifiée pour ouvrir un fichier sur le share et envoyer un write vers un named stream (streams_xattr). Définissez file_offset ≥ 0x10000 avec une petite longueur pour générer un OOB write déterministe d’une taille contrôlable.
- libsmb2 peut être utilisé pour s’authentifier et construire ce type de writes via SMB2/3.
- En pratique, réutiliser la session SMB négociée est pratique car l’exploit n’a besoin que de patcher quelques champs dynamiques dans la requête WRITE (
TreeId,SessionId,FileId) puis peut transmettre directement le paquet malformé sur le même 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
Comportement de l’allocator et pourquoi le page shaping est requis
- kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO) demande une allocation order-4 (16 pages contiguës) au buddy allocator lorsque size > KMALLOC_MAX_CACHE_SIZE. Ce n’est pas un objet de cache SLUB.
- memcpy se produit immédiatement après l’allocation ; le spraying post-allocation est inefficace. Vous devez pré-groom la mémoire physique afin qu’une cible choisie se trouve immédiatement après le bloc alloué de 16 pages.
- Sur Ubuntu, GFP_KERNEL puise souvent dans le type de migration Unmovable dans la zone Normal. Épuisez les freelists order-3 et order-4 pour forcer l’allocator à scinder un bloc order-5 en une paire adjacente order-4 + order-3, puis placez un slab order-3 (kmalloc-cg-4k) directement après le stream buffer.
Stratégie pratique de page shaping
- Spray ~1000–2000 objets msg_msg d’environ 4096 bytes (compatible kmalloc-cg-4k) pour remplir les slabs order-3.
- Recevez certains messages pour créer des trous et favoriser l’adjacence.
- Déclenchez le ksmbd OOB à plusieurs reprises jusqu’à ce que le stream buffer order-4 se place immédiatement avant un slab msg_msg. Utilisez le tracing eBPF pour confirmer les addresses et l’alignement si disponible.
Observabilité utile
# 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
Ce qu’il faut tracer pendant le tuning
kvmalloc_node(0x10000)confirme quand l’écriture de stream vulnérable consomme réellement une allocation d’ordre 4.load_msg/kretprobe:load_msgte permet d’estimer combien d’allocationsmsg_msgsegsont attachées à chaque message sprayé, ce qui est utile lors du tuning des tailles de messages primary/secondary pour un build kernel spécifique.- Si l’exploit est porté sur une autre distro/kernel, revérifie les noms de cache, les tailles de payload
msg_msginline, les offsetsanon_pipe_buf_ops, et les adresses des gadgets plutôt que de supposer que les constantes Ubuntu 22.04 LTS5.15.0-153-genericcorrespondent toujours.
Plan d’exploitation (msg_msg + pipe_buffer), adapté de CVE-2021-22555
- Spray beaucoup de messages System V
msg_msgprimary/secondary (taille 4KiB pour tenir danskmalloc-cg-4k). - Déclenche le OOB de ksmbd pour corrompre le pointeur
nextd’un message primary afin que deux primaries partagent un secondary. - Détecte la paire corrompue en taguant les files d’attente et en scannant avec
msgrcv(MSG_COPY)pour trouver des tags incohérents. - Libère le vrai secondary pour créer un UAF ; reprends-le avec des données contrôlées via des sockets UNIX (forge un faux
msg_msg). - Leak des pointeurs du kernel heap en abusant du m_ts over-read dans
copy_msgpour obtenirmlist.next/mlist.prev(SMAP bypass). - Avec un spray
sk_buff, reconstruis un fauxmsg_msgcohérent avec des liens valides et libère-le normalement pour stabiliser l’état. - Reprends le UAF avec des objets
struct pipe_buffer; leakanon_pipe_buf_opspour calculer la kernel base (bypass KASLR). - Spray un faux
pipe_buf_operationsavecreleasepointant vers un stack pivot/ROP gadget ; ferme les pipes pour exécuter et obtenir root.
Bypasses et notes
- KASLR : leak
anon_pipe_buf_ops, calcule la base (kbase_addr) et les adresses des gadgets. - SMEP/SMAP : exécute la ROP dans le contexte kernel via le flux
pipe_buf_operations->release; évite les derefs userspace jusqu’après la chaînedisable/prepare_kernel_cred/commit_creds. - Hardened usercopy : non applicable à ce primitive d’overflow de page ; les cibles de corruption sont des champs non-usercopy.
Fiabilité
- Élevée une fois l’adjacence obtenue ; quelques ratés ou panic occasionnels (<10%). Ajuster les comptes de spray/free améliore la stabilité. L’écrasement des deux bits de poids faible d’un pointeur pour induire des collisions spécifiques a été rapporté comme efficace (par ex. écrire le pattern
0x0000_0000_0000_0500dans l’overlap).
Paramètres clés à ajuster
- Nombre de sprays
msg_msget pattern des trous - Offset OOB (
pos) et longueur OOB résultante (count') - Nombre de sprays de sockets UNIX,
sk_buffetpipe_bufferpendant chaque étape
Mitigations et accessibilité
- Correctif : borner à la fois l’allocation et la destination/la longueur, ou limiter
memcpyà la taille allouée ; les patches upstream suivent cela sous CVE-2025-37947. - Une exploitation distante nécessiterait en plus un infoleak fiable et un grooming distant du heap ; ce texte se concentre sur le LPE local.
Voir aussi
Ksmbd Attack Surface And Fuzzing Syzkaller
Références PoC et tooling
- libsmb2 pour l’auth SMB et les écritures de streams
- Script traceur eBPF pour logger les adresses
kvmallocet faire un histogramme des allocations (par ex.grep 4048 out-4096.txt) - Un PoC minimal de reachability et un exploit local complet sont publiquement disponibles (voir References)
References
- ksmbd - Exploiting CVE-2025-37947 (3/3) — Doyensec
- Linux upstream fix:
ksmbd: prevent out-of-bounds stream writes by validating *pos - KSMBD-CVE-2025-37947 PoC repository
Tip
Apprenez et pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Parcourez le catalogue complet de HackTricks Training pour les parcours d’évaluation (ARTA/GRTA/AzRTA) et Linux Hacking Expert (LHE).
Support HackTricks
- Consultez les subscription plans!
- Rejoignez 💬 le groupe Discord, le groupe telegram, suivez @hacktricks_live sur X/Twitter, ou consultez la page LinkedIn et la chaîne YouTube.
- Partagez des hacking tricks en soumettant des PRs aux dépôts github HackTricks et HackTricks Cloud.


