On Tuesday, Tavis Ormandy of Google’s Project Zero released an exploit kit called
ctftool which uses and abuses Microsoft’s Text Services Framework in ways that can effectively get anyone
system that is—on any unpatched Windows 10 system they’re able to log into. The patches for this vulnerability—along with several other serious issues—went out in this week’s Patch Tuesday update.
We independently verified Ormandy’s proof-of-concept, and it’s precisely what it says on the tin: follow the directions and you get an
nt authority\system privileged command prompt a few seconds later. We also independently verified that applying KB4512508 closed the vulnerability. After applying the August security updates, the exploit no longer works.
The full writeup of Ormandy’s findings is fascinating and incredibly technically detailed. The TL;DR version is that Microsoft’s Text Services Framework, which is used to provide multilingual support and has been in place since Windows XP, includes a library called
MSCTF.DLL. (There’s no clear documentation demonstrating what Microsoft intended CTF to stand for, but with the release of this tool, it might as well stand for Capture The Flag.)
The Text Services Framework needs to monitor—and alter—user input to application windows in order to provide language services such as Simplified Chinese (Pinyin). If you install language support for Pinyin, you can see this in action. With language set to Pinyin, you can type in any window and suggestions for Chinese characters that can match either your phonetic typing (or entire words you’ve typed in English) will appear in a sub-menu.
The characters in this sub-menu can be rapidly selected with keyboard shortcuts, which will then replace what you typed with the Chinese characters you selected.
Ormandy didn’t start out looking for problems in the Text Services Framework—all he was really looking for was confirmation that he couldn’t send inter-process messages from an unprivileged process to a privileged process. But when he wrote a test case to send all possible messages to a Notepad.exe instance running as Administrator, he discovered that wasn’t the case: some of his inter-process messages unexpectedly went through.
If I send every possible message to a privileged window from an unprivileged process, the list should match the whitelist in win32k!IsMessageAlwaysAllowedAcrossIL and I can move onto something else.
Ah, I was so naive.Tavis Ormandy, Google Project Zero
Once Ormandy identified the culprit as
MSCTF.DLL, the next step was figuring out what could be done with it. As he discovered, the answer was “pretty much anything you’d like.” The CTF protocol is a legacy system dating back to 2001’s Office XP, which even included support for Windows 98; it was available with the base system beginning with Windows XP itself. There was no access control at all implemented in the protocol—even sandboxed processes could connect to a CTF session outside their sandbox. Clients report their thread ID, process ID, and window handle—but there was no verification and nothing stopping such a client from lying through its teeth to get what it wants.
Making things worse, the CTF protocol allowed a client to call any function pointer in the program it’s referencing… and the CTF protocol . So a client could effectively just keep attacking a target it didn’t know much about without causing it to crash. You might think that Address Space Layout Randomization—a modern security technique which makes predicting where vulnerable parts of an application reside in memory more challenging—would make things more difficult. Unfortunately, you’d be wrong, because as it turns out the CTF marshaling protocol informed you where the monitor’s stack is located.
This would get you into the monitor but wouldn’t yet get you into the client app you actually wanted to own. That process does require repeated trial and error, but that trial and error can be automated in a script. This is exactly what Ormandy’s proof-of-concept script did. When you run
ctf-consent-system.ctf in the tool, it spawns a UAC dialog by using the
runAs verb with a
ShellExecute() command. Once the UAC dialog is present,
ctftool uses the CTF framework to connect to it, probe it, and map its stack, which takes a few seconds. Once that’s done, it calls the internal function in
consent.exe. This indicates that a local user has successfully entered the requested credentials—and Bob’s your uncle; you’ve got an instance of
cmd.exe running as
This vulnerability lurked unacknowledged in the Windows stack for 20 years, and the consequences were even farther reaching than the proof-of-concept exploit—CTF can even be used on unpatched systems to bypass AppContainer Isolation used in the newest and supposedly most-securely-designed applications, such as Microsoft Edge.