Hardening Linux Against Environment Variable Attacks

Understanding Environment Variable Vulnerabilities

Environment variables provide a way for processes to configure their runtime environments. However, malicious actors can take advantage of how Linux handles environment variables to escalate privileges, bypass security controls, or achieve remote code execution. Developers must understand common attack techniques in order to effectively defend against them.

How Malicious Actors Can Exploit Exported Environment Variables

Exported environment variables are inherited by child processes. Attackers can take advantage of this to inject arbitrary code or manipulate the behavior of other programs. Some dangerous environment variables include:

  • LD_PRELOAD – Allows loading arbitrary shared objects before any other shared library. This can be used to intercept functions calls from existing libraries.
  • PERL5LIB – Alters module search path in Perl, allowing remote code execution if Perl scripts are executed from insecure sources.
  • PYTHONPATH – Modifies where Python modules are loaded from, enabling execution of malicious Python code.
  • PATH – Controls the search order for executables. An attacker can place malicious versions of system utilities earlier in the PATH to have them executed instead of the real binaries.

Examples of Attacks via LD_PRELOAD, PERL5LIB, and PYTHONHOME

Some real-world examples of attacks abusing environment variables include:

  • LD_PRELOAD attack to escalate privileges by intercepting sudo function calls.
  • Setting PERL5LIB to load malicious Perl modules containing backdoors.
  • PYTHONPATH manipulation to achieve remote code execution as a privileged user.

These variables provide control over linking, code loading, and module search paths – all leveraged by attackers to sideload malicious payloads or inject unexpected code into legitimate processes.

Limiting Access to Sensitive Environment Variables

To reduce the attack surface, access to particularly sensitive environment variables should be restricted. This can prevent less privileged processes from modifying these variables to inject malicious behavior into running programs.

Restricting Permissions to Modify Key Environment Variable Files

Many environment variables are loaded from startup files like /etc/environment or ~/.bashrc. Write access to these files should be limited only to the root user or individual owners:

# Restrict access to /etc/environment
chmod 644 /etc/environment

# Restrict bashrc only to owner
chmod 700 ~/.bashrc 

This prevents unprivileged users or processes from appending arbitrary environment variable definitions into these startup sources.

Blocking Inheritance of Potentially Dangerous Variables

Whitelisting environment variable inheritance prevents uncontrolled passing of dangerous variables to child processes:

# In /etc/sudoers
Defaults   env_keep += "HOME PATH TERM"

The above sudo configuration only preserves HOME, PATH, and TERM while stripping all other environment variables for sudo commands. This best practice drastically reduces attack surface from inherited environments.

Sanitizing Values of Environment Variables

When environment variable use is necessary, sanitizing their values can also limit attacks by removing dangerous inputs. Some methods include:

Filtering and Validating Variable Content

Before executing any privileged process, scrutinize its environment variables:

filter_env() {
  # Blocklisted strings
  unset ${blocklist[@]}

  # Filter allowed paths
  LD_PRELOAD=$(echo $LD_PRELOAD | grep "/lib/")  

  # Validate safe values
  if [ -z "$PYTHONPATH" ]; then
    export PYTHONPATH="/usr/local/lib/python"
  fi
}

filter_env
sudo ./admin_script.sh

This removes entire blacklist variables, sanitizes allowed values to known-good directories, and sets safe defaults where possible.

Blocklisting Dangerous Values Like External Paths

When filtering variable values, blocklist dangerous inputs like external paths:

# Blocklists
blocklist=(
  LD_PRELOAD
  PERL5LIB
  PYTHONPATH
)

path_blocklist=(
  ".."
  "/"
  "~/.."
)

# Filter implementation
if [[ ":$PATH:" == *":$path_blocklist:"* ]]; then
  echo "Illegal PATH value"
  exit 1 
fi

This denies PATH and other variables from containing directory traversal sequences that could reach unexpected payloads.

Preventing Code Injection Through Environment Variables

Limiting entire classes of attacks via environment variables requires system-wide configurations:

Configuring Execution Permissions in /etc/suid-debug to Block Attacks

The suid-debug feature can selectively disable environment variable attacks like LD_PRELOAD for SUID binaries:

  
LD_PRELOAD=/tmp/evil.so ls = nope
LD_PRELOAD=/tmp/evil.so sudo = nope  

# But normal usage still allowed: 
LD_PRELOAD=/usr/lib64/libmql1.so steam

This denies any attempt to influence SUID binaries with LD_PRELOAD or similar variables by dropping their values. Configure via:

/etc/suid-debug/LD_PRELOAD = 1

Using System Call Filtering with seccomp-bpf

The Linux kernels seccomp-bpf can filter all system calls made by processes within defined policies. Environment variable attacks often rely on executions, code injections, and disc operations.

  
seccomp.blacklist = execve, process_vm_writev, mknod 

docker run --security-opt=seccomp:/path/to/seccomp.blacklist

A strict policy effectively jails the container processes – denying critical system calls required by most attacks leveraging environment variables yet permitting the process to otherwise function safely.

Detecting and Responding To Environment Variable Attacks

Timely detection and diagnosis of attacks abusing environment variables allows rapid incident response.

Analyzing Process Execution Data and Command-Line Arguments

Collecting detailed audit records of all process executions reveals attack attempts trying to inherit manipulated variables:

  
type=SYSCALL msg=audit(1677564124.248:604527): arch=x86_64 syscall=execve success=no exit=-13 a0=68732F6E69622F6C64a1=1 a2=7FFECD2FA2D0 a3=7FFECD2F9F20 items=2 ppid=1 pid=14667 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=5 comm="ldconfig" exe="/usr/bin/ldconfig" subj==unconfined key="ldconfig"

In this case LD_PRELOAD was likely set maliciously prior to execution to intercept library calls from a privileged binary. Analyzing all execve and open syscall patterns reveals privilege escalation efforts.

Identifying Privilege Escalation Attempts in Audit Logs

Centralized logging also enables actual exploitations to be identified post-attack:

type=PROCTITLE msg=audit(1677564299.377:604546): proctitle=2F746D702F746D705F78783B2F746D702F746D705F7878
type=SYSCALL msg=audit(1677564299.377:604546): arch=x86_64 syscall=openat success=yes exit=3 a0=FFFF9C5592317000 a1=2F746D702F746D705F7878 a2=O_WRONLY|O_CREAT|O_TRUNC a3=0x1b6 items=0 ppid=2671 pid=11004 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj==unconfined key="sshd_config"

This unauthorized file write had the SUID bit set, indicating successful privilege escalation likely due to a malicious environment variable influencing bash.

Stopping Suspicious Processes and Restricting Accounts

Once an attack via environment variable is isolated, affected processes should be halted and user accounts disabled as appropriate:

kill -9 1337

usermod -L attacker01
iptables -I INPUT -s 192.168.1.x -j DROP

Rapid containment limits potential damages from exploitation attempts and allows for controlled repair of misconfigurations permitting the breach before resuming operations.

Leave a Reply

Your email address will not be published. Required fields are marked *