Show Notes

114 - NetUSB RCE, a Kernel Heap Overflow, & an XNU UAF

Two vulnerabilities in Zoom, a buffer overflow that affected Multi-Media Routers (MMR) servers and client, and an infoleak that only affected MMR servers. Both issues were found in various load_from() methods for serialization classes used in Real-time Transport Protocol (RTP) for audio/video content.

Buffer Overflow Various load_from() methods would allocate a buffer for a string based on the str_len read from the packet, but would then use read_str_with_len() which would read a string into that buffer, ignoring the original allocation size. This allowed an attacker to pass a malformed packet which would provide a size smaller than the string size, allowing an overflow with controlled size.

Uninitialized Read / Infoleak The MMR server’s load_from() would deserialize an object that contained an optional field of a properties table, which mapped name strings to variant objects. Some of these objects were byte arrays that were then converted to strings, however some areas never checked if those strings were null-terminated. One such area was the user_name property. By passing a user_name without a null terminator, uninitialized data could be leaked through the username in the browser.

Two vulnerabilities in Zoom, a buffer overflow that affected Multi-Media Routers (MMR) servers and client, and an infoleak that only affected MMR servers. Both issues were found in various load_from() methods for serialization classes used in Real-time Transport Protocol (RTP) for audio/video content.

Buffer Overflow Various load_from() methods would allocate a buffer for a string based on the str_len read from the packet, but would then use read_str_with_len() which would read a string into that buffer, ignoring the original allocation size. This allowed an attacker to pass a malformed packet which would provide a size smaller than the string size, allowing an overflow with controlled size.

Uninitialized Read / Infoleak The MMR server’s load_from() would deserialize an object that contained an optional field of a properties table, which mapped name strings to variant objects. Some of these objects were byte arrays that were then converted to strings, however some areas never checked if those strings were null-terminated. One such area was the user_name property. By passing a user_name without a null terminator, uninitialized data could be leaked through the username in the browser.

Use-after-free in the ipc_port subsystem of XNU, specifically the ipc_port_copy_send() function. This function would try to copy and send data on an IPC port, and attempts to account for a bunch of edge-cases on the state of the port. For example, if you pass a port that has a sentinel value instead of a pointer (like IP_NULL or IP_DEAD), it would return that same value and bail early. If a pointer is passed to a ‘dead’ port (IP_BITS_ACTIVE flag is cleared), it’ll also return IP_DEAD. Finally, if a valid live port is used, it’ll implicitly bump the reference count on the rights to that port and return a reference.

The problem is, some areas of code (such as ipc_right_copyin_two()) that call this function don’t check the return value, and thus it’s possible that a ‘dead’ port is passed and the reference count on the right is never increased. This is problematic because if the return value is never checked, the right is used and it’s possible some other routine can free it from underneath the caller.

Integer underflow in fs_context.c’s legacy_parse_param() function which was introduced in v5.1. When bounds checking the provided options length, they compare it with system page size - 2 - context data size. The context data size can be controlled by the user, and can exceed system page size - 2. If an attacker passes 4095 for example, the bounds check is rendered useless because it’ll allow SIZE_MAX bytes to be passed. This gives you a size-controlled overflow in the kmalloc-4k cache.

It’s worth noting this vulnerability does require CAP_SYS_ADMIN to exploit, however this capability check can be bypassed by using user namespaces if they’re enabled.

Integer underflow in fs_context.c’s legacy_parse_param() function which was introduced in v5.1. When bounds checking the provided options length, they compare it with system page size - 2 - context data size. The context data size can be controlled by the user, and can exceed system page size - 2. If an attacker passes 4095 for example, the bounds check is rendered useless because it’ll allow SIZE_MAX bytes to be passed. This gives you a size-controlled overflow in the kmalloc-4k cache.

It’s worth noting this vulnerability does require CAP_SYS_ADMIN to exploit, however this capability check can be bypassed by using user namespaces if they’re enabled.

Kernel bug in KCodes’ NetUSB kernel module, which is used by various network device vendors for routers and such. The vulnerability is in the dispatchNormalEPMsgOut() handler for an unlabelled command of 0x805f. A user-supplied size is read from the socket and is added to 0x11 to allocate a heap buffer with kmalloc(). This can be integer overflowed to get a small buffer allocated (kmalloc-32), meanwhile the unadjusted size is used for the copy, allowing heap overflow. Furthermore, this overflow is somewhat controlled because while you would have to pass a very large size, in practice it’ll only copy data up to the received size of the packet, so the amount you overflow is controllable.