Revisiting an old Apache exploit
My last blog posts were 10 years ago when I was quite active, unfortunately only two previous posts survived various blog service/installation migrations since 2012. In 2022 I have a new years resolution (the norm is 3840 x 2160 in this day and age 😛) to post more of my passion into this site, you may find a lot of things from programming, networking to hacking and everything in between.
Capture-the-Flag
Note: This has been a part of a controlled environment with permission during a competition. Please refer to disclaimer on the about page for more information.
I like to be challenged, I like video games and I absolutely love programming, CTFs wrap all three things into one package, that's why I like CTFs very much. In one of the recent CTFs I was challenged to do a vertical privilege escalation on a Debian machine, this post walks through the privilege escalation on this particular CTF.
The Setup
The challenge already provided me with a user and a password to ssh into the server, during enumeration I have discovered that it was running Apache 2.2.16 among other services running in the system, I tried various techniques including attacking the kernel using Dirty COW to no avail. While this was running an older version of Apache it had to be (CTF-style) intentional, so I went to enumerate what's available on Apache.
First things first, I had to check the list of allowed commands:
And BINGO, there are two items of interest here: environment variables,(especially LD_LIBRARY_PATH
) as well as the /usr/sbin/apache2
NOPASSWD setting for root user; LD_LIBRARY_PATH
provides a list of directories where Apache looks for shared libraries first this means that whenever Apache loads any shared library it looks on this path first before moving elsewhere, I went in to check what are the contents of this path:
Linux Permissions
Now let's revisit the Linux permission structure so we can understand how to exploit this particular vulnerability, in Unix every process has a set of associated numeric user identifiers and group identifiers referred to as UIDs and GIDs, the identifiers are as the ones below:
- real user and group ID
- effective user and group ID
- saved set-user and group ID
- file-system user and group ID (this is specific to Linux)
- supplementary group IDs
For our use case we are interested in the first three user IDs: real user ID, effective user ID and saved set-user ID. Real user ID identifies the user to which the process belongs to, effective user ID along with supplementary group IDs is used to determine the granted permissions to a process when it tries to perform operations and last but not least saved set-user ID allows a process to elevate privileges it would not normally have hence the name "set-user ID".
Now having this information we would try and write a payload that will try to do the following:
- Remove the
LD_LIBRARY_PATH
environment variable so we can set our own path where our modified library is stored. - Try to set real, effective and saved user IDs to root (with numeric value of 0 which is reserved for root).
- Execute the shell and see whether the changes had effect and we get elevated privileges.
In order to achieve the above-mentioned steps, we are going to write a small program that does those, good thing about our system is that it has GCC already installed so we can just spawn vim
and write our code then and there.
First try
We are going to write the following payload in C:
Note: We did not use a main() function here because it is not expected for a shared library that has been compiled with -shared
to be an executable and it won't work, therefore we have aptly named the function elevate_privileges
. In order for this to work we need to initialize a second entry point for apache2 process to recognize.
Now we need to compile this as a shared library and we will be targeting libcrypto
as our target: gcc -o /tmp/libcrypt.so.1 -shared elevate_privileges.c
, we are saving the library on /tmp
because we do not want to keep it, this resulted in an error:
This requires Position Independent Code (hence the instruction to recompile with -fPIC) to be generated, this means not to be dependent on a specific address in memory in order to work, this is required for shared libraries in cases when another project needs to link the said library, hence it requires the Position Independent Code flag to be present, lets add that: gcc -o /tmp/libcrypt.so.1 -shared -fPIC elevate_privileges.c
and this has been compiled correctly, now let's try to load it with the following command: sudo LD_LIBRARY_PATH=/tmp apache2
and this resulted in the following error and no root shell:
The reason for not getting a root shell is because apache2 only sees one entry point which is void main();
and it is the default main function coming by default from GCC itself, for this reason we need to let apache2 know that we have an additional entry point which is our elevate_privileges()
function, in order to do so we have to use GCC's Function Attributes feature by adding __attribute__ ((constructor))
on top of the elevate_privileges
function.
The entire payload code is the following:
The execution log is the following:
Now we can proceed in getting the flag and completing the challenge.