ksmbd ๊ณต๊ฒฉ ํ‘œ๋ฉด & SMB2/SMB3 ํ”„๋กœํ† ์ฝœ ํผ์ง• (syzkaller)

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ฐœ์š”

์ด ํŽ˜์ด์ง€๋Š” syzkaller๋ฅผ ์‚ฌ์šฉํ•ด Linux ์ธ์ปค๋„ SMB ์„œ๋ฒ„(ksmbd)๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ํผ์ง•ํ•˜๊ธฐ ์œ„ํ•œ ์‹ค์šฉ ๊ธฐ๋ฒ•๋“ค์„ ์ถ”์ƒํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์„ฑ์œผ๋กœ ํ”„๋กœํ† ์ฝœ ๊ณต๊ฒฉ ํ‘œ๋ฉด์„ ํ™•์žฅํ•˜๊ณ , SMB2 ์—ฐ์‚ฐ์„ ์ฒด์ด๋‹ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ ์œ ์ง€ ํ•˜๋‹ˆ์Šค(stateful harness)๋ฅผ ๊ตฌ์ถ•ํ•˜๋ฉฐ, ๋ฌธ๋ฒ•์— ๋งž๋Š” PDU๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์•ฝํ•˜๊ฒŒ ์ปค๋ฒ„๋˜๋Š” ์ฝ”๋“œ ๊ฒฝ๋กœ๋กœ ๋ณ€ํ˜•์„ ํŽธํ–ฅ์‹œํ‚ค๋ฉฐ, focus_areas์™€ ANYBLOB ๊ฐ™์€ syzkaller ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค. ์›๋ณธ ์—ฐ๊ตฌ๋Š” ํŠน์ • CVE๋“ค์„ ์—ด๊ฑฐํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฐฉ๋ฒ•๋ก ๊ณผ ์ž์‹ ์˜ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์ฒด์ ์ธ ์Šค๋‹ˆํŽซ์„ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค.

๋Œ€์ƒ ๋ฒ”์œ„: SMB2/SMB3 over TCP. Kerberos์™€ RDMA๋Š” ํ•˜๋‹ˆ์Šค ๋‹จ์ˆœํ™”๋ฅผ ์œ„ํ•ด ์˜๋„์ ์œผ๋กœ ๋ฒ”์œ„์—์„œ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.


๊ตฌ์„ฑ์œผ๋กœ ksmbd ๊ณต๊ฒฉ ํ‘œ๋ฉด ํ™•์žฅ

๊ธฐ๋ณธ์ ์ธ ksmbd ์„ค์ •์€ ์„œ๋ฒ„์˜ ๋งŽ์€ ๋ถ€๋ถ„์„ ํ…Œ์ŠคํŠธํ•˜์ง€ ๋ชปํ•œ ์ฑ„๋กœ ๋‘ก๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ธฐ๋Šฅ๋“ค์„ ํ™œ์„ฑํ™”ํ•˜์—ฌ ์ถ”๊ฐ€ ํŒŒ์„œ/ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ†ต๊ณผ์‹œํ‚ค๊ณ  ๋” ๊นŠ์€ ์ฝ”๋“œ ๊ฒฝ๋กœ์— ๋„๋‹ฌํ•˜์„ธ์š”:

  • Global-level
  • Durable handles
  • Server multi-channel
  • SMB2 leases
  • Per-share-level
  • Oplocks (๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋จ)
  • VFS objects

์ด๋“ค์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ชจ๋“ˆ์—์„œ ์‹คํ–‰์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค:

  • smb2pdu.c (๋ช…๋ น ํŒŒ์‹ฑ/๋””์ŠคํŒจ์น˜)
  • ndr.c (NDR ์ธ์ฝ”๋“œ/๋””์ฝ”๋“œ)
  • oplock.c (oplock ์š”์ฒญ/์ค‘๋‹จ)
  • smbacl.c (ACL ํŒŒ์‹ฑ/๊ฐ•์ œ)
  • vfs.c (VFS ์—ฐ์‚ฐ)
  • vfs_cache.c (์กฐํšŒ ์บ์‹œ)

