Talos Vulnerability Report

TALOS-2022-1660

Apple DCERPC packet stats buffer overflow vulnerability

July 13, 2023
CVE Number

CVE-2023-23513

SUMMARY

A buffer overflow vulnerability exists in the stats logging functionality of DCERPC library as used in Apple macOS 12.6.1 A specially-crafted network packet can lead to out-of-bounds memory modification which can lead to further memory corruption. An authenticated remote attacker can send a network request to trigger this vulnerability. A local attacker can write to a local socket to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

Apple macOS 12.6.1

PRODUCT URLS

macOS - https://apple.com

CVSSv3 SCORE

8.1 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-129 - Improper Validation of Array Index

DETAILS

macOS is a series of proprietary operating systems developed by Apple. DCERPC framework is library, used as a component of macOS. DCERPC is a remote procedure call protocol that is the basis for RPC functionality on Windows. DCERPC framework on macOS implements this protocol and enables interoperability of Windows network services on macOS. For example, it is used on top of SMB, through which support for Active Directory is implemented. DCERPC framework is employed by the rpcsvchost binary that opens a number of UNIX sockets and expose different RPC functionality.

There exists a vulnerability in the way DCERPC framework processes incoming packets. Namely, while receiving and processing packets in function receive_dispatch, global statistics about received packets are kept. Information from the packet is directly used to index into a table of stats in the following code:

    pktp = (rpc_cn_packet_p_t) fragbuf_p->data_p;                                    [1]

    /*
     * Trace the incoming packet.
     */
    RPC_CN_PKT_TRC (pktp);
    RPC_CN_PKT_DUMP (pktp, fragbuf_p->data_size);

    /*
     * Keep some stats on the packets received.
     */
    RPC_CN_STATS_INCR (pstats[RPC_CN_PKT_PTYPE (pktp)].rcvd);                       [2]
    RPC_CN_STATS_INCR (pkts_rcvd);

In the above code, at [1], a pointer to packet data is retrieved, and packet type is then used to increment count of received packets at [2]. Packet type is determined by macro RPC_CN_PKT_PTYPE, which simply casts the data pointer into header structure:

#define RPC_CN_PKT_PTYPE(pkt_p)           (RPC_CN_HDR_BIND(pkt_p).hdr.common_hdr.ptype)

Note that no check on validity of the packet type is performed. Structure common_hdr is:

typedef struct
{
    unsigned8  rpc_vers;               /* 00:01 RPC version - major */
    unsigned8  rpc_vers_minor;         /* 01:01 RPC version - minor */
    unsigned8  ptype;                  /* 02:01 packet type */
    unsigned8  flags;                  /* 03:01 flags */
    unsigned8  drep[4];                /* 04:04 ndr format */
    unsigned16 frag_len;               /* 08:02 fragment length */
    unsigned16 auth_len;               /* 10:02 authentication length */
    unsigned32 call_id;                /* 12:04 call identifier */
} rpc_cn_common_hdr_t, *rpc_cn_common_hdr_p_t;

From above, we can see that ptype is an unsigned 1-byte integer, meaning its values can range from 0 to 255. Packet type is used to index into pstats array, which is defined as pstats[RPC_C_CN_PKT_MAX_TYPE + 1]; with RPC_C_CN_PKT_MAX_TYPE being 19. Since no sanity checks are performed on the packet type, we can conclude that large value of ptype in the incoming packet will cause an out-of-bounds memory to be accessed, signifying memory corruption.

The effect is that RPC_CN_STATS_INCR will be executed on memory outside of the bounds of pstats array, which is a global variable. In other words, it will cause a 1-byte increment at an out-of-bounds location. Out-of-bounds memory access can happen in increments dependent on the size of array entry, which in this case is 8 bytes, for a total of 2048 bytes. Depending on the memory layout, this could result in modification of sensitive data and further memory corruption, which could be used as a component of an exploit to achieve arbitrary code execution.

Examining the memory contents immediately after the buffer overflow shows that global variable uuid_g_nil_uuid follows the limited size array. Variable uuid_g_nil_uuid represents a NIL UUID and is supposed to contain only zeros. Modifying it directly has impact on operation of the program and could lead to other issues.

