Show Notes

206 - A Ghostscript RCE and a Windows Registry Bug

A pretty classic string escaping bug in GhostScript, one common and buggy edge case when escaping characters in a buffer is to not properly account for escapes that happen at the very limit of the destination buffer. As was the case here, despite checking that the limit of the buffer was not reached on every iteration, when a character was found that should be escaped, it would write to the destination buffer write, first with the escape character (0x01) and then again with an XOR’d version of the character to be escaped. If this character was the last character before the end pointer marking the end of the buffer then it would end up writting one byte too far. So by the time the loop condition runs again, it will have written once out of bounds.

This out of bounds write, and related movement of the write ptr beyond the end pointer means later calculations of remaining buffer space are completely incorrect (turn into a negative number/very large position number). Allowing for future filters to overwrite adjacent memory.

A post-auth remote information disclosure in the SecurePoint UTM firewall. The bug in this case is the fact that a session ID can be sent in a response before the session is fully initialized and used. In this case, uninitialized data is sent in the response and can be used to chain with a separate memory corruption to RCE the portal. The authentication requirement comes from the fact that in a typical browser login case, the sessionId is immediately initialized after login and the exploitable condition can’t be triggered.

Project zero found a complex bug in the Windows kernel registry subsystem which create type confusion situations. Windows supports the ability to rename registry keys in place, which is facilitated by the NtRenameKey() syscall. One of the edge cases it has to try to deal with to support this is disallowing name collisions and ensuring users can’t redefine keys to existing key names. The problem is that while they check subkeys, they don’t check keys that have been created but haven’t been committed yet. In this case, it won’t be able to find an existing entry for that key name in the check, but CmRenameKey() will take ownership over the existing key unconditionally, which can cause several problems. The two main ones of interest:

  1. It’s possible for CmRenameKey() to overwrite various parts of the Key Control Block (KCB)
  2. Any errors triggered in the control flow for CmRenameKey() will destroy the KCB with no effort to preserve the state

Triggering memory corruption with this bug involved confusing the key node’s SubKeyCounts[1] which is used when looking up SubKeyLists[1]. By creating two keys and renaming both to a new name, committing the transaction, and subsequently deleting that registry tree, SubKeyLists[1] is set to -1. However, SubKeyCounts[1] is decremented from 0x2 to 0x1, allowing the next delete to attempt to translate -1 into a virtual address, which triggers an exception.

A pretty straightforward out-of-bounds write (OOB write) in the Apple SPU kernel extension, which is used for managing drivers on macOS and iOS. The problem lies in the opcode handler for ALLOCATE_BUFFER messages sent to SPU via an IOUserClient. This opcode allows a user to allocate from one of 16 inline slots inside the AppleSPU object. The problem is, there is no bounds checking to ensure you don’t try to allocate more than 16 buffers, thus giving easy OOB write.