์ฐธ๊ณ 

  • ์ •ํ™•ํ•œ ์˜ต์…˜์€ ๋ฐฐํฌํŒ์˜ ksmbd ์‚ฌ์šฉ์ž ๊ณต๊ฐ„(ksmbd-tools)์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. /etc/ksmbd/ksmbd.conf ๋ฐ ๊ฐ share ์„น์…˜์„ ๊ฒ€ํ† ํ•˜์—ฌ durable handles, leases, oplocks ๋ฐ VFS objects๋ฅผ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”.
  • Multi-channel๊ณผ durable handles๋Š” ์ƒํƒœ ๋จธ์‹ ๊ณผ ์ˆ˜๋ช…์— ์˜ํ–ฅ์„ ์ฃผ๋ฉฐ, ๋™์‹œ์„ฑ ํ•˜์—์„œ UAF/refcount/OOB ๋ฒ„๊ทธ๋ฅผ ์ž์ฃผ ๋“œ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค.

ํผ์ง•์„ ์œ„ํ•œ ์ธ์ฆ ๋ฐ ์†๋„ ์ œํ•œ ์กฐ์ •

SMB3๋Š” ์œ ํšจํ•œ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‹ˆ์Šค์— Kerberos๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋ณต์žก์„ฑ์ด ์ฆ๊ฐ€ํ•˜๋ฏ€๋กœ ํผ์ง•์—๋Š” NTLM/guest๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค:

  • guest ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๊ณ  map to guest = bad user๋กœ ์„ค์ •ํ•ด ์•Œ๋ ค์ง€์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ GUEST๋กœ ํด๋ฐฑ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • NTLMv2๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค(๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์ •์ฑ…์„ ํŒจ์น˜). ์ด๋Š” ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋ฉด์„œ SMB3 ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • ์‹คํ—˜ ์ค‘์—๋Š” ์—„๊ฒฉํ•œ credit ๊ฒ€์‚ฌ(credit checks)๋ฅผ ํŒจ์น˜ํ•ด ์ œ๊ฑฐํ•˜์„ธ์š” (ํ•˜๋“œ๋‹ ์ดํ›„ CVE-2024-50285๋กœ ๋™์‹œ ์ž‘์—… ํฌ๋ ˆ๋”ง ๋ถ€์—ฌ๊ฐ€ ๋” ์—„๊ฒฉํ•ด์กŒ์Šต๋‹ˆ๋‹ค). ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์†๋„ ์ œํ•œ์ด ํผ์ฆˆ๋œ ์‹œํ€€์Šค๋ฅผ ๋„ˆ๋ฌด ์ผ์ฐ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ตœ๋Œ€ ์—ฐ๊ฒฐ ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œ์ผœ(์˜ˆ: 65536) ๊ณ ์ฒ˜๋ฆฌ๋Ÿ‰ ํผ์ง• ์ค‘ ์กฐ๊ธฐ ๊ฑฐ๋ถ€๋ฅผ ํ”ผํ•˜์„ธ์š”.

์ฃผ์˜: ์ด๋Ÿฌํ•œ ์™„ํ™”๋Š” ํผ์ง•์„ ์šฉ์ดํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ์šด์˜ ํ™˜๊ฒฝ์— ์ด ์„ค์ •์„ ๋ฐฐํฌํ•˜์ง€ ๋งˆ์„ธ์š”.


์ƒํƒœ ์œ ์ง€ ํ•˜๋‹ˆ์Šค: ๋ฆฌ์†Œ์Šค ์ถ”์ถœ ๋ฐ ์š”์ฒญ ์ฒด์ด๋‹

SMB๋Š” ์ƒํƒœ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค: ๋งŽ์€ ์š”์ฒญ์ด ์ด์ „ ์‘๋‹ต์—์„œ ๋ฐ˜ํ™˜๋œ ์‹๋ณ„์ž(SessionId, TreeID, FileID ์Œ ๋“ฑ)์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‹ˆ์Šค๋Š” ์‘๋‹ต์„ ํŒŒ์‹ฑํ•˜๊ณ  ๋™์ผํ•œ ํ”„๋กœ๊ทธ๋žจ ๋‚ด์—์„œ ID๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ๊นŠ์€ ํ•ธ๋“ค๋Ÿฌ์— ๋„๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: smb2_create โ†’ smb2_ioctl โ†’ smb2_close).

์˜ˆ์ œ ์Šค๋‹ˆํŽซ: ์‘๋‹ต ๋ฒ„ํผ( +4B NetBIOS PDU ๊ธธ์ด ์ƒ๋žต)๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ID๋ฅผ ์บ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•:

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

