ksmbd Powierzchnia ataku & SMB2/SMB3 Protocol Fuzzing (syzkaller)

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Overview

Ta strona podsumowuje praktyczne techniki pozwalające ćwiczyć i fuzzować Linux in-kernel SMB server (ksmbd) przy użyciu syzkaller. Skupia się na rozszerzaniu powierzchni ataku protokołu poprzez konfigurację, budowaniu stanowego harnessu zdolnego do łączenia operacji SMB2, generowaniu grammar-valid PDUs, ukierunkowywaniu mutacji w słabo pokryte ścieżki kodu oraz wykorzystaniu funkcji syzkaller takich jak focus_areas i ANYBLOB. Podczas gdy oryginalne badania wymieniały konkretne CVE, tutaj kładziemy nacisk na powtarzalną metodologię i konkretne fragmenty, które możesz zaadaptować do własnych środowisk.

Zakres docelowy: SMB2/SMB3 over TCP. Kerberos i RDMA zostały celowo wyłączone z zakresu, aby utrzymać harness prostym.


Expand ksmbd Attack Surface via Configuration

Domyślna, minimalna konfiguracja ksmbd pozostawia dużą część serwera nieprzetestowaną. Włącz następujące funkcje, aby przetestować dodatkowe parsery/handlery i dotrzeć do głębszych ścieżek kodu:

  • Global-level
  • Durable handles
  • Server multi-channel
  • SMB2 leases
  • Per-share-level
  • Oplocks (on by default)
  • VFS objects

Włączenie tych opcji zwiększa wykonanie w modułach takich jak:

  • 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)

Uwagi

  • Dokładne opcje zależą od userspace ksmbd w Twojej dystrybucji (ksmbd-tools). Przejrzyj /etc/ksmbd/ksmbd.conf oraz sekcje per-share, aby włączyć durable handles, leases, oplocks i VFS objects.
  • Multi-channel i durable handles zmieniają automaty stanu i czasy życia obiektów, często ujawniając UAF/refcount/OOB bugs pod obciążeniem współbieżnym.

Authentication and Rate-Limiting Adjustments for Fuzzing

SMB3 wymaga ważnej sesji. Implementacja Kerberos w harnessach dodaje złożoności, więc preferuj NTLM/guest do fuzzingu:

  • Zezwól na guest access i ustaw map to guest = bad user, aby nieznani użytkownicy spadali do GUEST.
  • Akceptuj NTLMv2 (zmodyfikuj politykę jeśli jest wyłączone). Utrzymuje to prostotę handshake’u przy jednoczesnym ćwiczeniu ścieżek kodu SMB3.
  • Wyczyść/obejdź rygorystyczne checks na kredyty (post-hardening dla CVE-2024-50285 zaostrzył simultaneous-op crediting). W przeciwnym razie rate-limity mogą odrzucić fuzzowane sekwencje zbyt wcześnie.
  • Zwiększ max connections (np. do 65536), aby uniknąć wczesnych odrzuceń podczas fuzzingu o wysokiej przepustowości.

Ostrzeżenie: Te poluzowania służą wyłącznie ułatwieniu fuzzingu. Nie stosuj tych ustawień w środowisku produkcyjnym.


Stateful Harness: Extract Resources and Chain Requests

SMB jest stanowy: wiele żądań zależy od identyfikatorów zwracanych przez wcześniejsze odpowiedzi (SessionId, TreeID, FileID pairs). Twój harness musi parsować odpowiedzi i ponownie używać ID w tym samym programie, aby dotrzeć do głębokich handlerów (np. smb2_create → smb2_ioctl → smb2_close).

Example snippet to process a response buffer (skipping the +4B NetBIOS PDU length) and cache IDs:

// 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;
}
}

Wskazówki

  • Keep one fuzzer process sharing authentication/state: better stability and coverage with ksmbd’s global/session tables. syzkaller still injects concurrency by marking ops async, rerun internally.
  • Syzkaller’s experimental reset_acc_state can reset global state but may introduce heavy slowdown. Prefer stability and focus fuzzing instead.

Generowanie SMB2 sterowane gramatyką (Prawidłowe PDUs)

Przekształć struktury SMB2 z Microsoft Open Specifications w fuzzer grammar, tak aby twój generator produkował strukturalnie prawidłowe PDUs, które systematycznie docierają do dispatcherów i IOCTL handlers.

Przykład (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]

Ten styl wymusza poprawne rozmiary/przesunięcia struktur i dramatycznie poprawia coverage w porównaniu z blind mutation.


Directed Fuzzing z focus_areas

Użyj eksperymentalnego focus_areas w syzkaller, aby przyznać większą wagę określonym funkcjom/plikom, które obecnie mają słaby coverage. Przykładowy JSON:

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

To pomaga skonstruować poprawne ACLs, które wywołują ścieżki arithmetic/overflow w smbacl.c. Na przykład złośliwy Security Descriptor z nadmiernym dacloffset odtwarza integer-overflow.

Generator reproduktora (minimalny 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)

Przełamywanie stagnacji pokrycia za pomocą ANYBLOB

anyTypes syzkallera (ANYBLOB/ANYRES) pozwalają sprowadzić złożone struktury do blobów, które mutują generycznie. Utwórz nowy korpus z public SMB pcaps i skonwertuj payloady na programy syzkaller wywołujące twój pseudo-syscall (np. 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)"
)

To przyspiesza eksplorację i może natychmiast wywołać UAFs (np. w ksmbd_sessions_deregister), jednocześnie zwiększając pokrycie o kilka procent.


Sanitizery: Poza KASAN

  • KASAN pozostaje głównym detektorem błędów sterty (UAF/OOB).
  • KCSAN często generuje false positives lub data races o niskiej istotności dla tego celu.
  • UBSAN/KUBSAN może wykryć błędy związane z deklarowanymi granicami, które KASAN pomija z powodu semantyki indeksów tablic. Przykład:
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));

Setting num_subauth = 0 triggers an in-struct OOB read of sub_auth[-1], caught by UBSAN’s declared-bounds checks.


Notatki o przepustowości i równoległości

  • Pojedynczy proces fuzzer’a (wspólne auth/state) zwykle jest znacznie bardziej stabilny dla ksmbd i wciąż ujawnia race/UAF dzięki wewnętrznemu async executorowi syzkallera.
  • Przy użyciu wielu VM można nadal osiągnąć setki SMB commands/sekund łącznie. Pokrycie na poziomie funkcji rzędu ~60% dla fs/smb/server i ~70% dla smb2pdu.c jest osiągalne, choć pokrycie przejść stanów jest słabo reprezentowane przez takie metryki.

Praktyczna lista kontrolna

  • Włącz durable handles, leases, multi-channel, oplocks i VFS objects w ksmbd.
  • Zezwól na guest i map-to-guest; akceptuj NTLMv2. Usuń ograniczenia credit i zwiększ max connections dla stabilności fuzzera.
  • Zbuduj stateful harness, który cache’uje SessionId/TreeID/FileIDs i łańcuchuje create → ioctl → close.
  • Użyj grammar dla SMB2 PDUs, żeby utrzymać poprawność strukturalną.
  • Użyj focus_areas, aby przewagować słabiej pokryte funkcje (np. ścieżki w smbacl.c takie jak smb_check_perm_dacl).
  • Seeduj ANYBLOB z prawdziwych pcaps, aby przełamać plateau; pakuj seedy za pomocą syz-db do ponownego użycia.
  • Uruchamiaj z KASAN + UBSAN; triage raporty UBSAN declared-bounds ostrożnie.

Referencje

  • 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

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks