Windows: NtUserGetClipboardAccessToken Token Leak
Platform: Windows 8.1 Update (Windows 7 not vulnerable)
Class: Security Bypass/EoP
Summary:
The NtUserGetClipboardAccessToken win32k system call exposes the access token of the last user to lower-privileged users. It can also be used to open an anonymous impersonation thread token which normally OpenThreadToken shouldn't be able to do.
Description:
The NtUserGetClipboardAccessToken method opens a token object which is captured during the NtUserCloseClipboard system call assuming that the caller has written something to the clipboard.
The actual code goes something like:
WinStationObject = GetWindowStation()
if(CaptureToken) {
PACCESS_TOKEN token = PsReferenceImpersonationToken();
if(token == NULL) {
token = PsReferencePrimaryToken();
}
WinStationObject->ClipboardAccessToken = token;
}
and NtUserGetClipboardAcessToken is:
NtUserGetClipboardAccessToken(PHANDLE TokenHandle, ACCESS_MASK Access) {
WinStationObject = GetWindowStation();
ObOpenObjectByPointer(WinStationObject->ClipboardAccessToken, Access, TokenHandle);
}
This has a few implications:
1) It can allow a process to open an Anonymous level impersonation token on a thread, if impersonating that token you can force Win32k to capture the token then read it back, assuming you have permissions to do so. If you call NtOpenThreadToken this would fail. This is only of real significance in the case where there are bugs in handling of impersonation tokens (re: CreateProcessAsUser issue I've already reported).
2) It allows lower IL processes to open the last token to be captured in the same logon session, even if the IL is higher due to policy. For example in the UAC case if an administrator process copies any data to the clipboard it would be possible for a normal privilege process to open the token for read access, then create an impersonation token which can be assigned (as the user matches the current user, and the token IL can be dropped).
Of course all these conditions require access to the token in the DACL and IL levels. However because token objects Mandatory IL policy only defaults to no-write-up you can in many cases open tokens with GENERIC_READ which includes TOKEN_DUPLICATE. Normally the way you would access an existing primary or impersonation token would be through opening the Process or Thread with QUERY_INFORMATION access and opening the token. This would be blocked by lower IL
Probably the most troublesome area where this could be exploitable is in the parts of the sandboxing code of Chrome or Adobe Reader (or similar restricted token sandboxes). For example for various reasons both Chrome GPU processes and Adobe Reader add the logon SID as a restricted SID.
Another possibility is if you could induce a UIAccess process to write data to the clipboard you could access it's token and create a new process (at medium IL) with UIAccess permissions.
IE EPM shouldn't be vulnerable as the token won't have the necessary access to the token object.
There's always a good chance you'll see this as only a UAC style issue, but at least I've reported it. You can choose to apply remediation or not as you see fit.
Proof of Concept:
I’ve provided a PoC which abuses an elevated process which does a clipboard operation to gain admin privileges and write a file. I’d like to stress that I don’t believe this is isolated to elevated process attacks, but of course whether you fix it is entirely up to you.
1) Log in as a UAC admin
2) Execute the Poc_NtUserGetClipboardAccessToken_SecurityBypass.exe
3) Start a process as an administrator (say notepad)
4) Perform a clipboard operation, for example select some text and copy it to the clipboard
5) The PoC should show it has opened a file, you should now find c:\windows\test.txt present on the system
Expected Result:
It shouldn’t be possible to elevate privileges
Observed Result:
It was possible to get an admin token and use that to elevate privileges to write to the windows directory.
This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.