ํŒ

  • ์ธ์ฆ/์ƒํƒœ๋ฅผ ๊ณต์œ ํ•˜๋Š” fuzzer ํ”„๋กœ์„ธ์Šค ํ•˜๋‚˜๋ฅผ ์œ ์ง€ํ•˜์„ธ์š”: ksmbdโ€™s global/session tables์—์„œ ๋” ๋‚˜์€ ์•ˆ์ •์„ฑ๊ณผ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. syzkaller๋Š” ops๋ฅผ async๋กœ ํ‘œ์‹œํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ์žฌ์‹คํ–‰ํ•˜๋ฉด์„œ ์—ฌ์ „ํžˆ ๋™์‹œ์„ฑ์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • Syzkaller์˜ experimental reset_acc_state๋Š” global state๋ฅผ ๋ฆฌ์…‹ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹ฌ๊ฐํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ˆ์ •์„ฑ์„ ์šฐ์„ ํ•˜๊ณ  fuzzing์— ์ง‘์ค‘ํ•˜์„ธ์š”.

๋ฌธ๋ฒ• ๊ธฐ๋ฐ˜ SMB2 ์ƒ์„ฑ (์œ ํšจํ•œ PDUs)

Microsoft Open Specifications์˜ SMB2 ๊ตฌ์กฐ๋ฅผ fuzzer grammar๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ generator๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ์œ ํšจํ•œ PDUs๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด dispatchers์™€ IOCTL handlers์— ์ฒด๊ณ„์ ์œผ๋กœ ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ (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]

์ด ๋ฐฉ์‹์€ ๊ตฌ์กฐ์ฒด ํฌ๊ธฐ/์˜คํ”„์…‹์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฐ•์ œํ•˜๋ฉฐ ๋ธ”๋ผ์ธ๋“œ ๋ฎคํ…Œ์ด์…˜์— ๋น„ํ•ด ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๊ทน์ ์œผ๋กœ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.


Directed Fuzzing With focus_areas

syzkallerโ€™s ์‹คํ—˜์  focus_areas๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ์ปค๋ฒ„๋ฆฌ์ง€๊ฐ€ ์•ฝํ•œ ํŠน์ • ํ•จ์ˆ˜/ํŒŒ์ผ์— ๊ฐ€์ค‘์น˜๋ฅผ ๋”ํ•˜์„ธ์š”. ์˜ˆ์‹œ JSON:

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

์ด๊ฒƒ์€ smbacl.c์˜ arithmetic/overflow ๊ฒฝ๋กœ๋ฅผ ํƒ€๊นƒํ•˜๋Š” ์œ ํšจํ•œ ACLs๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ณผ๋„ํ•œ dacloffset์„ ๊ฐ€์ง„ ์•…์˜์ ์ธ Security Descriptor๋Š” integer-overflow๋ฅผ ์žฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์žฌํ˜„๊ธฐ ๋นŒ๋” (๊ฐ„๋‹จํ•œ 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)

ANYBLOB๋กœ ์ปค๋ฒ„๋ฆฌ์ง€ ์ •์ฒด ๋ŒํŒŒ

syzkallerโ€™s anyTypes (ANYBLOB/ANYRES)๋Š” ๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ์ผ๋ฐ˜์ ์œผ๋กœ mutateํ•˜๋Š” blob์œผ๋กœ ์ถ•์†Œํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ๊ณต๊ฐœ SMB pcaps์—์„œ ์ƒˆ๋กœ์šด corpus๋ฅผ seedํ•˜๊ณ  payload๋ฅผ syzkaller ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋‹น์‹ ์˜ pseudo-syscall(์˜ˆ: 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)"
)

์ด๊ฒƒ์€ ํƒ์ƒ‰์„ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘์‹œํ‚ค๋ฉฐ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋ช‡ ํผ์„ผํŠธ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ๋™์‹œ์— ์ฆ‰์‹œ UAFs(์˜ˆ: ksmbd_sessions_deregister)๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


Sanitizers: Beyond KASAN

  • KASAN์€ ํž™ ๋ฒ„๊ทธ(UAF/OOB)๋ฅผ ํƒ์ง€ํ•˜๋Š” ์ฃผ์š” ์ˆ˜๋‹จ์œผ๋กœ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.
  • KCSAN์€ ์ด ๋Œ€์ƒ์—์„œ ์ข…์ข… ์˜คํƒ์„ ๋‚ด๊ฑฐ๋‚˜ ์‹ฌ๊ฐ๋„๊ฐ€ ๋‚ฎ์€ ๋ฐ์ดํ„ฐ ๋ ˆ์ด์Šค๋ฅผ ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค.
  • UBSAN/KUBSAN์€ ๋ฐฐ์—ด ์ธ๋ฑ์Šค ์˜๋ฏธ๋ก  ๋•Œ๋ฌธ์— KASAN์ด ๋†“์น˜๋Š” ์„ ์–ธ๋œ ๊ฒฝ๊ณ„ ์˜ค๋ฅ˜๋ฅผ ์žก์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ:
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));

num_subauth = 0์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€์—์„œ sub_auth[-1]์— ๋Œ€ํ•œ OOB read๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉฐ, UBSAN์˜ declared-bounds ๊ฒ€์‚ฌ์— ์˜ํ•ด ํฌ์ฐฉ๋ฉ๋‹ˆ๋‹ค.


์ฒ˜๋ฆฌ๋Ÿ‰ ๋ฐ ๋ณ‘๋ ฌ์„ฑ ์ฃผ์˜์‚ฌํ•ญ

  • ๋‹จ์ผ fuzzer ํ”„๋กœ์„ธ์Šค (shared auth/state)๋Š” ksmbd์— ๋Œ€ํ•ด ํ›จ์”ฌ ๋” ์•ˆ์ •์ ์ธ ๊ฒฝํ–ฅ์ด ์žˆ์œผ๋ฉฐ, syzkaller์˜ ๋‚ด๋ถ€ async executor ๋•๋ถ„์— ์—ฌ์ „ํžˆ races/UAFs๋ฅผ ๋“œ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค.
  • ์—ฌ๋Ÿฌ VM์„ ์‚ฌ์šฉํ•˜๋ฉด ์ „๋ฐ˜์ ์œผ๋กœ ์ดˆ๋‹น ์ˆ˜๋ฐฑ ๊ฑด์˜ SMB ๋ช…๋ น์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ˆ˜์ค€์˜ ์ปค๋ฒ„๋ฆฌ์ง€๋Š” fs/smb/server์˜ ์•ฝ 60% ๋ฐ smb2pdu.c์˜ ์•ฝ 70% ์ •๋„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, ์ƒํƒœ ์ „์ด(state-transition) ์ปค๋ฒ„๋ฆฌ์ง€๋Š” ์ด๋Ÿฌํ•œ ์ง€ํ‘œ๋กœ๋Š” ๊ณผ์†Œํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค.

์‹ค๋ฌด ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • ksmbd์—์„œ durable handles, leases, multi-channel, oplocks ๋ฐ VFS objects๋ฅผ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”.
  • guest ๋ฐ map-to-guest๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  NTLMv2๋ฅผ ์ˆ˜์šฉํ•˜์„ธ์š”. fuzzer ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด credit limits๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  max connections๋ฅผ ๋Š˜๋ฆฌ์„ธ์š”.
  • SessionId/TreeID/FileIDs๋ฅผ ์บ์‹œํ•˜๊ณ  create โ†’ ioctl โ†’ close๋ฅผ ์—ฐ์‡„ํ•˜๋Š” stateful harness๋ฅผ ๊ตฌ์ถ•ํ•˜์„ธ์š”.
  • ๊ตฌ์กฐ์  ์œ ํšจ์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด SMB2 PDUs์— ๋Œ€ํ•œ grammar๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์•ฝํ•˜๊ฒŒ ์ปค๋ฒ„๋œ ํ•จ์ˆ˜์— ๊ฐ€์ค‘์น˜๋ฅผ ๋‘๊ธฐ ์œ„ํ•ด focus_areas๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š” (์˜ˆ: smbacl.c์˜ smb_check_perm_dacl ๊ฒฝ๋กœ).
  • ์ •์ฒด๊ธฐ๋ฅผ ๊นจ๊ธฐ ์œ„ํ•ด ์‹ค์ œ pcaps์˜ ANYBLOB๋กœ ์‹œ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด syz-db๋กœ ์‹œ๋“œ๋“ค์„ ํŒจํ‚นํ•˜์„ธ์š”.
  • KASAN + UBSAN๋กœ ์‹คํ–‰ํ•˜์„ธ์š”; UBSAN์˜ declared-bounds ๋ณด๊ณ ์„œ๋Š” ์‹ ์ค‘ํžˆ ๋ถ„์„ํ•˜์„ธ์š”.

์ฐธ๊ณ ์ž๋ฃŒ

  • 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
  • ๋ฐฐ๊ฒฝ ์ฝ๊ธฐ: pwning.tech โ€œTickling ksmbd: fuzzing SMB in the Linux kernelโ€; Dongliang Muโ€™s syzkaller notes

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