AB

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 variable
    • putenv(): add value to environment variable
    • setenv(): modify value of an environment variable
    • unset(): delete environment variable

How a Process Gets Environment Variables

  • Two ways:
    • fork(): child process inherits parent's environment variables
    • execve(): 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.