102 - Hacking Neural Nets, a Chrome WebRTC UAF and Pwning Windows
A use-after-free in
AddIceCandidate() for adding Interactive Connection Establishment candidates when starting a WebRTC session. The problem is, it’s possible to setup a
Promise that can call
setLocalDescription(), which will mark part of the local description memory for collection by the garbage collector. That memory is used by the
AddIceCandidate() function. Therefore, if you can trigger garbage collection after the promise runs but before
AddIceCandidate() executes, you can trigger a use-after-free which can be taken to code execution.
Race UAF in the Linux kernel. The issue is the
SO_PEERGROUPS socket options don’t maintain ownership / lock when copying
sk->sk_peer_cred to userspace. Other areas that use (or free)
sk_peer_cred, such as unix stream connect and unix listen paths, can free the
sk_peer_cred object before or while it’s being copied. This leads to information disclosure via UAF read. It’s theoretically possible to also obtain an out of bounds write to userspace memory via
SO_PEERGROUPS, but Jann Horn notes that path wouldn’t be viable for LPE, as an attacker wouldn’t have the necessary privileges to switch out the
sk_peer_cred on that socket.
Three vulnerabilities in Qualcomm’s Neural Processing Unit (NPU) driver. Specifically the article focuses on Samsung devices, as, for whatever reason, the NPU device is accessible to untrusted users where it isn’t on most other devices.
Bug 1: UAF in
The first bug has to do with the fact that the NPU driver has to keep track of the various network models that are loaded, and the clients they have. This is for two reasons, one being they need to be able to isolate different clients of the same network from each other. Another being, the driver has to be able to know which client ID to interact with when asynchronous commands (like
npu_exec_network) are used. It does this with a global static array of
network objects, which maintain their own
client reference (and the entire network object) needs to be cleaned up upon the file descriptor’s closure, as those clients will be free’d as well. It does this via
npu_host_cleanup_networks(), which eventually calls
free_network(). The problem is, there’s error paths that can short-circuit that
free_network() call, such as by having an asynchronous command processed while the close path is running. By sending an async
npu_exec_network command and quickly closing the file descriptor, when NPU later finishes the exec task and tries to send a message back to the CPU, it’ll get processed by
app_msg_proc, which will use the (now free’d) client object.
Bug 2: Logic bug in
npu_process_kevent() function is called when an exec network command is finished, and is responsible for copying
stats_buf information to userspace. The pointer to the
stats_buf object is stored in
kevt->reserved. The problem is, when calling
copy_to_user(), instead of using
kevt->reserved for the source pointer, they use
&kevt->preserved. This results in leaking the address of the
stats_buf object rather than the copying the contents.
Bug 3: Uninitialized read in
The final issue was in
app_msg_proc() and it’s use of a union in the
msm_npu_events object (which gets copied to userspace). A union will take the size of it’s largest member, which happens to be a 128-byte auxiliary data buffer. As this buffer is larger than some of the other objects in the union (such as
npu_event_execute_v2_done), trailing bytes get leaked to userspace.
Chaining it all together
The second bug can be used to get controlled data at a known kernel heap address, since the
stats_buf can be controlled by the user and the address gets leaked. This is useful for faking objects and gets around Privileged Access Never (PAN). The third bug can be used to defeat kernel Address Space Layout Randomization (kASLR). The first bug can be used to get a user-controlled pointer (via UAF) to get dereferenced, which eventually has a function pointer that gets called, allowing control flow hijack. By setting up the fake object via the second bug, and leaking the address of a gadget function with the third bug, this can lead to full code execution.
Heap based overflow in the Windows Kernel (ntfs.sys). This was originally found in the wild by Kaspersky, though Alex Plaskett here digs much more into the vulnerability and exploitation, and takes it in bit of a new direction removing the need for a separate info-leak.
The vulnerability itself is in
NtfsQueryEaUserEaList which iterates over a files Extended Attributes and stores their names and values to a user-provided output buffer. It would align the attribute to 32bits, the problem is in the check to ensure the extended attribute would fit in the remaining buffer:
if ( ea_block_size <= out_buf_length - padding )
The problem here is that the
out_buf_length - padding can underflow so the
mememove following it would copy more data than is remaining in the buffer.
On the exploitation front this was taken in a few stages, from the overflow, they targeted some structures from the Windows Notification Facility which they had reasonable control over allocations for when it comes to heap grooming. First was the
WNF_STATE_DATA object which has two fields of importance:
AllocateadSize which can be overflowed, and corrupted leading to a relative read and write respectively as the object will think it has more space than it actually does for both.
With relative r/w a bit more heap grooming was use4d to target
_WNF_NAME_INSTANCE andi its
StateData field for arbitrary write. From this point there are a number of known techniques that can be used.