While performing some random research related to the WIN32K.SYS driver syscalls a few months ago, I stumbled on an interesting finding – when examining the full 32-bit (or in the case of the original research – 64) return values, some of the services seemed to return unusual numbers, for example 0xfffffa8000ea0000. After investigating the subject for a while, it turned out that a part of the WIN32K syscall interface indeed does not always return a value of the native CPU size (as opposed to the core NT kernel). Instead, some of the graphical services seem to be explicitly declared as:
VOID NtUserRandomService( ... )
USHORT NtUserRandomService( ... )
Funny enough to find such types of quirks in the Windows kernel, eh? A list of the flawed syscall names is as follows:
ETHREAD (full disclosure)
NtUserSetRipFlags(Windows XP only)
NtUserSetDbgTag(Windows XP only)
- Other (unknown?)
The above list was created based on the Windows 7 64-bit graphical system call table, although I do not guarantee it is by any means complete (system calls might have been added, removed, or altered since then). As can be seen, a user-mode application is primarily able to read the addresses of two, internal kernel-mode structures (assigned to the currently executed thread, thus no serious information disclosure is going on, here). These are:
ETHREAD– the very standard NT kernel structure, assigned to every single thread running in the system,
W32THREAD– an internal, and pretty much unexplored structure, allocated on demand (i.e. when the thread calls a win32k service for the first time). For more details, you’re advised to take a look at the Mysteries of win32k & GDI post on the Woodmann RCE Forums.
In order to confirm the story a little, let’s take a look at the example NtUserGetKeyState system call epilogue:
mov [ecx+48h], edx mov eax, [eax+70h] mov [ecx+4Ch], eax call _LeaveCrit@0 ; LeaveCrit() mov ax, di pop edi pop esi pop ebp retn 4
Clearly, the code doesn’t care about the upper 16 bits of the return value (leading to a partial disclosure) – that’s also the case for the rest of the aforementioned routines. A complete log from a Windows 7 64-bit instance of a Proof of Concept code follows:
--- 64bit Kernel-address disclosure: [+] [ETHREAD] NtUserAlterWindowStyle : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserSetThreadState : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserNotifyWinEvent : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserModifyUserStartupInfoFlags: 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserSetThreadLayoutHandles : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserNotifyIMEStatus : 0xfffffa8000ea80b0 [+] [ETHREAD] NtUserSetThreadLayoutHandles : 0xfffffa8000ea80b0 [+] [W32THREAD] NtGdiEngUnlockSurface : 0xfffff900c216f010 [+] [W32THREAD] NtGdiPATHOBJ_vEnumStartClipLines: 0xfffff900c216f010 [+] [W32THREAD] NtGdiEngDeletePath : 0xfffff900c216f010 [+] [W32THREAD] NtGdiEngDeleteClip : 0xfffff900c216f010 [+] [W32THREAD] NtGdiFONTOBJ_vGetInfo : 0xfffff900c216f010 --- 48bit Kernel-address disclosure (the AX value is uncontrolled): [+] [ETHREAD] NtUserRegisterClassExWOW : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserGetKeyState : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserGetAsyncKeyState : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserVkKeyScanEx : 0xfffffa8000ea0332 [+] [ETHREAD] NtUserSetWindowWord : 0xfffffa8000ea0000 [+] [ETHREAD] NtUserSetClassWord : 0xfffffa8000ea0000
Since the disclosed addresses do not pose a direct threat to the system security, the MSRC team did not consider the issue worth fixing. Well, although I do agree that it’s a minor issue, it is still amusing for me to find such peculiarities in the main Windows graphical kernel module ;) No source code this time, although I do encourage you to fire your IDA and verify the findings by yourself (Windows WIN32K.SYS System Call Table might come in handy).
PS. It seems that I wasn’t the only one coming across this matter – Tavis Ormandy has apparently tweeted about it a year ago, as well ;) Nice one.
PS2. I received the first, valid submission for Pimp CrackMe – a reversing challenge by Gynvael and me (see: link). Well done!
11 thoughts on “Subtle information disclosure in WIN32K.SYS syscall return values”
It would be nice if some win32k syscall handlers allowed to store in rax bytes from a caller-controlled address.
@Crash: Yeah, it would certainly be nice ;)
In such a case, I guess MSRC would take the time and issue a patch, as it’d be quite a robust Information Disclosure vuln (which I think win32k.sys has plenty of, by the way).
useful in a remote ring3->ring0 transition via system call bug; <3 win32k.
Nice post!!!, as jf said, it could be very useful in some scenarios where you need to do a transition ring3->ring0.
@jf @NCR: Yeah, this kind of information might definitely come in handy in ring-0 exploitation ;) There are quite a few curiosities in the kernel user/gdi implementation, more coming soon.
It is worth to note that the ETHREAD address can be currently obtained using a NtQuerySystemInformation(SystemHandleInformation) undocumented call. AFAIK, there’s no such “official” method for the second internal structure, W32THREAD.
This useless information, have a legal way to get a reference to the object:
QueryObject proc uses ebx ObjectHandle:HANDLE, Object:PVOID
Local SystemInformation:PVOID, SystemInformationLength:ULONG
Local HandleInformation[sizeof(SYSTEM_HANDLE_INFORMATION) + 4]:BYTE
invoke ZwQueryInformationProcess, NtCurrentProcess, ProcessBasicInformation, addr ProcessInformation, sizeof(PROCESS_BASIC_INFORMATION), NULL
invoke ZwQuerySystemInformation, SystemHandleInformation, addr HandleInformation, sizeof(SYSTEM_HANDLE_INFORMATION) + 4, addr SystemInformationLength
invoke ZwAllocateVirtualMemory, NtCurrentProcess, addr SystemInformation, 0, addr SystemInformationLength, MEM_COMMIT, PAGE_READWRITE
invoke ZwQuerySystemInformation, SystemHandleInformation, SystemInformation, SystemInformationLength, Eax
mov ecx,dword ptr [edx]
mov dword ptr [ebx],edx
invoke ZwFreeVirtualMemory, NtCurrentProcess, addr SystemInformation, addr SystemInformationLength, MEM_RELEASE
@Indy: Yeah, I do realize that it is possible to retrieve the ETHREAD address by other means (namely, the NtQuerySystemInformation service). I even mentioned it in one of my comment replies:
Comments are closed.