TL;DR; you can do the same token stealing trick with UIAccess processes, which doesn't require an elevation prompt, then automate the UI of a privileged process to get a UAC bypass. An example PowerShell script which does this is on my github.
First, what is UIAccess? One of the related features of UAC was User Interface Privilege Isolation (UIPI). UIPI limits the ability of a process interacting with the windows of a higher integrity level process, preventing a malicious application automating a privileged UI to elevate privileges. There's of course some holes which have been discovered over the years but the fundamental principle is sound. However there's a big problem, what about Assistive Technologies? Many people rely on on-screen keyboards, screen readers and the like, they won't work if you can't read and automate the privileged UI. If you're blind does that mean you can't be an administrator? The design Microsoft went with was for a backdoor to UIPI and added a special flag to Access Tokens called UIAccess. When this flag is set most of the UIPI features of WIN32K are relaxed.
From an escalation perspective if you have UIAccess you can automate the windows of a higher integrity process, say an administrator command prompt and use that access to bypass, further, UAC prompts. You can set the UIAccess flag on a token by calling SetTokenInformation and pass the TokenUIAccess information class. If you do that you'll find that you can't set the flag as a normal user, you need SeTcbPrivilege which is typically only granted to SYSTEM. If you need a "God" privilege to set the flag how does UIAccess get set in normal operation?
You need to get the AppInfo service to spawn your process with an appropriate set of flags or just call ShellExecute. As the service runs as SYSTEM with SeTcbPrivilege is can set the UIAccess flag on start up. While the Consent application will spawn for UIAccess no UAC prompt will show (otherwise what's the point?). The AppInfo service spawns admin UAC processes, however by setting the uiAccess attribute in your manifest to true it'll instead spawn your process as UIAccess. However, it's not that simple, as per this link you also need sign the executable (easy as it can be self-signed) but also the executable must be in a secure location such as System32 or Program Files (harder). To prevent a malicious application spawning a UIAccess process, then injecting code into it, the AppInfo service tweaks the integrity of the token to be High (for split-token admin) or the current integrity plus 16 for normal users. This elevated integrity blocks read/write access to the new process.
Of course there are bugs, for example I found one in 2014, since fixed, in the secure location check by abusing directory NTFS named streams. UACME also has an exploit which abuses UIAccess (method 32, based on this blog post) if you can find a writable secure location directory or abuse the existing IFileOperation tricks to write a file into the appropriate location. However, for those keeping score the UIAccess is a property of the access token. As the OS doesn't do anything special to clear it you can open the token from an existing UIAccess process, take it's token and create a new process with that token and start automating the heck out of privileged windows ;-)
In summary here's how to exploit this behavior on a completely default install of Windows 10 RS5 and below.
- Find or start a UIAccess process, such as the on-screen keyboard (OSK.EXE). As AppInfo doesn't prompt for UIAccess this can be done, relatively, silently.
- Open the process for PROCESS_QUERY_LIMITED_INFORMATION access. This is allowed as long as you have any access to the process. This could even be done from a Low integrity process (but not from an AC) although on Windows 10 RS5 some other sandbox mitigations get in the way in the next step, but it should work on Windows 7.
- Open the process token for TOKEN_DUPLICATE access and duplicate the token to a new writable primary token.
- Set the new token's integrity to match your current token's integrity.
- Use the token in CreateProcessAsUser to spawn a new process with the UIAccess flag.
- Automate the UI to your heart's desire.
As an example I've uploaded a PowerShell script which does the attack and uses the SendKeys class to write an arbitrary command to a focused elevated command prompt on the desktop (how you get the command prompt is out of scope).
There's almost certainly other tricks you can do once you've got UIAccess. For example if the administrator has set the "User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop" group policy then it's possible to disable the secure desktop from a UIAccess process and automate the elevation prompt itself.
In conclusion, while the old admin token stealing trick went away it doesn't mean it doesn't still have value. By abusing UIAccess programs we can almost certainly bypass UAC. Of course as it's not a security boundary and is so full of holes I'm not sure anyone cares about it :-)