- Exploiting Local Interprocess Command Sockets -
How this came to be:
A few weekends ago I was working through exercises from the folks at Offensive Security when the VPN connection died. ifconfig told me that the tap interface was down, out of habit I fired off netstat to see what other connections were established, something strange stood out. There was a root-owned process listening in the Registered Ports range, the port number didn't ring a bell.
Digging deeper with lsof, the process turned out to be KeepNote, an open source tool used by OffSec students and pentesters alike to organize their notes.
This is the story of how that netstat became a root shell.
Creating the Perfect Storm
The Protocol:The first step in our exploration is figuring out exactly what traffic goes over this socket.
The KeepNote help menu hints of an interprocess command functionality present in the software.
Watching the IPC in action we discover a clear-text protocol with an unknown numeric string common across sessions.
To test whether this string plays a role in authentication and or authorization, we replay the session via a raw socket.
We just might have something here...
The numeric string appears to be the sole authentication mechanism in the protocol, let's track down how it is created.
A look at the source code reveals the following function. We now know that authentication is based off a key space of 1,000,001 pins
The Socket:
Just how feasible it is to brute force this pin, and what controls are in place?
For this we search for instances of the socket listen and accept methods.
Note: Here we discover the port is randomized on process startup.
We have a listen backlog of 1, however, the manner in which connections are accepted in no way prevents brute forcing the pin. Use of the loopback interface lends additional advantage in the form of a speed increase, and elimination of the need to carefully handle timeouts.
The Port:
Port randomization in open_socket() forces us to create a means by which to reliably map the PID to a PORT number. Many of you will shout: netstat, lsof, ss, ps, fuser! If you explore these solutions you’ll find the -p flag and process to socket information is not available to non-privileged users.We grep /proc for potential representations of the port number and find hex representing the socket pair present in /proc/<pid>/net/tcp. We are able to leverage state information in the file to further identify the socket. From the enum in tcp_states.h we know 0A represents a
TCP_LISTEN state.We now have everything we need to discover, map, and crack the IPC pin. Onward to code execution!
The Commands:
After some exploration, leveraging extension installation functionality seems the most likely path to execution of code.
Reviewing the code, there appears to be an "Extension" class inherited from keepnote.gui.extension.Extension, we choose this as our target for execution.
By poisoning the __init__ method of this class, we can gain execution when an instance of the class is created. Importantly, we do so with low likelihood of disrupting normal execution flow.
The Payload:
Our first attempt at using the install command results in a user prompt. We could social engineer the interaction as follows, but this is less than ideal:
Digging for alternate ways to instantiate an extension, we find on_temp_extension(). This function initializes a single session extension instance without user interaction. It lacks functionality to unpack our archive, so we'll need to extract the extension contents ourselves.
User interaction required.
Silent extension installation.
The Mitigation:
In order to mitigate this attack, I recommend starting KeepNote with the --newproc flag. Use of this flag will prevent the command socket from being created. As the project does not appear to be under active development, and exposure to this vulnerability is rather low, turning off the IPC socket will be an acceptable mitigation for most users.
I have contacted the primary author of the project out of courtesy.
Note, this blog is in no way a commentary on the competency of the authors of the project, many of whom I'm certain are more capable developers than myself; thanks for the great software folks!
The Exploit:
Code available at: https://github.com/themson/keepUP
Note: I've also written a threaded version of this POC, however, under Python 2.7.* the GIL drastically impacts the speed of the attack. A speed increase can be had by leveraging taskset to force process affinity to one core, however, if speed is a major concern, C is the answer.
Enough Talk, uid=0 Time!
Hijacking the KeepNote IPC socket to execute arbitrary code.
In order to demonstrate this vulnerability, we create a user with no privileged group membership or sudoer privileges. We then use this account to exploit the IPC socket, gaining a root shell.
In order to demonstrate this vulnerability, we create a user with no privileged group membership or sudoer privileges. We then use this account to exploit the IPC socket, gaining a root shell.
Map, Crack, Hijack, Escalate
We can now hijack any account with an exposed KeepNote IPC socket.
Go learn something ...
@ThemsonMester
Cited Resources:
https://github.com/brotchie/keepnote
https://docs.python.org/2/library/socket.html#socket.socket.listen
https://docs.python.org/2/library/random.html#random.randint
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp_states.h
https://github.com/mdrasmus/keepnote-extensions
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574%28v=vs.85%29.aspx
http://www.advancedlinuxprogramming.com/alp-folder/alp-ch05-ipc.pdf
http://patorjk.com/software/taag/