# 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: ```c++ /* 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: ```c++ /* 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 ![](https://i.imgur.com/1lKWqS8.png) 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: ```c++ /* 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: ```c++ /* 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.