ksmbd Angriffsfläche & SMB2/SMB3 Protokoll-Fuzzing (syzkaller)
Reading time: 8 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Überblick
Diese Seite fasst praktische Techniken zusammen, um den Linux In-Kernel SMB-Server (ksmbd) mit syzkaller zu exercisen und zu fuzzing. Der Fokus liegt auf der Erweiterung der Protokoll-Angriffsfläche über Konfiguration, dem Aufbau eines zustandsbehafteten Harness, das SMB2-Operationen verketten kann, der Generierung grammatikgültiger PDUs, dem Biasing von Mutationen in schwach abgedeckte Codepfade und der Nutzung von syzkaller-Features wie focus_areas und ANYBLOB. Während die ursprüngliche Forschung konkrete CVEs aufzählt, betonen wir hier die wiederverwendbare Methodik und konkrete Snippets, die Sie an Ihre eigenen Setups anpassen können.
Zielumfang: SMB2/SMB3 über TCP. Kerberos und RDMA sind bewusst außerhalb des Umfangs, um das Harness einfach zu halten.
Erweitern der ksmbd-Angriffsfläche über Konfiguration
Standardmäßig lässt ein minimales ksmbd-Setup große Teile des Servers ungetestet. Aktivieren Sie die folgenden Features, um den Server durch zusätzliche Parser/Handler zu treiben und tiefere Codepfade zu erreichen:
- Global-level
- Durable handles
- Server multi-channel
- SMB2 leases
- Per-share-level
- Oplocks (on by default)
- VFS objects
Das Aktivieren dieser Optionen erhöht die Ausführung in Modulen wie:
- 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)
Hinweise
- Die genauen Optionen hängen vom ksmbd Userspace Ihrer Distribution (ksmbd-tools) ab. Überprüfen Sie /etc/ksmbd/ksmbd.conf und die per-share Sektionen, um durable handles, leases, oplocks und VFS objects zu aktivieren.
- Multi-channel und durable handles ändern Zustandsmaschinen und Lebenszyklen und führen unter Concurrency häufig zu UAF/refcount/OOB-Bugs.
Authentifizierung und Rate-Limiting-Anpassungen für Fuzzing
SMB3 benötigt eine gültige Session. Die Implementierung von Kerberos im Harness erhöht die Komplexität, daher bevorzugen Sie für Fuzzing NTLM/guest:
- Allow guest access und setzen Sie map to guest = bad user, sodass unbekannte Benutzer auf GUEST zurückfallen.
- Accept NTLMv2 (patch policy falls deaktiviert). Das hält den Handshake einfach, während SMB3-Codepfade ausgeübt werden.
- Patchen Sie strikte Credit-Checks für Experimente heraus (post-hardening für CVE-2024-50285 machte simultaneous-op crediting strenger). Andernfalls können Rate-Limits fuzzed Sequenzen zu früh ablehnen.
- Erhöhen Sie max connections (z. B. auf 65536), um frühe Ablehnungen bei High-Throughput-Fuzzing zu vermeiden.
Warnung: Diese Lockerungen dienen ausschließlich dem Fuzzing. Setzen Sie diese Einstellungen nicht in Produktionsumgebungen ein.
Zustandsbehaftetes Harness: Ressourcen extrahieren und Requests verketten
SMB ist zustandsbehaftet: Viele Requests hängen von Bezeichnern ab, die in vorherigen Antworten zurückgegeben werden (SessionId, TreeID, FileID-Paare). Ihr Harness muss Antworten parsen und IDs innerhalb desselben Programms wiederverwenden, um zu tiefen Handlern zu gelangen (z. B. smb2_create → smb2_ioctl → smb2_close).
Beispiel-Snippet, um einen Response-Buffer zu verarbeiten (überspringt die +4B NetBIOS PDU-Länge) und IDs zu cachen:
// 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;
}
}
Tipps
- Behalte einen fuzzer-Prozess, der Authentifizierung/Zustand teilt: bessere Stabilität und Coverage mit ksmbd’s globalen/Sitzungstabellen. syzkaller injiziert weiterhin Concurrency, indem es ops als async markiert; rerun intern.
- Syzkaller’s experimentelles reset_acc_state kann den globalen Zustand zurücksetzen, kann aber starke Verlangsamungen verursachen. Bevorzuge Stabilität und fokussiere dich stattdessen auf fuzzing.
Grammatikgesteuerte SMB2-Erzeugung (gültige PDUs)
Übersetze die Microsoft Open Specifications SMB2-Strukturen in eine fuzzer-Grammatik, damit dein Generator strukturell gültige PDUs erzeugt, die systematisch Dispatcher und IOCTL-Handler erreichen.
Beispiel (SMB2 IOCTL-Anfrage):
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]
Dieser Stil erzwingt korrekte Strukturgrößen/-offsets und verbessert die Coverage dramatisch gegenüber blind mutation.
Directed Fuzzing With focus_areas
Verwende syzkaller’s experimental focus_areas, um bestimmte Funktionen/Dateien, die derzeit eine schwache Coverage aufweisen, stärker zu gewichten. Beispiel JSON:
{
"focus_areas": [
{"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0},
{"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0},
{"weight": 1.0}
]
}
Dies hilft beim Erstellen gültiger ACLs, die arithmetic/overflow paths in smbacl.c treffen. Zum Beispiel reproduziert ein bösartiger Security Descriptor mit einem übergroßen dacloffset einen 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)
Coverage-Plateaus mit ANYBLOB überwinden
syzkaller’s anyTypes (ANYBLOB/ANYRES) erlauben es, komplexe Strukturen in generisch mutierende Blobs zu verwandeln. Erzeuge ein neues Corpus aus öffentlichen SMB pcaps und konvertiere Payloads in syzkaller-Programme, die deinen pseudo-syscall aufrufen (z. B. 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)"
)
Das beschleunigt die Erkundung und kann sofort UAFs auslösen (z. B. in ksmbd_sessions_deregister), während die Abdeckung um einige Prozentpunkte steigt.
Sanitizers: Jenseits von KASAN
- KASAN bleibt der wichtigste Detektor für Heap-Bugs (UAF/OOB).
- KCSAN liefert bei diesem Ziel häufig Fehlalarme oder Datenrennen mit geringer Schwere.
- UBSAN/KUBSAN können Fehler bei deklarieren Bounds aufspüren, die KASAN aufgrund der Array-Index-Semantik übersieht. Beispiel:
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));
Das Setzen von num_subauth = 0 löst einen in-struct OOB read von sub_auth[-1] aus, der von UBSAN’s declared-bounds checks erkannt wird.
Durchsatz- und Parallelitäts-Hinweise
- Ein einzelner fuzzer-Prozess (shared auth/state) ist für ksmbd tendenziell deutlich stabiler und bringt dank syzkaller’s internem async executor weiterhin races/UAFs zum Vorschein.
- Mit mehreren VMs kann man insgesamt weiterhin Hunderte SMB-Befehle pro Sekunde erreichen. Auf Funktions-Ebene sind etwa ~60% von fs/smb/server und ~70% von smb2pdu.c erreichbar, wobei die Abdeckung von state-transitions durch solche Metriken unterrepräsentiert ist.
Praktische Checkliste
- Aktiviere durable handles, leases, multi-channel, oplocks und VFS objects in ksmbd.
- Erlaube guest und map-to-guest; akzeptiere NTLMv2. Patch out credit limits und erhöhe max connections für fuzzer-Stabilität.
- Baue einen stateful harness, der SessionId/TreeID/FileIDs cached und create → ioctl → close verknüpft.
- Verwende eine grammar für SMB2 PDUs, um strukturelle Gültigkeit zu erhalten.
- Nutze focus_areas, um schwach abgedeckte Funktionen zu übergewichten (z.B. smbacl.c-Pfade wie smb_check_perm_dacl).
- Seed mit ANYBLOB aus realen pcaps, um Plateaus zu durchbrechen; packe Seeds mit syz-db zur Wiederverwendung.
- Führe mit KASAN + UBSAN aus; triagiere UBSAN declared-bounds reports sorgfältig.
Referenzen
- 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
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks