ksmbd Surface d'attaque & SMB2/SMB3 Protocol Fuzzing (syzkaller)

Reading time: 9 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Aperçu

Cette page synthétise des techniques pratiques pour exercer et fuzz le serveur SMB en-kernel Linux (ksmbd) en utilisant syzkaller. Elle se concentre sur l'expansion de la surface d'attaque du protocole via la configuration, la construction d'un harnais stateful capable d'enchaßner des opérations SMB2, la génération de PDUs valides grammaticalement, le biaisage des mutations vers des chemins de code faiblement couverts, et l'exploitation des fonctionnalités de syzkaller telles que focus_areas et ANYBLOB. Alors que la recherche originale énumÚre des CVE spécifiques, ici nous mettons l'accent sur la méthodologie réutilisable et des extraits concrets que vous pouvez adapter à vos propres environnements.

Portée cible : SMB2/SMB3 over TCP. Kerberos et RDMA sont volontairement hors-scope pour garder le harnais simple.


Étendre la surface d'attaque de ksmbd via la configuration

Par défaut, une configuration ksmbd minimale laisse de larges parties du serveur non testées. Activez les fonctionnalités suivantes pour pousser le serveur à travers des parseurs/handlers supplémentaires et atteindre des chemins de code plus profonds :

  • Global-level
  • Durable handles
  • Server multi-channel
  • SMB2 leases
  • Per-share-level
  • Oplocks (activĂ©s par dĂ©faut)
  • VFS objects

L'activation de ces éléments augmente l'exécution dans des modules tels que :

  • smb2pdu.c (parsing/dispatch des commandes)
  • ndr.c (encodage/dĂ©codage NDR)
  • oplock.c (demande/rupture d'oplock)
  • smbacl.c (parsing/renforcement des ACL)
  • vfs.c (opĂ©rations VFS)
  • vfs_cache.c (cache de lookup)

Notes

  • Les options exactes dĂ©pendent des userspace ksmbd de votre distro (ksmbd-tools). Consultez /etc/ksmbd/ksmbd.conf et les sections par-partage pour activer durable handles, leases, oplocks et VFS objects.
  • Multi-channel et durable handles modifient les machines d'Ă©tat et les durĂ©es de vie, rĂ©vĂ©lant souvent des bugs UAF/refcount/OOB sous concurrence.

Authentification et ajustements de rate-limiting pour le Fuzzing

SMB3 nécessite une session valide. Implémenter Kerberos dans les harnais ajoute de la complexité, donc préférez NTLM/guest pour le fuzzing :

  • Autorisez l'accĂšs guest et dĂ©finissez map to guest = bad user afin que les utilisateurs inconnus retombent sur GUEST.
  • Acceptez NTLMv2 (patcher la policy si dĂ©sactivĂ©e). Cela maintient la poignĂ©e de main simple tout en exerçant les chemins de code SMB3.
  • Patcherez les contrĂŽles stricts de credits lors des expĂ©rimentations (le durcissement postĂ©rieur pour CVE-2024-50285 a rendu le crĂ©dit pour opĂ©rations simultanĂ©es plus strict). Sinon, les rate-limits peuvent rejeter des sĂ©quences fuzzĂ©es trop tĂŽt.
  • Augmentez le max connections (p. ex. Ă  65536) pour Ă©viter des rejets prĂ©coces lors d'un fuzzing Ă  haut dĂ©bit.

Attention : Ces relaxations servent uniquement à faciliter le fuzzing. Ne pas déployer ces réglages en production.


Harnais Ă  Ă©tats : Extraire des ressources et enchaĂźner des requĂȘtes

SMB est stateful : beaucoup de requĂȘtes dĂ©pendent d'identifiants retournĂ©s par des rĂ©ponses prĂ©cĂ©dentes (SessionId, TreeID, paires FileID). Votre harnais doit parser les rĂ©ponses et rĂ©utiliser les IDs dans le mĂȘme programme pour atteindre des handlers profonds (p. ex., smb2_create → smb2_ioctl → smb2_close).

Exemple d'extrait pour traiter un buffer de réponse (en sautant les +4B de longueur NetBIOS PDU) et mettre en cache les IDs :

c
// process response. does not contain +4B PDU length
void process_buffer(int msg_no, const char *buffer, size_t received) {
uint16_t cmd_rsp = u16((const uint8_t *)(buffer + CMD_OFFSET));
switch (cmd_rsp) {
case SMB2_TREE_CONNECT:
if (received >= TREE_ID_OFFSET + sizeof(uint32_t))
tree_id = u32((const uint8_t *)(buffer + TREE_ID_OFFSET));
break;
case SMB2_SESS_SETUP:
// first session setup response carries session_id
if (msg_no == 0x01 && received >= SESSION_ID_OFFSET + sizeof(uint64_t))
session_id = u64((const uint8_t *)(buffer + SESSION_ID_OFFSET));
break;
case SMB2_CREATE:
if (received >= CREATE_VFID_OFFSET + sizeof(uint64_t)) {
persistent_file_id = u64((const uint8_t *)(buffer + CREATE_PFID_OFFSET));
volatile_file_id   = u64((const uint8_t *)(buffer + CREATE_VFID_OFFSET));
}
break;
default:
break;
}
}

Conseils

  • Gardez un seul processus fuzzer partageant l'authentification/Ă©tat : meilleure stabilitĂ© et couverture avec les tables globales/session de ksmbd. syzkaller injecte nĂ©anmoins de la concurrence en marquant les ops comme async, rĂ©exĂ©cution en interne.
  • L'option expĂ©rimentale reset_acc_state de syzkaller peut rĂ©initialiser l'Ă©tat global mais introduit un ralentissement important. PrivilĂ©giez la stabilitĂ© et concentrez-vous sur le fuzzing.

Génération SMB2 pilotée par une grammaire (PDUs valides)

Traduisez les structures SMB2 des Microsoft Open Specifications en une grammaire pour fuzzer afin que votre générateur produise des PDUs structurellement valides, qui atteignent systématiquement les dispatchers et les IOCTL handlers.

Exemple (SMB2 IOCTL request):

smb2_ioctl_req {
Header_Prefix           SMB2Header_Prefix
Command                 const[0xb, int16]
Header_Suffix           SMB2Header_Suffix
StructureSize           const[57, int16]
Reserved                const[0, int16]
CtlCode                 union_control_codes
PersistentFileId        const[0x4, int64]
VolatileFileId          const[0x0, int64]
InputOffset             offsetof[Input, int32]
InputCount              bytesize[Input, int32]
MaxInputResponse        const[65536, int32]
OutputOffset            offsetof[Output, int32]
OutputCount             len[Output, int32]
MaxOutputResponse       const[65536, int32]
Flags                   int32[0:1]
Reserved2               const[0, int32]
Input                   array[int8]
Output                  array[int8]
} [packed]

Ce style force des tailles/décalages de structure corrects et améliore considérablement la couverture par rapport à la mutation aveugle.


Fuzzing dirigé avec focus_areas

Utilisez syzkaller’s experimental focus_areas pour surpondĂ©rer des fonctions/fichiers spĂ©cifiques qui ont actuellement une faible couverture. Exemple JSON:

json
{
"focus_areas": [
{"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0},
{"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0},
{"weight": 1.0}
]
}

Ceci aide à construire des ACLs valides qui atteignent les chemins arithmetic/overflow dans smbacl.c. Par exemple, un Security Descriptor malveillant avec un dacloffset surdimensionné reproduit un integer-overflow.

Script de reproduction (Python minimal):

python
def build_sd():
import struct
sd = bytearray(0x14)
sd[0x00] = 0x00; sd[0x01] = 0x00
struct.pack_into('<H', sd, 0x02, 0x0001)
struct.pack_into('<I', sd, 0x04, 0x78)
struct.pack_into('<I', sd, 0x08, 0x00)
struct.pack_into('<I', sd, 0x0C, 0x10000)
struct.pack_into('<I', sd, 0x10, 0xFFFFFFFF)  # dacloffset
while len(sd) < 0x78:
sd += b'A'
sd += b"\x01\x01\x00\x00\x00\x00\x00\x00"  # minimal DACL
sd += b"\xCC" * 64
return bytes(sd)

Briser les plateaux de coverage avec ANYBLOB

Les anyTypes de syzkaller (ANYBLOB/ANYRES) permettent de réduire des structures complexes en blobs qui mutent de façon générique. Générez un nouveau corpus à partir de pcaps SMB publics et convertissez les payloads en programmes syzkaller appelant votre pseudo-syscall (e.g., syz_ksmbd_send_req):

bash
# Extract SMB payloads to JSON
# tshark -r smb2_dac_sample.pcap -Y "smb || smb2" -T json -e tcp.payload > packets.json
python
import json, os
os.makedirs("corpus", exist_ok=True)

with open("packets.json") as f:
data = json.load(f)
# adjust indexing to your tshark JSON structure
packets = [e["_source"]["layers"]["tcp.payload"] for e in data]

for i, pkt in enumerate(packets):
pdu = pkt[0]
pdu_size = len(pdu) // 2  # hex string length → bytes
with open(f"corpus/packet_{i:03d}.txt", "w") as f:
f.write(
f"syz_ksmbd_send_req(&(&(0x7f0000000340))=ANY=[@ANYBLOB=\"{pdu}\"], {hex(pdu_size)}, 0x0, 0x0)"
)

Cela lance l'exploration et peut immédiatement déclencher des UAFs (p. ex., dans ksmbd_sessions_deregister) tout en augmentant la couverture de quelques pourcents.


Sanitizers : Au-delĂ  de KASAN

  • KASAN reste le principal dĂ©tecteur pour les bogues de heap (UAF/OOB).
  • KCSAN produit souvent des faux positifs ou des data races de faible gravitĂ© sur cette cible.
  • UBSAN/KUBSAN peut dĂ©tecter des erreurs de bornes dĂ©clarĂ©es que KASAN manque Ă  cause de la sĂ©mantique des indices de tableau. Exemple:
c
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
struct smb_sid {
__u8 revision; __u8 num_subauth; __u8 authority[NUM_AUTHS];
__le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
} __attribute__((packed));

Définir num_subauth = 0 déclenche une lecture in-struct OOB de sub_auth[-1], détectée par les declared-bounds checks d'UBSAN.


Notes sur le débit et le parallélisme

  • Un seul processus fuzzer (auth/state partagĂ©) a tendance Ă  ĂȘtre significativement plus stable pour ksmbd et met nĂ©anmoins au jour des races/UAFs grĂące Ă  l'async executor interne de syzkaller.
  • Avec plusieurs VM, vous pouvez toujours atteindre des centaines de commandes SMB par seconde au total. Une couverture au niveau fonction d'environ ~60% de fs/smb/server et ~70% de smb2pdu.c est atteignable, bien que la couverture des transitions d'Ă©tat soit sous-reprĂ©sentĂ©e par de tels mĂ©triques.

Checklist pratique

  • Activez durable handles, leases, multi-channel, oplocks et VFS objects dans ksmbd.
  • Autorisez guest et map-to-guest ; acceptez NTLMv2. Éliminez les credit limits et augmentez le max connections pour la stabilitĂ© du fuzzer.
  • Construisez un stateful harness qui met en cache SessionId/TreeID/FileIDs et enchaĂźne create → ioctl → close.
  • Utilisez une grammar pour SMB2 PDUs afin de maintenir la validitĂ© structurelle.
  • Utilisez focus_areas pour surpondĂ©rer les fonctions faiblement couvertes (par ex., chemins de smbacl.c comme smb_check_perm_dacl).
  • Grainez avec ANYBLOB tirĂ© de pcaps rĂ©els pour franchir les plateaux ; packez les seeds avec syz-db pour rĂ©utilisation.
  • ExĂ©cutez avec KASAN + UBSAN ; triez soigneusement les rapports declared-bounds d'UBSAN.

Références

  • Doyensec – ksmbd Fuzzing (Part 2): https://blog.doyensec.com/2025/09/02/ksmbd-2.html
  • syzkaller: https://github.com/google/syzkaller
  • ANYBLOB/anyTypes (commit 9fe8aa4): https://github.com/google/syzkaller/commit/9fe8aa4
  • Async executor change (commit fd8caa5): https://github.com/google/syzkaller/commit/fd8caa5
  • syz-db: https://github.com/google/syzkaller/tree/master/tools/syz-db
  • KASAN: https://docs.kernel.org/dev-tools/kasan.html
  • UBSAN/KUBSAN: https://docs.kernel.org/dev-tools/ubsan.html
  • KCSAN: https://docs.kernel.org/dev-tools/kcsan.html
  • Microsoft Open Specifications (SMB): https://learn.microsoft.com/openspecs/
  • Wireshark Sample Captures: https://wiki.wireshark.org/SampleCaptures
  • Lecture de fond: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; notes syzkaller de Dongliang Mu

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks