A use of uninitialized data vulnerability exists in the SMB Server Apple macOS 11.2. A specially crafted SMB packet can cause uninitialized data to end up in server reply which can leak sensitive information. This vulnerability can be triggered by sending a malicious packet to the vulnerable server.
Apple macOS 11.2
6.5 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
CWE-201 - Information Exposure Through Sent Data
macOS is a series of proprietary operating systems developed by Apple with macOS 11.2, with Big Sur being the latest.
Server Message Block (SMB) is a network file sharing protocol widely used in Windows network environments and macOS contains a proprietary implementation of both server and client components. SMB is often used in office and enterprise environments for file and printer sharing.
Three distinct versions and multiple dialects of SMB protocol are supported by macOS’ SMB server. This vulnerability is present in SMB2 and newer versions of the protocol, more specifically in the
CREATE_REQUEST processing which is used to create files on remote shares.
CREATE_REQUEST structure as sent by the client contains a number of fields related to file creation including file name and zero or more
SMB2_CREATE_CONTEXT buffers. Protocol specification enumerates a number of unique
SMB2_CREATE_CONTEXT buffer types, one of which is
SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST whose identifying value is 0x4d784163 (or “MxAc”) and which is used to request file access information to be included in server’s reply.
SMB2_CREATE_CONTEXT buffers states that each of these, in request and replies both, must start on a 8 byte aligned boundary. If we examine the code responsible for creating a reply to
MxAc request we can see the following in
smb2::insert(smb2::create_context_insert const&, uint8_t*&, uint8_t* const&, uint8_t* const&) function:
100042161 int64_t rax_5 = *output_buffer  100042164 int64_t rcx_10 = *arg3 100042167 r12_1 = 0 100042172 if (rax_5 u<= rcx_10 && rax_5 - output_buffer_start s>= 0) 10004217b uint64_t rcx_11 = zx.q(rcx_10.d - rax_5.d) 10004217d uint64_t name_length = zx.q(arg1->name_length) 100042185 if (rcx_11.d u< name_length.d) 100042185 goto label_1000420f3 10004218b if (name_length.w != 0) 100042191 char* name_pointer = arg1->name_pointer 100042195 if (name_pointer != 0) 1000421a4 _memmove(rax_5, name_pointer, name_length, rcx_11)  1000421a9 rdi = rdi 1000421ad int64_t r12_2 = name_length + *output_buffer 1000421b0 *output_buffer = r12_2 1000421b3 rax_5 = r12_2 1000421b6 rax_5 = rax_5 + 7 1000421ba int64_t rax_6 = rax_5 & -8  1000421be *output_buffer = rax_6 1000421c1 int16_t rax_7 = rax_6.w - output_buffer_start.w 1000421c4 *(rdi + 2) = rax_7.b 1000421c7 *(rdi + 3) = rax_7:1.b 1000421ca int64_t rdi_2 = *output_buffer 1000421cd int64_t rax_8 = *arg3 1000421d0 r12_1 = 0 1000421d3 if (rdi_2 u<= rax_8) 1000421df void* rcx_13 = rdi_2 - output_buffer_start 1000421df if (rdi_2 - output_buffer_start s>= 0) 1000421ea uint64_t data_length = zx.q(arg1->data_length) 1000421f1 if (data_length.d u> rax_8.d - rdi_2.d) 1000421f1 goto label_1000420f3 1000421f7 r12_1.b = 1 1000421fa if (data_length.d != 0) 100042203 int64_t data_pointer = arg1->data_pointer 100042207 if (data_pointer != 0) 100042213 _memmove(rdi_2, data_pointer, data_length, rcx_13)  100042218 *output_buffer = *output_buffer + data_length
At  in the above code, output buffer construction is started and at  a
SMB2_CREATE_CONTEXT name is copied to the start of the buffer. Then, at , an 8 byte alignment check is performed and output buffer pointer is adjusted to accommodate the rest of the data. At , the rest of
SMB2_CREATE_CONTEXT response data is copied into the structure.
When an allocation for this output buffer is made no initialization is performed, the memory contents of the previous allocation are still present. Depending on the structure sizes and alignment, by the time this call to
smb2::insert is done, the output buffer can contain from one up to 4 bytes of uninitialized data which is then sent to the client. This is demonstrated by the attached proof of concept exploit that crafts a
CREATE_REQUEST SMB2 packet with a large number of
SMB2_CREATE_CONTEXT structures, each of which gets a reply. Create context of type
MxAc is used in the PoC because its size makes the alignment work in our favour and each
SMB2_CREATE_CONTEXT response structure in the reply will contain 4 bytes of random heap data.
$python smb_create_file_poc.py ('sending', 20630) Leaked: 00000005 ('\x00\x00\x00\x05') 03000203 ('\x03\x00\x02\x03') ff7f0000 ('\xff\x7f\x00\x00') cb876863 ('\xcb\x87hc') ff7f0000 ('\xff\x7f\x00\x00') ff7f0000 ('\xff\x7f\x00\x00') 9b7f0000 ('\x9b\x7f\x00\x00') ff7f0000 ('\xff\x7f\x00\x00') ff7f0000 ('\xff\x7f\x00\x00') ff7f0000 ('\xff\x7f\x00\x00') 9b7f0000 ('\x9b\x7f\x00\x00') 9b7f0000 ('\x9b\x7f\x00\x00') ff7f0000 ('\xff\x7f\x00\x00') 9b7f0000 ('\x9b\x7f\x00\x00') c773a242 ('\xc7s\xa2B') 9b7f0000 ('\x9b\x7f\x00\x00') c773a242 ('\xc7s\xa2B') 9b7f0000 ('\x9b\x7f\x00\x00') 30d10102 ('0\xd1\x01\x02') 30d10102 ('0\xd1\x01\x02')
In our testing, and as demonstrated by the PoC above, leaked data can contain some user and machine specific data as well as heap or code pointer fragments which in turn could be used to determine heap and image bases and defeat ASLR and aid in further service exploitation.
2021-03-15 - Vendor Disclosure
2021-05-25 0 Vendor Patched
2021-06-02 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.