PwnKit, a Win32k Type Confusion, and Binary Ninja 3.0
This was an interesting data based attack all because it was assumed there would be arguments in
argv. A for-loop starts with
n=1 looping until
n < argv. Then after processing the arguments, accessing
argv[n] outside of the loop. Normally this would be pointing to the last argument but when
argc is zero, and the loop never runs and
argv[n] points out of bounds.
This particular issue was actually reported on back in 2013 though it was not exploited at the time. It was noted that they could get as far as having the first environment variable treated as the executable to be started, but without being able to authenticate as root or pass arguments they couldn’t weaponize it.
Which is where PwnKit picks back up, rather than looking at this as just another way of controlling the program that will be executed, they looked at abusing that write-back into
argv[n] as a way of introducing environment variables that would have been stripped by
ld.so (which removes things like
LD_PRELOAD when running setuid binaries so a low-privileged user cannot cause any issues). What Qualys found was that a cleverly named folder and binary name could be used to have it write back a proper environment variable.
Having a folder like
name=. in their
PATH environment, and inside the
name=. folder having a binary named
value would result in the
g_find_program_in_path call returning the string
name=./value which ends up being written into
Using this they could reintroduce sensitive environment values and compromise a privileged setuid binary.
Once again, the use of user-mode callbacks in the Windows kernel enabled an attacker to change out the type of an object unexpectedly leading to a type confusion.
The post indicates that several families of kernel calls (
xxxTooltipWndProc) could be used to trigger the
xxxClientAllocWindowClassExtraBytes callbacks. The callback could then use
NtUserConsoleControl method to set the
ConsoleWindow flag of the
tagWND object. Once the callback returned, the
tagWND object will be accessed, but it will be unaware of the type change that occurred, leading to a type confusion where a user_mode pointer is treated as the offset to the desktop heap, which can be used for more out-of-bound accesses.
There is a bit of a race condition in some areas of kernel code a file that has been closed by userspace will still be accessed by the kernel.
The issue is when
fd_install(fd, file) is called, which exposes the file to the userland and then any further work on
file is attempted. The problem is that as it has been exposed to the userspace, it can be closed by userspace immediately leading to a use-after-free.