182 - Exploiting Null Derefs and Windows Type COM-fusion
The last time we covered a “how to exploit a null-deref in the modern era” post we were…disappointed (and potentially attacked by North Korea but that’s another story), this one is legit. Rather than focusing on the null-deref as the core memory corruption though, it abuses the handling of the null-dereference with a kernel oops and the side-effects of the oops to overflow a reference count.
Effectively the insight here is that a kernel oops, is a way for the kernel to attempt to recover from an issue without crashing. When an oops happen, the task that caused it will be killed off, and important cleanup code that might usually happen won’t be executed. For example, locks won’t be unlocked, reference counts that were taken won’t be returned, memory can remain allocated.
So, this exploit took a null-dereference in show_smaps_rollup
(triggered by reading /proc/[pid]/smaps_rollup
on a task without no virtual memory address). The corresponding kernel oops would potentially fail to return three reference counts. The one of interest mm_struct
’s mm_users
reference count would be leaked, and as it was a 32-bit counter could reasonably be overflowed. And a reference count overflow can be used to trigger a use-after-free.
The next steps were just to trigger the kernel oops 2^32 times to overflow the reference count, and do so without leaking too much memory every time. You might be wondering how long this might take to exploit.
On server setups that print kernel logging to a serial console, generating 232 kernel oopses takes over 2 years. However on a vanilla Kali Linux box using a graphical interface, a demonstrative proof-of-concept takes only about 8 days to complete!
Another type confusion spawned from the usage of unions. This bug occurred in the COM+ (Component Object Model) event system services’ InMemoryRegRow::PutPropertyBag()
method when handling PROPVARIANT objects (a generic container object that can hold integers or COM pointers). This function will take two PROPVARIANT objects as input which are expected to have a vector of strings and a vector of PROPVARIANTS, but it never actually validates and checks the variant type. They assume the type is going to be the CAPROPVARIANT
they expect. As an attacker, you can supply a VT_BLOB
variant type instead (which points to data you control), which you can use to fake a VT_UNKNOWN
object and eventually get a crafted vtable followed for code execution.
Straight-forward issue, but kinda fun as it impacts the network code in several first-part Nintendo games across multiple consoles (3DS, Wii U, Switch). The NetworkBuffer
in the network library has two methods Add
and Set
which are used to fill the backing buffer with data from the network. None of the methods check that the data actually fits within the network buffer allowing for an overflow with attacker-controlled data.
Exploitation on devices with ASLR should be possible by corrupting the NetworkBuffer
used to send data back to the attacker, however the author focused on Mario Kart 7 (3DS) and Mario Kart 8 (Wii U), neither of which have ASLR present, Without ASLR the exploitation was reasonably straight forward.
They found that the allocated around receiving Mii data would result in the buffer headers and data being placed in contiguous memory. So the overflow from the first buffer could corrupt the header of second buffer. This gave control over the dataPtr
which is where the second buffer would write data to. Providing an arbitrary write primitive.
This primitive could be used to store a ROP payload, and then target the stack to trigger the ROP chain.
Multiple vulnerabilities were announced in Git, the most interesting to me though are the integer overflows in parsing .gitattributes
leading to out-of-bounds reads and writes.
First, the uninteresting. CVE-2022-41953, Git GUI on windows as part of post-processing on a checkout will run a spell-checker if available. It will search for this spell-check tool inside the worktree that was just checked out.
CVE-2022-41903 - Integer Overflow in Padding Operators
This is described as multiple integer overflows can occur when processing a padding operator as part of the “pretty-formats” which are exposed directly in the git log --format
option. But can be accessed through other commands also that perform pretty prettying such as git archive
. Looking at the commits however, most of the fixed issues are indeed integer overflows but the out of bounds reads are other issues.
The first of these out-of-bounds reads is when left-flushing, to do this the code needs to look ahead and see if there are any spaces to be “stolen.” It loops over the string skipping ahead until it finds the first space, it does not respect the buffer’s boundary while doing so.
The second out-of-bounds read is a little more interesting as it has to do with an incomplete update to the code that happened. Prior to supporting truncation in the padding operators the end of the string would be found using strchr
, which would return NULL
if the character in question wasn’t found. Adding support for truncation they also added support for other characters to mark the end, so they used strcspn
which returns the offset in the string to the first character in the selection set, or if none were found, to the NULL
at the end of the string. The conditional following this was not updated to reflect the change in return, it continued to look if the value was NULL
rather than the value it pointed to being NULL
. This mistake results in the end of the token being incorrectly calculated and returned, leading to reading out of bounds later after this function returned.
The out of bounds write in pretty formatting was an integer overflow issue. The struct strbuf
would track length using a size_t
but the code on line 1554 would read the sb->len
into an integer value leading to a potentially incorrect memcpy
shortly there after.
There were several more integer overflows patched in this area, but these three were the most interesting to look at from an exploitation perspective.
CVE-2022-23521 - Multiple Integer Overflows while processing .gitattributes
Again, multiple issues were fixed, but two are interesting to me
The first can result in an out-of-bounds write. This happens when you have too many attribute names present. It can result in a crash just because the xcalloc
call tries to allocate too much memory, but if you provide enough attributes so that the value wraps back to 0 rather than stopping when it goes negative. The xcalloc
on line 384 will allocate too little space for the data written into the buffer a few lines later.
The second is an out-of-bounds read and provides a kinda fun primitive. In attr_stack_free
(starting on L448), the problem is that struct attr_stack->num_matches
is an unsigned value, but the loop iterator i
is a signed int. With a sufficently large num_matches
the iterator will go negative, resulting in trying to read before the attr
array, and then a call to free
with the value that was read. There is potential for a use-after-free if there are other threads running (I’m not sure if there are), but this is basically an infinite free loop as the loop will never terminate since i
cannot be greataer than the num_matches
value.