mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
220 lines
10 KiB
Markdown
220 lines
10 KiB
Markdown
# 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('<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’s anyTypes (ANYBLOB/ANYRES) omogućavaju sabijanje složenih struktura u blobs koji se generički mutiraju. Napunite novi korpus iz javnih SMB pcaps i konvertujte payloads u syzkaller programe koji pozivaju vaš pseudo-syscall (npr. 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)"
|
||
)
|
||
```
|
||
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}}
|