10 KiB
ksmbd Attack Surface & SMB2/SMB3 Protocol Fuzzing (syzkaller)
{{#include ../../banners/hacktricks-training.md}}
Pregled
Ova stranica sažima praktične tehnike za vežbanje i fuzzing Linux in-kernel SMB servera (ksmbd) koristeći syzkaller. Fokusira se na proširenje attack surface-a protokola kroz konfiguraciju, izgradnju stateful harness-a sposobnog da poveže SMB2 operacije, generisanje grammar-valid PDUs, usmeravanje mutacija ka slabo pokrivenim kodnim putevima i korišćenje syzkaller funkcija kao što su focus_areas i ANYBLOB. Dok originalno istraživanje nabraja specifične CVE-e, ovde naglašavamo ponovljivo metodološko pristupanje i konkretne isječke koje možete prilagoditi sopstvenim okruženjima.
Target scope: SMB2/SMB3 over TCP. Kerberos i RDMA su namerno van opsega da bi harness ostao jednostavan.
Proširite ksmbd Attack Surface putem konfiguracije
Po defaultu, minimalna ksmbd konfiguracija ostavlja veliki deo servera netestiranim. Omogućite sledeće funkcije da biste naveli server da prolazi kroz dodatne parsere/handlere i doseže dublje kodne puteve:
- Global-level
- Durable handles
- Server multi-channel
- SMB2 leases
- Per-share-level
- Oplocks (on by default)
- 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 ksmbd userspace-a vaše distro-e (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-e i lifetim-e, često izlažući UAF/refcount/OOB bugove pod konkurentnošću.
Podešavanja autentikacije i rate-limiting za fuzzing
SMB3 zahteva validnu sesiju. Implementacija Kerberos-a u harness-evima dodaje kompleksnost, pa za fuzzing preferirajte NTLM/guest:
- Allow guest access i set map to guest = bad user tako da nepoznati korisnici padaju na GUEST.
- Accept NTLMv2 (patch policy ako je disabled). Ovo održava handshake jednostavnim dok se i dalje vežbaju SMB3 kodni putevi.
- Patch-ujte stroge kredit-provere dok eksperimentišete (post-hardening za CVE-2024-50285 je učinio simultaneous-op crediting strožijim). U suprotnom, rate-limiti mogu odbiti fuzzovane sekvence prerano.
- Povećajte max connections (npr. na 65536) da izbegnete rane odbijanja tokom visokopropusnog fuzzinga.
Upozorenje: Ova relaksiranja su isključivo radi olakšavanja fuzzinga. Ne koristite ovakva podešavanja u produkciji.
Stateful Harness: Ekstrahovanje resursa i povezivanje zahteva
SMB je stateful: mnogi zahtevi zavise od identifikatora vraćenih u prethodnim odgovorima (SessionId, TreeID, FileID parovi). Vaš harness mora parsirati odgovore i ponovo koristiti ID-e unutar istog programa da bi dostigao dublje handlere (npr. smb2_create → smb2_ioctl → smb2_close).
Primer isječka za obradu response buffer-a (preskačući +4B NetBIOS PDU length) i keširanje ID-eva:
// 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
- Koristite jedan fuzzer proces koji deli authentication/state: bolja stabilnost i pokrivenost sa ksmbd’s global/session tables. syzkaller i dalje ubrizgava konkurentnost označavanjem ops kao async, interno ponovo izvršava.
- Syzkaller’s experimental reset_acc_state može resetovati global state ali može uvesti značajno usporenje. Preferirajte stabilnost i fokusirajte se na fuzzing umesto toga.
Generisanje SMB2 vođeno gramatikom (ispravni PDU-i)
Prevedite Microsoft Open Specifications SMB2 strukture u fuzzer gramatiku tako da vaš generator proizvodi strukturalno ispravne PDU-e, koji sistematski stižu 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 osigurava ispravne veličine/offsete struktura i dramatično poboljšava coverage u odnosu na blind mutation.
Directed Fuzzing pomoću focus_areas
Koristite syzkaller’s eksperimentalni focus_areas da date veću težinu specifičnim funkcijama/datotekama koje trenutno imaju slabu coverage. Primer 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 u konstruisanju validnih ACL-ova koji pogode aritmetičke/overflow putanje u smbacl.c. Na primer, maliciozan Security Descriptor sa prevelikim dacloffset reprodukuje integer-overflow.
Reproducer builder (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)
Prevazilaženje platoa pokrivenosti uz ANYBLOB
syzkaller-ove anyTypes (ANYBLOB/ANYRES) omogućavaju sabijanje složenih struktura u blob-ove koji se generički mutiraju. Napravite novi korpus iz javnih SMB pcaps i konvertujte payloads u syzkaller programe koji pozivaju vaš pseudo-syscall (npr., syz_ksmbd_send_req):
# Extract SMB payloads to JSON
# tshark -r smb2_dac_sample.pcap -Y "smb || smb2" -T json -e tcp.payload > packets.json
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 početno istraživanje i može odmah da izazove UAFs (npr. u ksmbd_sessions_deregister), istovremeno povećavajući pokrivenost za nekoliko procenata.
Sanitizers: Iza KASAN
- KASAN ostaje primarni detektor za heap bugs (UAF/OOB).
- KCSAN često daje false positives ili data races niske ozbiljnosti u ovom targetu.
- UBSAN/KUBSAN može otkriti declared-bounds greške koje KASAN propušta zbog semantike array-index-a. Example:
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 pokreće in-struct OOB čitanje sub_auth[-1], koje je otkriveno UBSAN-ovim proverama deklarisanih granica.
Napomene o propusnosti i paralelizmu
- Jedan fuzzer proces (shared auth/state) obično je značajno stabilniji za ksmbd i i dalje izbacuje races/UAFs zahvaljujući syzkaller-ovom internal async executor-u.
- Sa više VM-ova i dalje možete pogoditi stotine SMB komandi/sekundi ukupno. Pokrivenost na nivou funkcija od oko ~60% za fs/smb/server i ~70% za smb2pdu.c je ostvariva, mada pokrivenost prelaza stanja nije adekvatno predstavljena takvim metrima.
Praktična kontrolna lista
- Omogućite durable handles, leases, multi-channel, oplocks i VFS objects u ksmbd.
- Dozvolite guest i map-to-guest; prihvatite NTLMv2. Patch-ujte credit limits i povećajte max connections radi stabilnosti fuzzer-a.
- 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 dodatno ponderišete slabo pokrivene funkcije (npr. smbacl.c putanje poput smb_check_perm_dacl).
- Seed-ujte sa ANYBLOB iz realnih pcaps da probijete plateaus; pakujte seed-ove sa syz-db za ponovnu upotrebu.
- Pokrenite sa KASAN + UBSAN; pažljivo triage-ujte UBSAN declared-bounds izveštaje.
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}}