Environment Variables and Attacks Flashcards
Environment Variables
- A set of named-value pairs stored inside each process’s memory
- Part of the operating environment in which a process runs
- Values set by users before program runs
- Programs can use them explicitly or implicitly
- Introduced in Unix and adopted by Microsoft Windows
- Attackers can affect program behavior via environment variables.
- Dangerous for privileged programs
- Example: PATH variable
- Shell process uses it to find program if full path is not provided
Environment Variables - Study Areas
- Where environment variables are stored
- How programs use environment variables
- How environment variables are related to shell variables
How to Access Environment Variables
From the main function:
#include <stdio.h>
void main(int argc, char* argv[], char* envp[]) {
int i = 0;
while (envp[i] != NULL) {
printf("%s\n", envp[i++]);
}
}
Using the global variable:
#include <stdio.h>
extern char** environ;
void main(int argc, char* argv[], char* envp[]) {
int i = 0;
while (environ[i] != NULL) {
printf("%s\n", environ[i++]);
}
}
environ
is more reliable.
Programs can also use:
getenv(var_name)
: find value of environment variableputenv()
: add value to environment variablesetenv()
: modify value of an environment variableunset()
: delete environment variable
How a Process Gets Environment Variables
- Two ways:
fork()
: child process inherits parent's environment variablesexecve()
: memory space is overwritten, old environment variables are lost; can be invoked to pass environment variables.
execve()
and Environment Variables
- Program executes
/usr/bin/env
to print environment variables. - A new variable
newenv
is constructed and used as the 3rd argument.
execve()
Example
$ a.out 1 // Passing NULL
$ a.out 2 // Passing newenv()
AAA=aaa
BBB=bbb
$ a.out 3 // Passing environ
SSH_AGENT_PID=...
GPG_AGENT_INFO=...
TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=...
WINDOWID=...
OLDPWD=...
- Output shows environment variables obtained from the parent process.
Memory Location for Environment Variables
- Stored on the stack of a process's memory.
- Before
main()
is invoked, three blocks of data are pushed onto the stack:- Area 1: Actual strings of environment variables.
- Mark 2: Array of pointers to area 1.
- Area 3: Array of pointers to arguments supplied when the program is run.
- Area 4: Stack frame for the
main()
function.
envp
and environ
point to the same place initially.envp
is accessible inside main()
, while environ
is global.
- Changes to environment variables may move storage to the heap, so
environ
will change (but envp
does not).
Shell Variables vs. Environment Variables
- Shell Variables:
- Internal variables used by a shell program.
- Created, assigned, and deleted using built-in shell commands.
- Environment Variables:
- Copied into shell variables when a shell program starts.
- Changes to shell variables do not affect environment variables.
Shell Variables and Child Processes
- Shell executes programs in child processes.
- Shell program explicitly sets shell variables as environment variables for the new program.
- Bash shell provides two types of shell variables as environment variables:
- Shell variables copied from the parent's environment variables.
- User-defined shell variables marked for export.
- Variables deleted with
unset
will not appear as environment variables in the child process.
Shell Example
- Typing
env
in shell prompt creates a child process. - Only
LOGNAME
and LOGNAME3
get into the child process, but not LOGNAME2
. This is because only exported variables and those inherited from the environment are passed to child processes.
Side Note on The /proc
File System
- Virtual file system in Linux.
- Contains a directory for each process, named with the process ID.
- Each process directory has a virtual file called
environ
, containing the environment of the process. - Example:
/proc/932/environ
contains the environment variables of process 932. strings /proc//environ
prints the environment variables of the current process (shell replaces
with its PID).- When the
env
program is invoked in a bash shell, it runs in a child process. Therefore, it prints the environment variables of the shell's child process, not its own.
Attack Surface on Environment Variables
- Hidden usage of environment variables is dangerous.
- Users can set environment variables, making them part of the attack surface for Set-UID programs.
Attack Surface: Linker
- Linker finds external library functions.
- Out of developer’s control.
- Linkers use environment variables to find libraries.
- Attackers can get privileged programs to find malicious libraries.
Attacks via Dynamic Linker
- Linking finds external library code.
- Done during runtime (dynamic) or compile time (static).
- Dynamic Linking:
- Uses environment variables, which becomes part of the attack surface.
- Static Linking:
- The linker combines the program’s code and the library code.
- Size is significantly larger compared to dynamic linking.
Attacks via Dynamic Linker (cont.)
- Dynamic Linking:
- Linking is done during runtime.
- Uses shared libraries (DLL in Windows).
- Executable is loaded into memory.
- Loader passes control to the dynamic linker.
- Linker finds implementation of functions (e.g.,
printf()
) in shared libraries. - Control is given to
main()
- Use
ldd
command to see shared libraries a program depends on.- Includes
libc
library (e.g., printf()
, sleep()
). - The dynamic linker itself is in a shared library and is invoked before
main()
.
Attacks via Dynamic Linker: Risk
- Dynamic linking saves memory.
- Part of the program’s code is undecided during compilation.
- If the user can influence the missing code, they can compromise the program.
Attacks via Dynamic Linker: Case Study 1
LD_PRELOAD
: List of shared libraries searched first by the linker.LD_LIBRARY_PATH
: If not all functions are found in LD_PRELOAD
, the linker searches folders specified by LD_LIBRARY_PATH
.- Both variables can be set by users, allowing control over the linking process.
- If the program is Set-UID, it may lead to security breaches.
Case Study 1: Normal Programs
- Program calls
sleep()
function, which is dynamically linked. - Implement a custom
sleep()
function. - Compile the code, create a shared library, and add it to the
LD_PRELOAD
environment variable.
Case Study 1: Set-UID Programs
- If the technique works for Set-UID programs, it can be very dangerous.
- Countermeasure:
- Dynamic linker ignores
LD_PRELOAD
and LD_LIBRARY_PATH
when EUID and RUID differ.
Verifying the Countermeasure
- Make a copy of the
env
program and make it Set-UID. - Export
LD_LIBRARY_PATH
and LD_PRELOAD
and run both programs. - The original
env
program will execute normally. - Our
env
program will not use the preloaded library due to the countermeasure.
Attack Surface: External Programs
- A program may invoke external programs for functionalities like sending emails or processing data.
- External program's code runs with the privileges of the calling process.
- The external program may use environment variables not used by the caller.
- Therefore, the entire program's attack surface is expanded and risky.
Attacks via External Program
- Application invokes an external program.
- Application itself may not use environment variables, but the invoked program might.
- Typical ways of invoking external programs:
exec()
family of functions (calls execve()
): runs the program directly.system()
: calls execl()
, which eventually calls execve()
to run /bin/sh
; the shell program then runs the program.
- Attack surfaces differ for these two approaches.
Attacks via External Program: Case Study
- Shell programs are affected by many environment variables, most commonly the
PATH
variable. - When a shell program runs a command without an absolute path, it uses the
PATH
variable to locate the command. - The case study forces a program to execute a malicious program by manipulating the
PATH
variable.
Attacks via External Program: Attack Surfaces
execve()
's attack surface is smaller compared to system()
.execve()
does not invoke shell and is not affected by environment variables.- When invoking external programs in privileged programs, use
execve()
.
Attack Surface: Library
- Most programs invoke functions from external libraries.
- These functions may not be developed for privileged programs.
- May not sanitize environment values.
- If invoked by privileged programs, environment variables used by these functions become part of the attack surface.
Attacks via Library
- Programs often use functions from external libraries.
- If these functions use environment variables, they add to the attack surface.
- Case Study – Locale in UNIX:
- Programs use library functions for translated messages.
- Unix uses
gettext()
and catopen()
in the libc
library.
Attacks via Library (cont.)
- The locale subsystem relies on environment variables:
LANG
, LANGUAGE
, NLSPATH
, LOCPATH
, LC_ALL
, LC_MESSAGES
- These variables can be set by users, so the translated message can be controlled.
- Attackers can use format string vulnerability to format the
printf()
function. - Countermeasure:
- Library author can explicitly check and ignore specific environment variables when called from a Set-UID program (e.g., Conectiva Linux ignoring
NSLPATH
).
Attack Surface: Application Code
- A program may use environment variables in its code.
- Developers may make incorrect assumptions about environment variables.
- Incorrect assumptions lead to incorrect sanitization, resulting in security flaws.
Attacks via Application Code
- Programs may directly use environment variables.
- If these are privileged programs, it may result in untrusted inputs.
Attacks via Application Code (cont.)
- The program uses
getenv()
to get its current directory from the PWD
environment variable. - Copies it into an array “arr” without checking length, leading to a potential buffer overflow.
- Value of
PWD
comes from the shell program. - The shell program updates its shell variable whenever we change the folder.
- We can change the shell variable ourselves.
Attacks via Application Code - Countermeasures
- When environment variables are used by privileged Set-UID programs, they must be sanitized properly.
- Developers may choose to use a secure version of
getenv()
, such as secure_getenv()
. getenv()
searches the environment variable list and returns a pointer to the string found.secure_getenv()
returns NULL
when “secure execution” is required.- Secure execution is defined by conditions like when the process’s user/group EUID and RUID don’t match.
Set-UID Approach vs. Service Approach
- Set-UID Approach: Normal-User Process uses Privileged Process to conduct privileged operations directly.
- Service Approach: Normal User Process requests for service from a Privileged Process, which then conducts privileged operations.
Set-UID Approach vs. Service Approach (cont.)
- Most OSes follow two approaches:
- Set-UID approach: normal users run a special program to gain root privileges temporarily.
- Service approach: normal users request a privileged service to perform actions.
- Set-UID has a broader attack surface caused by environment variables.
- Environment variables cannot be trusted in Set-UID.
- Environment variables can be trusted in the Service approach.
- Due to this reason, Android OS completely removed the Set-UID and Set-GID mechanism.
Summary
- What are environment variables?
- How they get passed from one process to its children.
- How environment variables affect program behaviors.
- Risks introduced by environment variables.
- Case studies.
- Attack surface comparison between Set-UID and service approaches.