LD_PRELOAD and Environment Variable Hijacking
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:
Look for any of these patterns in the output:
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 for other sudo exploitation paths.
Also check the global sudoers defaults:
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
#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:
-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:
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:
Step 2 — Create a malicious version of one of those libraries:
/tmp/libcrypt.c
#include <stdlib.h>
#include <unistd.h>
void __attribute__((constructor)) init() {
setuid(0);
setgid(0);
system("/bin/bash -p");
}
Step 3 — Run the sudo command with your library directory first:
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:
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:
See https://hackindex.io/platforms/linux/privilege-escalation/python-library-hijacking for the full Python library hijacking technique.
PERL5LIB Injection
Same approach for Perl scripts:
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:
!env_reset disables the reset entirely, making every environment variable available. This is rare but extremely impactful when present.
References
-
ld.so(8) Manualman7.org/linux/man-pages/man8/ld.so.8.html (opens in new tab)
LD_PRELOAD, LD_LIBRARY_PATH behavior and security restrictions.
-
sudoers(5) Manualman7.org/linux/man-pages/man5/sudoers.5.html (opens in new tab)
env_keep, env_reset, and SETENV directive documentation.
Was this helpful?
Your feedback helps improve this page.