# ksmbd Površina napada i fuzzing SMB2/SMB3 protokola (syzkaller) {{#include ../../banners/hacktricks-training.md}} ## Pregled Ova stranica apstrahuje praktične tehnike za vežbanje i fuzzing Linux in-kernel SMB servera (ksmbd) koristeći syzkaller. Fokus je na proširenju attack surface protokola kroz konfiguraciju, izgradnji stateful harness-a sposobnog da lančano izvodi SMB2 operacije, generisanju PDUs validnih prema gramatici, usmeravanju mutacija ka slabo pokrivenim kodnim putevima i iskorišćavanju syzkaller funkcija kao što su focus_areas i ANYBLOB. Dok originalno istraživanje navodi specifične CVE-ove, ovde naglašavamo ponovljivo metodološko pristupanje i konkretne snippete koje možete prilagoditi sopstvenim setup-ovima. Ciljni obuhvat: SMB2/SMB3 preko TCP-a. Kerberos i RDMA su namerno van obuhvata da bi harness ostao jednostavan. --- ## Proširenje ksmbd površine napada kroz konfiguraciju Po defaultu, minimalan ksmbd setup ostavlja velike delove servera netestiranim. Omogućite sledeće funkcije da biste naterali server kroz dodatne parsere/handlere i dohvatili dublje kodne puteve: - Global-level - Durable handles - Server multi-channel - SMB2 leases - Per-share-level - Oplocks (uključen po defaultu) - VFS objects Omogućavanje ovih opcija povećava izvršavanje u modulima kao što su: - smb2pdu.c (command parsing/dispatch) - ndr.c (NDR encode/decode) - oplock.c (oplock request/break) - smbacl.c (ACL parsing/enforcement) - vfs.c (VFS ops) - vfs_cache.c (lookup cache) Napomene - Tačne opcije zavise od vašeg distro-ovog ksmbd userspace-a (ksmbd-tools). Pregledajte /etc/ksmbd/ksmbd.conf i per-share sekcije da omogućite durable handles, leases, oplocks i VFS objects. - Multi-channel i durable handles menjaju state machine i lifetime, često eksponirajući UAF/refcount/OOB bagove pod konkurentnošću. --- ## Podešavanja autentifikacije i rate-limiting za fuzzing SMB3 zahteva validnu sesiju. Implementacija Kerberos-a u harness-evima dodaje kompleksnost, pa se za fuzzing radije koristi NTLM/guest: - Dozvolite guest pristup i podesite map to guest = bad user tako da nepoznati korisnici padaju na GUEST. - Prihvatite NTLMv2 (patch-ujte politiku ako je onemogućen). Ovo pojednostavljuje handshake dok i dalje aktivira SMB3 kodne puteve. - Patch-ujte stroge credit checks tokom eksperimentisanja (post-hardening za CVE-2024-50285 je strožije regulisao simultaneous-op crediting). Inače, rate-limiti mogu odbacivati fuzzovane sekvence prerano. - Povećajte max connections (npr. na 65536) da izbegnete rane odbacivanja pri visokoprotočnom fuzzingu. Upozorenje: Ova opuštanja služe isključivo za potrebe fuzzinga. Ne deploy-ujte sa ovim podešavanjima u produkciji. --- ## Stateful harness: Ekstrakcija resursa i lančanje zahteva SMB je stateful: mnogi zahtevi zavise od identifikatora vraćenih prethodnim odgovorima (SessionId, TreeID, FileID parovi). Vaš harness mora parsirati odgovore i ponovo koristiti ID-ove unutar istog programa da bi dosegao dublje handlere (npr. smb2_create → smb2_ioctl → smb2_close). Primer snippeta za obradu response buffera (preskačući +4B NetBIOS PDU length) i keširanje ID-ova: ```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; } } ``` Saveti - Zadržite jedan fuzzer process koji deli authentication/state: pruža bolju stabilnost i pokrivenost sa ksmbd’s global/session tables. syzkaller i dalje uvodi concurrency tako što označava ops kao async i interno ih ponovo pokreće. - Syzkaller’s experimental reset_acc_state može resetovati global state, ali može uvesti značajno usporenje. Prioritet dajte stabilnosti i fokusirajte se na fuzzing umesto toga. --- ## Generisanje SMB2 vođeno gramatikom (validni PDUs) Prevedite Microsoft Open Specifications SMB2 strukture u fuzzer grammar tako da vaš generator proizvodi strukturno validne PDUs koje sistematski dopiru do dispatchers i IOCTL handlers. Primer (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] ``` Ovaj stil prisiljava na ispravne structure sizes/offsets i drastično poboljšava coverage u odnosu na blind mutation. --- ## Directed Fuzzing With focus_areas Koristite syzkaller’s experimental focus_areas da date veću težinu određenim functions/files koje trenutno imaju slab coverage. Example JSON: ```json { "focus_areas": [ {"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0}, {"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0}, {"weight": 1.0} ] } ``` Ovo pomaže da se konstruišu validni ACLs koji pogađaju arithmetic/overflow puteve u smbacl.c. Na primer, zlonamerni Security Descriptor sa prevelikim dacloffset reprodukuje integer-overflow. Generator reprodukcije (minimalni Python): ```python def build_sd(): import struct sd = bytearray(0x14) sd[0x00] = 0x00; sd[0x01] = 0x00 struct.pack_into(' 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)" ) ``` Ovo ubrzava istraživanje i može odmah izazvati UAFs (npr. u ksmbd_sessions_deregister) dok podiže coverage za nekoliko procenata. --- ## Sanitizers: Više od KASAN - KASAN ostaje primarni detektor za heap bugs (UAF/OOB). - KCSAN često daje false positives ili low-severity data races na ovom targetu. - UBSAN/KUBSAN može uhvatiti declared-bounds greške koje KASAN promaši zbog array-index semantics. Primer: ```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)); ``` Postavljanje num_subauth = 0 izaziva in-struct OOB čitanje sub_auth[-1], koje detektuju UBSAN-ove provere deklarisanih granica. --- ## Napomene o propusnosti i paralelizmu - Jedan fuzzer proces (shared auth/state) obično je znatno stabilniji za ksmbd i i dalje otkriva races/UAFs zahvaljujući syzkaller’s internal async executor. - Sa višestrukim VM-ovima, i dalje možete dostići stotine SMB komandi/sekundi ukupno. Pokrivenost na nivou funkcija oko ~60% za fs/smb/server i ~70% za smb2pdu.c je ostvariva, mada je pokrivenost prelaza stanja potcenjena ovakvim metrikama. --- ## Praktični kontrolni spisak - Omogućite durable handles, leases, multi-channel, oplocks i VFS objects u ksmbd. - Allow guest i map-to-guest; accept NTLMv2. Patch out credit limits i povećajte max connections radi stabilnosti fuzzera. - Napravite stateful harness koji kešira SessionId/TreeID/FileIDs i povezuje create → ioctl → close. - Koristite grammar za SMB2 PDUs da održite strukturnu validnost. - Koristite focus_areas da preterano opteretite slabo pokrivene funkcije (npr. smbacl.c putanje kao smb_check_perm_dacl). - Seedujte sa ANYBLOB iz stvarnih pcaps da probijete platea; pakujte seed-ove sa syz-db za ponovnu upotrebu. - Pokrenite sa KASAN + UBSAN; pažljivo razvrstajte UBSAN izveštaje o declared-bounds. --- ## Reference - 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 - Background reading: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mu’s syzkaller notes {{#include ../../banners/hacktricks-training.md}}