Showing posts with label c++. Show all posts
Showing posts with label c++. Show all posts

Thursday, February 9, 2012

Linux terminal keylogger in userspace

Introduction

Sometimes, during a pentest, you have access to a certain system user's password, can actually successfully login on the system(using ssh for example), but cannot gain root privileges. This can be caused due to the fact that the user is not a sudoer, nor is sudo installed on the system, and of course, that the password is not the same as the root user.

However, this user might actually use "su" to become the superuser. In this case, we have access to his settings and configuration files, located in his home directory, which can be modified and used to obtain the root's password.

There are several environment variables that libc uses to modify an application's behaviour when launching it. Among many, there is one that allows the user to load one or more arbitrary shared objects right before launching a certain application. This environment variable is named LD_PRELOAD.

The LD_PRELOAD environment variable

Using LD_PRELOAD, a user can launch an application and force it to load any shared object he wants. So how can we take advantage of LD_PRELOAD? On GNU/Linux, programs are usually compiled dynamically, allowing the symbols used in it to be loaded when the application is launched. When the application is executed, the shared objects that contain the symbols used are loaded, and those symbol's addresses are resolved. Every reference to the loaded symbols will use those addresses.

Fortunately for us, this symbol loading is done after the shared objects pointed by LD_PRELOAD are loaded. Therefore, if we compile a shared object which contains a function that has the same signature(name + return type + arguments) as one that another application expects to resolve, it will use ours instead of the "original" one, allowing us to execute arbitrary code.

Okay, so now we can inject arbitrary code, now how can we use this technique? We could hook the read system call, then wait for the user to launch su. Our object would be loaded and we would be able to read the data typed by the user, in which we will eventually find the root's password.

However, we cannot do this, since su is a suid file. The libc does not allow us to execute an application that has the suid bit set, and instruct it to load our library on startup. If this was possible, we could execute ping, for example, make our shared object load and drop a root shell right away. Therefore LD_PRELOAD + suid binary is not a possibility.

Anyhow, we can use another approach. We can hook the execve syscall, which is used by bash to execute commands, and modify its behaviour. This way we could execute whatever we want, no matter what bash is trying to execute.

The actual keylogger

So what i did was to instead of trying to hook the read syscall and log every byte read by the application, was to hook execve and fork() right before calling the original execve and log the data that is written to stdin(which should be read by the execve'd application) into a file. This way, no matter what was being executed, suid files or regular, we can still read stdin, since we are not hooking the syscall on the executed application, but on bash. My execve is basically a proxy that logs everything that is written to stdin before it is sent to the child process.

Finally, we can read every byte written by the user, but we require bash to load our shared object using the LD_PRELOAD environment variable. We can achieve this by editing(or creating) the ~/.pam_environment file and inserting this line into it:
LD_PRELOAD=FullPathToTheSharedObject
In my case, i have inserted the line:
LD_PRELOAD=/home/matias/key.so
After a restart(or logout performed by the user) that environment variable will be set, loading our shared object everytime bash starts.

Note that we can't edit the .bashrc file, since this file is interpreted by bash after the process is created. What we require is a way of editting the LD_PRELOAD environment variable before bash is started, which can be achieved through ~/.pam_environment.

The source code of this PoC is available here https://github.com/mfontanini/Programs-Scripts/tree/master/keylogger. Download both keylogger.c and Makefile. In order to compile, just execute make, keylogger.so will be the object generated.

This is a screenshot of the keylogger, storing the password and commands typed by the user when executing su:



By default the log file is located in /tmp/output. If you want to change it, just edit the sourcecode and edit the OUTPUT_FILE define, or add a CFLAG to the Makefile:
CFLAGS=-c -Wall -O3 -fPIC -DOUTPUT_FILE=/home/somebody/blah.log
There is an array named injected_files which contains a list of all the files that will be "logged" when executed. This is used because there are lots of applications that we don't want to log. This array contains /bin/su and /usr/bin/ssh. Feel free to add any other application that you want to keylog.

Finally, there's a code snippet at the end of the file which removes the value of the LD_PRELOAD variable right after the shared object is loaded. This is just a mechanism to hide our keylogger. Otherwise, if the user executed "echo $LD_PRELOAD" while using bash, he would see the location of our keylogger as the output. Note that by removing the LD_PRELOAD variable, child processes will not load our shared object, therefore in a GUI environment, where the first application that is executed is gnome-terminal or other graphical terminal, and this application is the one that executes bash, the shared object will be loaded by gnome-terminal, but won't be loaded by bash. Therefore, if you plan on using this keylogger on a GUI environment, remove the body of the "void init(void)" function, located at the end of keylogger.c.

Hope you find it useful!

Sunday, December 4, 2011

Linux rootkit implementation

This is a rootkit i developed some time ago for educational purposes. It has the ability to hide itself from lsmod, hide processes, tcp connections, logged in users and to give uid 0 to any running process. The rootkit does not work on linux kernel >= 3.0.  now works on Linux Kernels >= 3.0 thanks to Dhiru Kholia, who ported it. He also made the proper fixes for the rootkit to compile on CentOS. The rootkit has been successfully tested on kernels >= 2.6.26.

The hiding is performed through file system function hooking. On Linux, every fs driver provides functions to open, read, write and perform operations with files and directories. This functions are stored in a struct file_operations, stored inside every inode. Therefore, every file_operations contains a pointer to the open, read, write(and many other) functions which will be called whenever a user tries to execute those actions on a filesystem object.

So what i did was to retrieve a certain inode and modify the pointer to its read function, replacing it with my own function. In this new function, filtering on the input was performed, in order to remove the entries i wanted to hide.

Let's take for example the connection hiding mechanism. netstat takes tcp connections information from a virtual file named /proc/net/tcp. This file contains one entry per line, each one indicating source and destination port, source and destination address and more information about each open connection. In order to hide a certain connection, i replaced the default read function with my own, in which i read entries on that file and skipped those containing the port i needed to hide.

In order to give orders to the rootkit, i used the same mechanism. I added a write function pointer to the file /proc/buddyinfo, which by default has no write permissions. So after hooking that function, whenever any user writes something to that virtual file, the rootkit will read what was wrote and execute actions based on the input. The commands it supports are the next ones:
  • hide/show. This commands hide/show the rootkit from lsmod(actually from /proc/modules).
  • hsport PORT/ssport PORT. Hides(hsport) connection which have PORT as their source port, or "unhides it"(ssport) if it was previously hidden.
  • hdport PORT/sdport PORT. Same as above but using destination port instead of source.
  • hpid PID/spid PID. Hides or "unhides" a process that has PID as its pid. This is done by hooking the /proc readdir pointer.
  • huser USER/suser USER. This commands hide or "unhide" a logged in user, so that who or other similar commands won't indicate USER is logged in the system. This is done by hooking /var/run/utmp.
  • root PID. This makes the process identified by PID to contain uid 0 and gid 0. This is kind of dirty but works well; the credentials struct from the init process is copied to the process identified by PID.
This is a screenshot showing how the rootkit works, hiding a user, a process, the ssh socket and making the bash process gain root privileges:


You can get the source code https://github.com/mfontanini/Programs-Scripts/tree/master/rootkit. In order to compile it, you require your kernel's headers(on debian-based distributions, this can be found on the package linux-headers-2.6.X.X, where X depend on your kernel version). Download both the Makefile and the source file, and then just execute:
make
insmod rootkit.ko
That's all. Hope you find it useful!