Rapid7 Blog

Remote Keystroke Sniffing with Meterpreter

POST STATS:

SHARE

Earlier this afternoon, I committed some code to allow keystroke sniffing through Meterpreter sessions. This was implemented as set of new commands for the stdapi extension of Meterpreter. Dark Operator, author of many great Meterpreter scripts, already wrote a nice blog post describing how to use the new keystroke sniffer, but I wanted to cover some of the internals and limitations as well.

The keyscan_start command spawns a new thread inside of the process where Meterpreter was injected. This thread allocates a large 1Mb buffer to store captured keystrokes. Every 30 ms, this thread calls GetAsyncKeyState, which returns the up/down status of each of the 256 possible Virtual Key Codes. If a key state change is detected and the new state is down, the key, along with the Shift, Control, and Alt flags are stored into the buffer as 16-bit value. If the entire buffer is used, it skips back to the beginning and overwrites old entries. This poll/compare method is based on a keyboard status application written by Rick, who presented at the last San Antonio Hackers meeting (and presents at Austin Hackers frequently).

One limitation of the GetAsyncKeyState function is that it must have access to the active, input desktop in order to monitor the key states. This presents a problem when the target process is running as a service. In the case of the VNC injection payload, we jump through a series of hoops to get access to the input desktop. This sequence has now been implemented as the grabdesktop command, but this is still not sufficient in many cases. If the service does not have rights to interact with the desktop, no amount of API jumping allows the GetAsyncKeyState function to receive keystrokes from the user.

Fortunately, Meterpreter supports the migrate command, which allows us to move our running code into a process that does have interactive access to the desktop. In the example below, we will use ms08_067_netapi exploit to obtain a Meterpreter shell on a Windows XP SP2 system, then migrate the running payload into the Explorer.exe process owned by the active user. This allows us to then use the keyscan_start and keyscan_dump commands to log the user's keystrokes.