Code Execution via Insecure Synaptics Section Objects

Edit: Thanks for the comments, I realize this is NOT Lenovo specific problem, it just happened to come pre-loaded on my Lenovo machine.

Alex Ionescu did a cool talk a while back on exploiting unsecured shared memory objects. It sounded like an interesting attack vector to put to use, so I pulled up WinObj on my Lenovo machine and take a look for any ACL-less section objects (section objects are maps of memory that can be shared across applications – leave one of these unsecured and you are leaving yourself open to a 3rd party application able to read and write to it.)

My Lenovo had a memory map called “SynTPAPIMemMap”. Inspecting this via WinObj shows no ACLs – good place to start.

The owner of this memory map turned out to be SynTPEnh.exe, which is spawned at boot by the SynTPEnh service, a Lenovo touchpad utility.

Examining one of the SynTPEnh.exe .dlls in IDA, we can see it is responsible for creating and managing this memory map.

Since any app can read/write to this mapping, all one has to do is find all references made to this memory map and see what choke points best to attack. Out of all the references I found to it, the most promising one was the dll export “RegisterPluginW”, which seems to be called every time the user “clicks” and or even touches the mouse pad at times.

 

When RegisterPluginW is called, I noticed it will iterate over the memory map, setting of my memory breakpoints. The inner function responsible for this is the function I named “RespawnProc” (below).

Examining the RespawnProc function, I see it has the possibility to call the “CreateProcess” function, and whats even more incredible, is the cmdLine parameter for the CreateProcess, is pulled right from the memory map (rbx), which we can control!

To control execution flow where I want, we need to get “WindowCheck” function to return 0. Lets see how we do that…

Inside WindowCheck function

Looking at the function, its relying again on input from the same unsecured memory map. We can get this function to fail by writing invalid handles and invalid process IDs to the buffer its using to store them. This is probably a mechanism to relaunch this window process, in the event it died. Too bad their storing this in an unsecured memory map. To cause this to fail, we need to understand the format of the buffer, and what its all about.

After lightly reverse engineering the memory map, I found the buffer was an array of over 20 TPAPI objects. Highlighted in this memory below is one TPAPI object (Red) and a few important members.

The cmdline member in blue, is used as the CreateProcess parameter. It seems that it should be as simple as rewriting the cmdLine to a process I want to spawn, and setting invalid PID and/or Window Handle members to force the “WindowCheck” function to fail. I only have to worry about doing this to the first TPAPI object, since all will be iterated over upon touch/click and I dont need 27 calc.exe instances popping up.

Here is part of very simple code to trigger this execution.

We execute this code, and the second I move the mouse calc.exe instance is spawned from SynTPEnh process with inherited permissions.

 

What we have now, is the ability for any application able to write to this Lenovo section object to get code execution as the current user’s account, which can be a privilege escalation (depending where you are running from), or it can be an execution divert, in environments you dont want child processes under MS Word for example.