On macOS, vulnerable code could be reached over network, after authentication, through SMB protocol. However, it can also be triggered through access to local UNIX sockets in /var/rpc/ncalrpc/* via a regular user.

Crash Information

With AddressSanitizer, the crash occurs on a read right before an increment.

 =================================================================
     ==6372==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0001004b79b4 at pc 0x0001003f1d53 bp 0x7000016f9e90 sp 0x7000016f9e88
     READ of size 4 at 0x0001004b79b4 thread T15
     ==6372==WARNING: invalid path to external symbolizer!
     ==6372==WARNING: Failed to use and restart external symbolizer!
         #0 0x1003f1d52 in receive_dispatch+0x1b22 (./DCERPC:x86_64+0x2d2d52)
         #1 0x1003edf60 in rpc__cn_network_receiver+0x1b40 (./DCERPC:x86_64+0x2cef60)
         #2 0x1001249e2 in proxy_start+0x1e2 (./DCERPC:x86_64+0x59e2)
         #3 0x7fff6d7d3108 in _pthread_start+0x93 (/usr/lib/system/libsystem_pthread.dylib:x86_64+0x6108)
         #4 0x7fff6d7ceb8a in thread_start+0xe (/usr/lib/system/libsystem_pthread.dylib:x86_64+0x1b8a)

 0x0001004b79b4 is located 4 bytes to the right of global variable 'uuid_g_nil_uuid' defined in './projects/dcerpc/dcerpc/uuid/uuid.c:298:12' (0x1004b79a0) of size 16
 SUMMARY: AddressSanitizer: global-buffer-overflow (./DCERPC:x86_64+0x2d2d52) in receive_dispatch+0x1b22
 Shadow bytes around the buggy address:
   0x100020096ee0: 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9
   0x100020096ef0: 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9
   0x100020096f00: 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9
   0x100020096f10: 04 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
   0x100020096f20: 00 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9
 =>0x100020096f30: f9 f9 f9 f9 00 00[f9]f9 00 00 00 00 00 00 00 00
   0x100020096f40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
   0x100020096f50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
   0x100020096f60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
   0x100020096f70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
   0x100020096f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 Shadow byte legend (one shadow byte represents 8 application bytes):
   Addressable:           00
   Partially addressable: 01 02 03 04 05 06 07
   Heap left redzone:       fa
   Freed heap region:       fd
   Stack left redzone:      f1
   Stack mid redzone:       f2
   Stack right redzone:     f3
   Stack after return:      f5
   Stack use after scope:   f8
   Global redzone:          f9
   Global init order:       f6
   Poisoned by user:        f7
   Container overflow:      fc
   Array cookie:            ac
   Intra object redzone:    bb
   ASan internal:           fe
   Left alloca redzone:     ca
   Right alloca redzone:    cb
 Thread T15 created by T4 here:
     #0 0x10059967c in wrap_pthread_create+0x5c (./libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4267c)
     #1 0x1001245bb in dcethread_create+0x3fb (./DCERPC:x86_64+0x55bb)
     #2 0x100124c9c in dcethread_create_throw+0x2c (./DCERPC:x86_64+0x5c9c)
     #3 0x1003a16df in rpc__cn_assoc_acb_create+0x47f (./DCERPC:x86_64+0x2826df)
     #4 0x100302e84 in rpc__list_element_alloc+0x10a4 (./DCERPC:x86_64+0x1e3e84)
     #5 0x10038bee7 in rpc__cn_assoc_acb_alloc+0x107 (./DCERPC:x86_64+0x26cee7)
     #6 0x1003927a1 in rpc__cn_assoc_listen+0x251 (./DCERPC:x86_64+0x2737a1)
     #7 0x1003db93e in rpc__cn_network_select_dispatch+0x12ce (./DCERPC:x86_64+0x2bc93e)
     #8 0x100364f4f in lthread_loop+0x65f (./DCERPC:x86_64+0x245f4f)
     #9 0x100363dbc in lthread+0x28c (./DCERPC:x86_64+0x244dbc)
     #10 0x1001249e2 in proxy_start+0x1e2 (./DCERPC:x86_64+0x59e2)
     #11 0x7fff6d7d3108 in _pthread_start+0x93 (/usr/lib/system/libsystem_pthread.dylib:x86_64+0x6108)
     #12 0x7fff6d7ceb8a in thread_start+0xe (/usr/lib/system/libsystem_pthread.dylib:x86_64+0x1b8a)

 Thread T4 created by T2 here:
     #0 0x10059967c in wrap_pthread_create+0x5c (./libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4267c)
     #1 0x1001245bb in dcethread_create+0x3fb (./DCERPC:x86_64+0x55bb)
     #2 0x100124c9c in dcethread_create_throw+0x2c (./DCERPC:x86_64+0x5c9c)
     #3 0x100363ad3 in rpc__nlsn_activate_desc+0xc3 (./DCERPC:x86_64+0x244ad3)
     #4 0x10035bd8b in rpc_server_listen+0x47b (./DCERPC:x86_64+0x23cd8b)
     #5 0x10000316b in run_dcerpc_svc(void*)+0x1c (/usr/libexec/rpcsvchost:x86_64+0x10000316b)
     #6 0x7fff6d7d3108 in _pthread_start+0x93 (/usr/lib/system/libsystem_pthread.dylib:x86_64+0x6108)
     #7 0x7fff6d7ceb8a in thread_start+0xe (/usr/lib/system/libsystem_pthread.dylib:x86_64+0x1b8a)

 Thread T2 created by T0 here:
     #0 0x10059967c in wrap_pthread_create+0x5c (./libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4267c)
     #1 0x100002c1f in main+0x13ff (/usr/libexec/rpcsvchost:x86_64+0x100002c1f)
     #2 0x7fff6d5cecc8 in start+0x0 (/usr/lib/system/libdyld.dylib:x86_64+0x1acc8)
VENDOR RESPONSE

Fixed by Apple on 2023-01-23, patch information available at: https://support.apple.com/en-us/HT213605

TIMELINE

2022-11-15 - Vendor Disclosure
2023-01-23 - Vendor Patch Release
2023-07-13 - Public Release

Credit

Discovered by Aleksandar Nikolic and Dimitrios Tatsis of Cisco Talos.