Skip to content

Commit 4b54ccf

Browse files
authored
Merge pull request #1383 from HackTricks-wiki/update_ksmbd_-_Fuzzing_Improvements_and_Vulnerability_Dis_20250904_124648
ksmbd - Fuzzing Improvements and Vulnerability Discovery (2/...
2 parents b083058 + 74c3290 commit 4b54ccf

File tree

3 files changed

+238
-0
lines changed

3 files changed

+238
-0
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@
494494
- [135, 593 - Pentesting MSRPC](network-services-pentesting/135-pentesting-msrpc.md)
495495
- [137,138,139 - Pentesting NetBios](network-services-pentesting/137-138-139-pentesting-netbios.md)
496496
- [139,445 - Pentesting SMB](network-services-pentesting/pentesting-smb/README.md)
497+
- [Ksmbd Attack Surface And Fuzzing Syzkaller](network-services-pentesting/pentesting-smb/ksmbd-attack-surface-and-fuzzing-syzkaller.md)
497498
- [rpcclient enumeration](network-services-pentesting/pentesting-smb/rpcclient-enumeration.md)
498499
- [143,993 - Pentesting IMAP](network-services-pentesting/pentesting-imap.md)
499500
- [161,162,10161,10162/udp - Pentesting SNMP](network-services-pentesting/pentesting-snmp/README.md)

src/network-services-pentesting/pentesting-smb/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,12 @@ In **kali** it is located on /usr/share/doc/python3-impacket/examples/
481481

482482
[https://www.hackingarticles.in/beginners-guide-to-impacket-tool-kit-part-1/](https://www.hackingarticles.in/beginners-guide-to-impacket-tool-kit-part-1/)
483483

484+
### ksmbd attack surface and SMB2/SMB3 protocol fuzzing (syzkaller)
485+
486+
{{#ref}}
487+
ksmbd-attack-surface-and-fuzzing-syzkaller.md
488+
{{#endref}}
489+
484490
## **Bruteforce users credentials**
485491

486492
**This is not recommended, you could block an account if you exceed the maximum allowed tries**
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# ksmbd Attack Surface & SMB2/SMB3 Protocol Fuzzing (syzkaller)
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
## Overview
6+
This page abstracts practical techniques to exercise and fuzz the Linux in-kernel SMB server (ksmbd) using syzkaller. It focuses on expanding the protocol attack surface through configuration, building a stateful harness capable of chaining SMB2 operations, generating grammar-valid PDUs, biasing mutations into weakly-covered code paths, and leveraging syzkaller features such as focus_areas and ANYBLOB. While the original research enumerates specific CVEs, here we emphasise the reusable methodology and concrete snippets you can adapt to your own setups.
7+
8+
Target scope: SMB2/SMB3 over TCP. Kerberos and RDMA are intentionally out-of-scope to keep the harness simple.
9+
10+
---
11+
12+
## Expand ksmbd Attack Surface via Configuration
13+
By default, a minimal ksmbd setup leaves large parts of the server untested. Enable the following features to drive the server through additional parsers/handlers and reach deeper code paths:
14+
15+
- Global-level
16+
- Durable handles
17+
- Server multi-channel
18+
- SMB2 leases
19+
- Per-share-level
20+
- Oplocks (on by default)
21+
- VFS objects
22+
23+
Enabling these increases execution in modules such as:
24+
- smb2pdu.c (command parsing/dispatch)
25+
- ndr.c (NDR encode/decode)
26+
- oplock.c (oplock request/break)
27+
- smbacl.c (ACL parsing/enforcement)
28+
- vfs.c (VFS ops)
29+
- vfs_cache.c (lookup cache)
30+
31+
Notes
32+
- Exact options depend on your distro’s ksmbd userspace (ksmbd-tools). Review /etc/ksmbd/ksmbd.conf and per-share sections to enable durable handles, leases, oplocks and VFS objects.
33+
- Multi-channel and durable handles alter state machines and lifetimes, often surfacing UAF/refcount/OOB bugs under concurrency.
34+
35+
---
36+
37+
## Authentication and Rate-Limiting Adjustments for Fuzzing
38+
SMB3 needs a valid session. Implementing Kerberos in harnesses adds complexity, so prefer NTLM/guest for fuzzing:
39+
40+
- Allow guest access and set map to guest = bad user so unknown users fall back to GUEST.
41+
- Accept NTLMv2 (patch policy if disabled). This keeps the handshake simple while exercising SMB3 code paths.
42+
- Patch out strict credit checks when experimenting (post-hardening for CVE-2024-50285 made simultaneous-op crediting stricter). Otherwise, rate-limits can reject fuzzed sequences too early.
43+
- Increase max connections (e.g., to 65536) to avoid early rejections during high-throughput fuzzing.
44+
45+
Caution: These relaxations are to facilitate fuzzing only. Do not deploy with these settings in production.
46+
47+
---
48+
49+
## Stateful Harness: Extract Resources and Chain Requests
50+
SMB is stateful: many requests depend on identifiers returned by prior responses (SessionId, TreeID, FileID pairs). Your harness must parse responses and reuse IDs within the same program to reach deep handlers (e.g., smb2_create → smb2_ioctl → smb2_close).
51+
52+
Example snippet to process a response buffer (skipping the +4B NetBIOS PDU length) and cache IDs:
53+
54+
```c
55+
// process response. does not contain +4B PDU length
56+
void process_buffer(int msg_no, const char *buffer, size_t received) {
57+
uint16_t cmd_rsp = u16((const uint8_t *)(buffer + CMD_OFFSET));
58+
switch (cmd_rsp) {
59+
case SMB2_TREE_CONNECT:
60+
if (received >= TREE_ID_OFFSET + sizeof(uint32_t))
61+
tree_id = u32((const uint8_t *)(buffer + TREE_ID_OFFSET));
62+
break;
63+
case SMB2_SESS_SETUP:
64+
// first session setup response carries session_id
65+
if (msg_no == 0x01 && received >= SESSION_ID_OFFSET + sizeof(uint64_t))
66+
session_id = u64((const uint8_t *)(buffer + SESSION_ID_OFFSET));
67+
break;
68+
case SMB2_CREATE:
69+
if (received >= CREATE_VFID_OFFSET + sizeof(uint64_t)) {
70+
persistent_file_id = u64((const uint8_t *)(buffer + CREATE_PFID_OFFSET));
71+
volatile_file_id = u64((const uint8_t *)(buffer + CREATE_VFID_OFFSET));
72+
}
73+
break;
74+
default:
75+
break;
76+
}
77+
}
78+
```
79+
80+
Tips
81+
- 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.
82+
- Syzkaller’s experimental reset_acc_state can reset global state but may introduce heavy slowdown. Prefer stability and focus fuzzing instead.
83+
84+
---
85+
86+
## Grammar-Driven SMB2 Generation (Valid PDUs)
87+
Translate the Microsoft Open Specifications SMB2 structures into a fuzzer grammar so your generator produces structurally valid PDUs, which systematically reach dispatchers and IOCTL handlers.
88+
89+
Example (SMB2 IOCTL request):
90+
91+
```
92+
smb2_ioctl_req {
93+
Header_Prefix SMB2Header_Prefix
94+
Command const[0xb, int16]
95+
Header_Suffix SMB2Header_Suffix
96+
StructureSize const[57, int16]
97+
Reserved const[0, int16]
98+
CtlCode union_control_codes
99+
PersistentFileId const[0x4, int64]
100+
VolatileFileId const[0x0, int64]
101+
InputOffset offsetof[Input, int32]
102+
InputCount bytesize[Input, int32]
103+
MaxInputResponse const[65536, int32]
104+
OutputOffset offsetof[Output, int32]
105+
OutputCount len[Output, int32]
106+
MaxOutputResponse const[65536, int32]
107+
Flags int32[0:1]
108+
Reserved2 const[0, int32]
109+
Input array[int8]
110+
Output array[int8]
111+
} [packed]
112+
```
113+
114+
This style forces correct structure sizes/offsets and dramatically improves coverage versus blind mutation.
115+
116+
---
117+
118+
## Directed Fuzzing With focus_areas
119+
Use syzkaller’s experimental focus_areas to overweight specific functions/files that currently have weak coverage. Example JSON:
120+
121+
```json
122+
{
123+
"focus_areas": [
124+
{"filter": {"functions": ["smb_check_perm_dacl"]}, "weight": 20.0},
125+
{"filter": {"files": ["^fs/smb/server/"]}, "weight": 2.0},
126+
{"weight": 1.0}
127+
]
128+
}
129+
```
130+
131+
This helps construct valid ACLs that hit arithmetic/overflow paths in smbacl.c. For instance, a malicious Security Descriptor with an oversized dacloffset reproduces an integer-overflow.
132+
133+
Reproducer builder (minimal Python):
134+
135+
```python
136+
def build_sd():
137+
import struct
138+
sd = bytearray(0x14)
139+
sd[0x00] = 0x00; sd[0x01] = 0x00
140+
struct.pack_into('<H', sd, 0x02, 0x0001)
141+
struct.pack_into('<I', sd, 0x04, 0x78)
142+
struct.pack_into('<I', sd, 0x08, 0x00)
143+
struct.pack_into('<I', sd, 0x0C, 0x10000)
144+
struct.pack_into('<I', sd, 0x10, 0xFFFFFFFF) # dacloffset
145+
while len(sd) < 0x78:
146+
sd += b'A'
147+
sd += b"\x01\x01\x00\x00\x00\x00\x00\x00" # minimal DACL
148+
sd += b"\xCC" * 64
149+
return bytes(sd)
150+
```
151+
152+
---
153+
154+
## Breaking Coverage Plateaus With ANYBLOB
155+
syzkaller’s anyTypes (ANYBLOB/ANYRES) allow collapsing complex structures into blobs that mutate generically. Seed a new corpus from public SMB pcaps and convert payloads into syzkaller programs calling your pseudo-syscall (e.g., syz_ksmbd_send_req):
156+
157+
```bash
158+
# Extract SMB payloads to JSON
159+
# tshark -r smb2_dac_sample.pcap -Y "smb || smb2" -T json -e tcp.payload > packets.json
160+
```
161+
162+
```python
163+
import json, os
164+
os.makedirs("corpus", exist_ok=True)
165+
166+
with open("packets.json") as f:
167+
data = json.load(f)
168+
# adjust indexing to your tshark JSON structure
169+
packets = [e["_source"]["layers"]["tcp.payload"] for e in data]
170+
171+
for i, pkt in enumerate(packets):
172+
pdu = pkt[0]
173+
pdu_size = len(pdu) // 2 # hex string length → bytes
174+
with open(f"corpus/packet_{i:03d}.txt", "w") as f:
175+
f.write(
176+
f"syz_ksmbd_send_req(&(&(0x7f0000000340))=ANY=[@ANYBLOB=\"{pdu}\"], {hex(pdu_size)}, 0x0, 0x0)"
177+
)
178+
```
179+
180+
This jump-starts exploration and can immediately trigger UAFs (e.g., in ksmbd_sessions_deregister) while lifting coverage a few percent.
181+
182+
---
183+
184+
## Sanitizers: Beyond KASAN
185+
- KASAN remains the primary detector for heap bugs (UAF/OOB).
186+
- KCSAN often yields false positives or low-severity data races in this target.
187+
- UBSAN/KUBSAN can catch declared-bounds mistakes that KASAN misses due to array-index semantics. Example:
188+
189+
```c
190+
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
191+
struct smb_sid {
192+
__u8 revision; __u8 num_subauth; __u8 authority[NUM_AUTHS];
193+
__le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */
194+
} __attribute__((packed));
195+
```
196+
197+
Setting num_subauth = 0 triggers an in-struct OOB read of sub_auth[-1], caught by UBSAN’s declared-bounds checks.
198+
199+
---
200+
201+
## Throughput and Parallelism Notes
202+
- A single fuzzer process (shared auth/state) tends to be significantly more stable for ksmbd and still surfaces races/UAFs thanks to syzkaller’s internal async executor.
203+
- With multiple VMs, you can still hit hundreds of SMB commands/second overall. Function-level coverage around ~60% of fs/smb/server and ~70% of smb2pdu.c is attainable, though state-transition coverage is under-represented by such metrics.
204+
205+
---
206+
207+
## Practical Checklist
208+
- Enable durable handles, leases, multi-channel, oplocks, and VFS objects in ksmbd.
209+
- Allow guest and map-to-guest; accept NTLMv2. Patch out credit limits and raise max connections for fuzzer stability.
210+
- Build a stateful harness that caches SessionId/TreeID/FileIDs and chains create → ioctl → close.
211+
- Use a grammar for SMB2 PDUs to maintain structural validity.
212+
- Use focus_areas to overweight weakly-covered functions (e.g., smbacl.c paths like smb_check_perm_dacl).
213+
- Seed with ANYBLOB from real pcaps to break plateaus; pack seeds with syz-db for reuse.
214+
- Run with KASAN + UBSAN; triage UBSAN declared-bounds reports carefully.
215+
216+
---
217+
218+
## References
219+
- Doyensec – ksmbd Fuzzing (Part 2): https://blog.doyensec.com/2025/09/02/ksmbd-2.html
220+
- syzkaller: https://github.com/google/syzkaller
221+
- ANYBLOB/anyTypes (commit 9fe8aa4): https://github.com/google/syzkaller/commit/9fe8aa4
222+
- Async executor change (commit fd8caa5): https://github.com/google/syzkaller/commit/fd8caa5
223+
- syz-db: https://github.com/google/syzkaller/tree/master/tools/syz-db
224+
- KASAN: https://docs.kernel.org/dev-tools/kasan.html
225+
- UBSAN/KUBSAN: https://docs.kernel.org/dev-tools/ubsan.html
226+
- KCSAN: https://docs.kernel.org/dev-tools/kcsan.html
227+
- Microsoft Open Specifications (SMB): https://learn.microsoft.com/openspecs/
228+
- Wireshark Sample Captures: https://wiki.wireshark.org/SampleCaptures
229+
- Background reading: pwning.tech “Tickling ksmbd: fuzzing SMB in the Linux kernel”; Dongliang Mu’s syzkaller notes
230+
231+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)