Exploiting Shared Library Misconfigurations

Get the practical knowledge of Linux privilege escalation by discussing 3 pentester academy labs on shared library injection. You will realize how dangerous shared library injection is when you find GCC compiler and permission misconfiguration

Exploiting Shared Library Misconfigurations

So far you have learnt about the basic concept of libraries, how the loading works and how hijacking the search order in malicious binary could lead to a complete system takeover Well, that is enough for the exercises I will be discussing today.

Following labs will be discussed one-by-one

LAB: Library Chaos

When I launched this lab and hunted for suid binaries (the very first step), I found one unusual binary /usr/bin/welcome owned by the user and group root.

I wasn't able to run the binary as it is throwing an error that libwelcom.so library not found. On checking with ldd and readelf with -d option it is confirmed that the libwelcome.solibrary is needed by the binary but it doesn't exist in the system, luckily

To check library search order, I started with /etc/ld.so.conf and then I had gone through the files in the /etc/ld.so.conf.d/ directory. There I found one file custom.conf which looked odd to me

I found that the library search also tries to search in /home/student/lib. To confirm this, you can run LD_DEBUG=libs /usr/bin/welcome.

The directory is in direct control of the current logged in user and while loading libraries, it focuses on the load part rather than checking file ownership. So I wrote a malicious code to get an interactive bash shell after setting uid and gid of the root user

#include <stdlib.h>
#include <unistd.h>

void _init() {
    setuid(0);
    setgid(0);
    system("/bin/bash -i");
}

NOTE: I have used _init in this case to demonstrate that can also work if you have an older version of GCC and another toolkit. But I recommend you to use __attribute__((constructor)) instead

If you are new to setuid and setgid, I have a detailed post on this topic – Demystifying SUID and SGID bit and Exploiting SUID Binaries to Get Root User Shell

Now you need to compile the code and save it in /home/student/lib so that ld.so.conf.d/custom.conf should be able find it

$ mkdir -p lib
$ gcc -shared -fPIC -nostartfiles -o lib/libwelcome.so exploit.c

Now run /usr/bin/welcome again and you will get the shell with the root user privileges

LAB: Library Chaos II

When this lab spawned, I checked for suid binaries and found /usr/local/bin/token binary which doesn't look like the usual binary.

Since the $PATH environment variable contains an entry of the /usr/local/bin directory, I can directly execute this binary.

Like in the above lab I discussed, in this case also the library is missing from the system. If that is the case, there might be some way to load or inject the malicious shared library into the process

This time I couldn't find any vulnerability in the /etc/ld.so.conf file and /etc/ld.so.conf.d directory. On checking the dynamic section I found that the file contains RPATH value set to the /tmp/lib/ directory.

Well, that is interesting, as if you recall the precedence of RPATH is higher than ld configs. So if you will create the shared library in /tmp/lib/librandom.so it will try to load that file

Reusing the same code from the above lab here. Run the following set of commands to create the malicious library in RPATH

$ mkdir -p /tmp/lib
$ gcc -shared -fPIC -o /tmp/lib/librandom.so exploit.c

While running the code, I found the symbol is not implemented. Let's try out with a variable.

Add a simple value to the random_token variable.

int random_token = 123456;

Consider it as a litmus paper test, where I am just checking whether the symbol is implemented correctly or not.

And it executed successfully, now add constructor attribute to token function

void token()__attribute__((constructor));

Run the executable again, and this time you will get the shell with the root user privileges

LAB: Load Order Matters

While looking for suid binaries, I found in this case sudo is installed but there are no suspicious suid binary found

On checking sudo privileges for current everything looked OK, but env_keep+=LD_PRELOAD caught my attention. Generally, programs that fork another program, pass the environment variables but in the case of sudo it will only pass the environments when configured in env_keep otherwise it will ignore.

If you are new to sudo or want to refresh your knowledge, I have already written two posts on the topic – Understand Sudo in Linux and Exploiting Sudo Misconfiguration to Get Root Shell

So I wrote the program to call system binary. Since the program will "run as" the root user, thanks to sudo. You can ignore redundantly setuid() and setgid() calls

If you are wondering why I have to unset LD_PRELOAD environment variable before calling system(), read my post on explaining the concepts of shared libraries – Understanding Concept of Shared Libraries

Compile the code using GCC with any name, lib prefix is not required in this and call the apache after specifying an LD_PRELOAD environment variable

$ gcc -shared -fPIC -o inject.so exploit.c
$ sudo LD_PRELOAD=/home/student/inject.so /usr/sbin/apache2

You have seen me in the lab first checking all other options and then if sudo misconfiguration is found, use LD_PRELOAD. Well, I could have used it with suid binary in the first place. but since this would also be executed with the EUID of the root user, it would be child's play to escalate to root privilege. So, LD_PRELOAD cannot be used with setuid. This is a security feature in Linux. However, on a system with Glibc, you can preload a library using another supported way: by adding the library into /etc/ld.so.preload. This one doesn't suffer from the restrictions of LD_PRELOAD.  For more, visit https://stackoverflow.com/questions/9232892/ld-preload-with-setuid-binary