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:
fork
in C), the child's process inherits all environment variables of parent process since its memory is duplicated from parent's memory.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.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 main categories:
LD_PRELOAD
environment variableDuring 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:
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.
However, if we have an program like this:
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:
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.
PATH
environment variableShell program's behaviour are affected by many environment variables. The most common one is the PATH
environment variable. Consider the following set-uid program:
We can compile and set it as set-uid program by do following commands:
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:
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:
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?
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:
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.
To reduce the vulnerability of environment variables, we have some solution: