Authorized environments only. Read Legal & Ethics and OPSEC Plan before any engagement. This SOP covers defensive assessment, hardening validation, and non-destructive privilege-escalation enumeration.


Table of Contents

  1. Engagement Setup
  2. Information Gathering (Read-Only)
  3. Configuration Review
  4. Privilege Escalation Vectors (Non-Destructive Checks)
  5. Logging & Monitoring Review
  6. Network Security
  7. Automated Enumeration Tools
  8. Common Misconfigurations Checklist
  9. Evidence Collection
  10. Reporting
  11. Safety & Legal
  12. Tools Reference
  13. Common Pitfalls
  14. Reference Resources

Pre-Engagement & Authorization

Linux LPE work is inherently destabilizing — kernel exploits panic boxes, container escapes cross trust boundaries, and persistence primitives outlive the engagement window. Pin specifics in writing before any tool from §7 runs against an in-scope host. The “Pre-Engagement” checklist inside §1 below covers engagement kickoff; this section adds the Linux-specific abuse-surface authorization an LPE engagement actually needs.

Authorization Checklist

  • Kernel-exploit detonation scope — explicit per-CVE authorization for any LPE PoC binary (PwnKit / DirtyPipe / GameOver(lay) / Looney Tunables / nf_tables UAF / Leaky Vessels), tied to a captured uname -a + distro snapshot taken at engagement start. Public PoCs on production are out-of-scope by default.
  • Container escape boundary — explicit host-vs-guest authorization. runc Leaky Vessels (CVE-2024-21626), cgroup release_agent escape, Docker / containerd / podman socket abuse, and Kubernetes service-account-token use all cross the container/host boundary; if the host is out of scope, escape PoCs stop at proof-of-namespace-break.
  • /etc/passwd / /etc/shadow modification scope — read-only enumeration is in scope; write access (adding a UID 0 row, exfiltrating /etc/shadow for offline cracking) requires written sign-off and a backup snapshot.
  • Sudo / sudoedit policy abuse — capturing sudo -l output is enumeration; chaining NOPASSWD entries via GTFOBins or detonating CVE-2023-22809 / CVE-2021-3156 is exploitation and must be named in the SoW.
  • SUID binary modification — auditing the existing SUID set is in scope; creating new SUID bits (chmod +s …) or modifying baseline SUID binaries requires explicit permission plus a documented revert step.
  • NFS / SMB / CIFS share write authorizationshowmount -e and no_root_squash flag-grep are read-only; writing a SUID payload to a no_root_squash export needs sign-off from the share owner, not just the host owner.
  • systemd unit / cron / timer write authorization — dropping a .service, .timer, .socket, lingering ~/.config/systemd/user/ unit, or /etc/cron.*/ file creates persistence and must be named, time-boxed, and registered for cleanup.
  • Jurisdictional + safe-harbor framing — see Legal & Ethics (canonical) for CFAA / Computer Misuse Act framing; bug-bounty engagements: confirm the program’s safe-harbor language covers Linux LPE explicitly (some VDPs scope to web-only).

Lab Environment Requirements

  • Distro + kernel version-matched lab VM. Kernel CVE PoCs are pinned at the patch level — Ubuntu 22.04 with kernel 5.15.0-67 is not the same target as 5.15.0-101 even though both report 5.15.0 to uname -r. Snapshot the target’s cat /etc/os-release, uname -a, ldd --version, sudo --version, pkexec --version, and runc --version before staging the lab.
  • Throwaway VM snapshot before any kernel-exploit detonation. Public LPE PoCs panic the kernel on near-miss versions or leave the box unbootable; reproduce in a snapshotted VM, never on the live target.
  • Container runtime version-matched for Leaky Vessels (CVE-2024-21626) testing. runc, containerd, and the Docker engine bundle runc independently — Docker 25.0.2 / containerd 1.7.13 / runc 1.1.12 are the patched baseline; match the target’s bundled set exactly in the lab.
  • Capability-aware lab container. Validate container-escape primitives in a lab container that mirrors the in-scope target’s --cap-add / --privileged / --security-opt / mount set; capability differences silently change which primitives work.
  • GTFOBins coverage spot-check pre-engagement. Before reporting a sudo / SUID / capability finding as exploitable, verify the binary appears on GTFOBins with the relevant primitive — many baseline binaries look exploitable but lack a public escalation gadget.
  • Operator-side OPSEC. No curl … | sh from a target you do not control (see §7 note); download to a throwaway path, sha256sum, inspect, then run. Tool artifacts (LinPEAS output, pspy logs, captured /etc/shadow) are sensitive — store, transport, and destroy per OPSEC Plan.

Disclosure-Ready Posture

  • Baseline before touching anything. At engagement start capture: linpeas.sh -a > linpeas.baseline.out, lse.sh -l 2 -i > lse.baseline.out, sudo -l > sudo-policy.baseline.out, getcap -r / 2>/dev/null > caps.baseline.out, full find / -perm -4000 -ls > suid.baseline.out SUID inventory. The disclosure delta (what you changed) is meaningless without the baseline.
  • Activity timeline. Run pspy and/or auditd (where authorized) for the duration of active testing so the sysadmin can correlate test activity to alerts post-engagement; capture journalctl -u auditd --since "<engagement-start ISO-8601>" at hand-off.
  • Do NOT wipe history in scope unless explicitly authorized. ~/.bash_history, ~/.zsh_history, lastb, journald, and /var/log/auth.log are evidence — wiping them is itself a finding that must be disclosed. Use a dedicated operator account or unset HISTFILE rather than scrubbing after the fact.
  • Sudoers + capability state snapshot. Sudoers (mode 440 root-owned) and file capabilities change rarely, but the sudo -l policy and getcap -r / output that were in effect during the test must be in the report — otherwise reproducibility is lost when sysadmins later tighten the rules.
  • Container runtime + image digest snapshot. Record docker info --format '{{.RuncVersion}}', image digest (docker inspect --format '{{.Image}}' <ctr>), and kubectl version so findings tie back to a reproducible runtime build.
  • Evidence pack + final report routing. Stage evidence per the Collection Log hash-and-timestamp pattern referenced in §9 below; final disclosure pack (executive summary, technical detail, IOC defanging, remediation timeline) follows Disclosure.

1. Engagement Setup

Pre-Engagement

  • Obtain written authorization (signed Rules of Engagement)
  • Define scope: hosts, subnets, services, user accounts
  • Set time windows and blackout periods
  • Establish emergency contacts and escalation path
  • Agree on change control procedures
  • Confirm backup/restore process exists

Objectives (Examples)

  • Identify misconfigurations enabling unauthorized access or privilege escalation
  • Validate hardening baseline compliance (CIS, STIG, etc.)
  • Test privilege separation and access controls
  • Evaluate logging/monitoring efficacy

2. Information Gathering (Read-Only)

System Identification

# OS version and kernel
uname -a
cat /etc/os-release
cat /etc/*-release
hostnamectl
 
# Kernel version (for known vuln research)
uname -r

User & Group Enumeration

# List all users
cat /etc/passwd
cut -d: -f1 /etc/passwd
 
# Users with login shells
grep -v "/nologin\|/false" /etc/passwd
 
# Check for UID 0 (root-equivalent) accounts
awk -F: '$3 == 0 {print $1}' /etc/passwd
 
# Group memberships
cat /etc/group
groups <username>
 
# Sudo access
sudo -l
cat /etc/sudoers
ls -la /etc/sudoers.d/
 
# Recently modified user accounts
ls -lat /home/

Running Services & Network

# Active services
systemctl list-units --type=service --state=running
ps aux
 
# Network listeners
ss -tulnp
netstat -tulnp
 
# Firewall status
sudo iptables -L -n -v
sudo ufw status verbose
sudo firewall-cmd --list-all
 
# Check for unusual binds (0.0.0.0 vs localhost)
ss -tulnp | grep "0.0.0.0"

Installed Packages

# Debian/Ubuntu
dpkg -l
apt list --installed
 
# RHEL/CentOS
rpm -qa
yum list installed
 
# Check for outdated packages
apt list --upgradable  # Debian/Ubuntu
yum check-update       # RHEL/CentOS
 
# Look for unnecessary packages (compilers, dev tools on prod)
dpkg -l | grep -E "gcc|g\+\+|build-essential|python-dev"

3. Configuration Review

File & Directory Permissions

Sensitive files to check:

# SSH configuration
ls -la /etc/ssh/sshd_config
cat /etc/ssh/sshd_config | grep -E "PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|PermitEmptyPasswords"
 
# Shadow file (should be 600 or 640)
ls -la /etc/shadow
 
# Sudoers (should be 440)
ls -la /etc/sudoers
ls -la /etc/sudoers.d/
 
# Cron files
ls -la /etc/cron*
ls -la /var/spool/cron/crontabs/
 
# World-writable files (dangerous)
find / -type f -perm -002 -ls 2>/dev/null
 
# World-writable directories
find / -type d -perm -002 -ls 2>/dev/null
 
# SUID/SGID binaries (privilege escalation vectors)
find / -type f \( -perm -4000 -o -perm -2000 \) -ls 2>/dev/null
 
# Files owned by users but writable by others
find / -type f -perm -o+w -ls 2>/dev/null

SSH Hardening Checks

# Show effective sshd config (resolves Match/Include blocks)
sudo sshd -T 2>/dev/null | grep -Ei "permitroot|passwordauth|permitempty|kbdinteract|maxauth|kex|ciphers|macs|allowusers|allowgroups|x11|tcpforward|gatewayports|allowagent|clientalive"
 
# Per-directive checks (raw config; does not honor Match)
grep -Ei "^PermitRootLogin"            /etc/ssh/sshd_config   # expected: no  (or prohibit-password if using key-only root mgmt)
grep -Ei "^PasswordAuthentication"     /etc/ssh/sshd_config   # expected: no  when keys are mandatory
grep -Ei "^KbdInteractiveAuthentication|^ChallengeResponseAuthentication" /etc/ssh/sshd_config  # expected: no
grep -Ei "^PermitEmptyPasswords"       /etc/ssh/sshd_config   # expected: no
grep -Ei "^MaxAuthTries"               /etc/ssh/sshd_config   # expected: <= 4
grep -Ei "^LoginGraceTime"             /etc/ssh/sshd_config   # expected: 60 or less
grep -Ei "^X11Forwarding"              /etc/ssh/sshd_config   # expected: no unless required
grep -Ei "^AllowAgentForwarding"       /etc/ssh/sshd_config   # expected: no unless required
grep -Ei "^AllowTcpForwarding"         /etc/ssh/sshd_config   # expected: no unless required
grep -Ei "^GatewayPorts"               /etc/ssh/sshd_config   # expected: no
grep -Ei "^Allow(Users|Groups)|^Deny(Users|Groups)" /etc/ssh/sshd_config  # principle of least access
 
# Algorithm strength (Mozilla "Modern" / "Intermediate" baselines)
grep -Ei "^KexAlgorithms|^Ciphers|^MACs|^HostKeyAlgorithms|^PubkeyAcceptedAlgorithms" /etc/ssh/sshd_config
 
# NOTE: SSH protocol 1 was removed from OpenSSH 7.6 (Oct 2017). The legacy
# "Protocol 2" directive is unparsed in modern sshd; do not rely on its absence.
 
# External audit (recommended; --policy=mozilla_modern or --policy=mozilla_intermediate)
ssh-audit <target_host>            # github.com/jtesta/ssh-audit
 
# Inventory authorized_keys (per-user, including root and service accounts)
sudo find / -xdev -name "authorized_keys*" -ls 2>/dev/null
# Inspect specific files only after scoping; printing keys to stdout is logged

Sudo Policy Review

# Check sudoers for NOPASSWD (dangerous)
sudo grep NOPASSWD /etc/sudoers /etc/sudoers.d/*
 
# Check for overly permissive sudo (ALL=(ALL) ALL)
sudo grep "ALL=(ALL)" /etc/sudoers /etc/sudoers.d/*
 
# Users in sudo/wheel group
getent group sudo
getent group wheel

Service Configuration

# Apache (Debian path /etc/apache2 ; RHEL path /etc/httpd)
grep -RIE "Indexes|ServerTokens|ServerSignature|TraceEnable" /etc/apache2/ /etc/httpd/ 2>/dev/null
# Expected: -Indexes, ServerTokens Prod, ServerSignature Off, TraceEnable Off
 
# Nginx
grep -RIE "server_tokens|autoindex|ssl_protocols|ssl_ciphers" /etc/nginx/ 2>/dev/null
# Expected: server_tokens off; autoindex off; TLS 1.2/1.3 only
 
# Check running services on unexpected ports (anything not on loopback)
ss -tulnp | awk 'NR==1 || ($5 !~ /^127\./ && $5 !~ /^\[::1\]/)'
 
# Check for credentials in config files (skip binary matches and avoid /proc)
sudo grep -RIin --exclude-dir={proc,sys} -E "password|passwd|secret|api[_-]?key|token" /etc/ 2>/dev/null | head -50

4. Privilege Escalation Vectors (Non-Destructive Checks)

PATH Hijacking

# Check PATH for writable directories
echo $PATH | tr ':' '\n' | while read dir; do ls -ld "$dir" 2>/dev/null; done
 
# Check if current directory (.) is in PATH (dangerous)
echo $PATH | grep -E "^\.:|:\.:|\.$"

Writable Scripts/Binaries in Privileged Locations

# Check if user can write to system binaries
find /usr/bin /usr/sbin /bin /sbin -writable 2>/dev/null
 
# Check for writable scripts called by root cron
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.daily/

Kernel & userland LPE (Version Check Only)

Only enumerate. Do not run public exploit binaries on production hosts — many are noisy, panic-prone, or backdoored. If exploitation is in scope, copy the host kernel/glibc/sudo/polkit versions into a sandbox and reproduce there.

# Distribution + kernel + relevant userland (sudo, glibc, polkit, runc)
cat /etc/os-release
uname -a                                    # kernel version + build
ldd --version | head -1                     # glibc
sudo --version | head -1                    # sudo
pkexec --version 2>/dev/null                # polkit
runc --version 2>/dev/null                  # container runtime
 
# Auditing tools (read-only, heuristic)
linux-exploit-suggester.sh                  # github.com/The-Z-Labs/linux-exploit-suggester
linux-exploit-suggester-2.pl                # github.com/jondonas/linux-exploit-suggester-2
 
# Installed kernels (multi-kernel hosts may boot a stale image)
dpkg -l | grep -E "^ii\s+linux-image"       # Debian/Ubuntu
rpm -qa | grep -E "^kernel-"                # RHEL/Fedora

Recent illustrative LPE primitives (verify each against the running kernel/userland — most distros ship patches):

CVEComponentTrigger surfaceQuick check
CVE-2021-4034 (PwnKit)polkit pkexecSUID pkexec + crafted argv/envls -l $(which pkexec) ; pkexec --version (polkit < 0.120 likely vuln)
CVE-2022-0847 (DirtyPipe)Linux kernel 5.8–5.16.xsplice() into pipe, write to read-only fileuname -r in vulnerable range
CVE-2023-2640 / CVE-2023-32629 (GameOver(lay))Ubuntu OverlayFSUbuntu-shipped OverlayFS patcheslsb_release -a Ubuntu + kernel 5.4–6.5 ; `mount
CVE-2023-4911 (Looney Tunables)glibc ld.so GLIBC_TUNABLESBuffer overflow when SUID binary processes envldd --version (glibc 2.34–2.38 unpatched)
CVE-2023-22809 (sudoedit env-var)sudo 1.8.0–1.9.12p1EDITOR/VISUAL/SUDO_EDITOR argv injectionsudo --version ; sudo -l shows sudoedit rule
CVE-2021-3156 (Baron Samedit)sudo 1.8.2–1.9.5p1Heap overflow via sudoedit -s argvsudo --version ; reproduce only in sandbox
CVE-2023-32233Linux kernel nf_tables ≤ 6.3.1Anonymous-set UAFuname -r + `lsmod
CVE-2024-1086Linux kernel nf_tables 5.14–6.7.1UAF via nft_verdict_inituname -r + `lsmod
CVE-2024-21626 (Leaky Vessels)runc ≤ 1.1.11FD leak → host filesystem in containerrunc --version ; container engines bundle runc — check Docker/containerd build

[verify 2026-04-25] Each row’s “fixed in” version differs per distro back-port. Cross-check with the vendor security tracker (https://ubuntu.com/security/cves, https://access.redhat.com/security/cve/<id>, https://security-tracker.debian.org/tracker/<id>).

Capabilities (Linux File Capabilities)

# File capabilities across the entire mounted filesystem
getcap -r / 2>/dev/null
 
# Capabilities of the current process / shell / a target PID
capsh --print
getpcaps $$
getpcaps <pid>
 
# Per-thread capabilities (CapEff/CapPrm/CapBnd as bitmaps — decode with capsh)
grep ^Cap /proc/self/status
capsh --decode=$(awk '/^CapEff/{print $2}' /proc/self/status)

Dangerous capabilities (single-cap → root) — most have a documented GTFOBins-style escalation path; cross-reference GTFOBins → Capabilities:

CapabilityWhy it’s root-equivalent
cap_setuid / cap_setgidDirect UID/GID change inside scripted interpreters that hold the cap
cap_dac_overrideBypass file read/write/execute permission checks (read /etc/shadow)
cap_dac_read_searchBypass file read + directory search checks
cap_chown / cap_fownerRe-own arbitrary files (chown root:root + chmod +s)
cap_sys_adminEffectively root: mount, BPF, kernel module ops, namespace setup
cap_sys_ptraceAttach to root processes; inject shellcode
cap_sys_moduleLoad kernel modules (drop a malicious .ko)
cap_net_admin + cap_net_rawNetwork reconfiguration, raw sockets, ARP/DNS poisoning
cap_sys_chroot + writable host pathsCombine with mount tricks to escape
cap_bpf (kernel ≥ 5.8)Load BPF programs without cap_sys_admin

T1548.001 (SUID/SGID), T1574.012 (Linux File and Directory Permissions Modification — capabilities subset).

Container & runtime escape (If Applicable)

# Am I in a container?  (any of the following is a strong signal)
ls -la /.dockerenv /.containerenv 2>/dev/null
grep -E "docker|kubepods|containerd|lxc|crio" /proc/1/cgroup /proc/self/cgroup 2>/dev/null
grep -qE "container=" /proc/1/environ && echo "systemd-nspawn/podman"
cat /proc/1/sched | head -1                  # PID 1 not "init"/"systemd" → container
 
# What kind?  (orchestrator hints)
mount | grep -E "overlay|aufs|fuse-overlayfs"
ls /var/run/secrets/kubernetes.io/serviceaccount/ 2>/dev/null   # K8s pod
env | grep -E "KUBERNETES_|HOSTNAME|HOST_IP"
# === Docker socket mounted into container (host control plane exposed) ===
ls -la /var/run/docker.sock /run/docker.sock 2>/dev/null
# If readable, the container can drive the host's Docker daemon and request
# a new container with the host root mounted — equivalent to root on host.
# Equivalent for containerd / nerdctl / podman sockets:
ls -la /run/containerd/containerd.sock /run/podman/podman.sock 2>/dev/null
 
# === User in `docker` group (host) ===
id ; groups | grep -qw docker && echo "docker group → root-equivalent on host"
 
# === Privileged or over-capabilitied containers ===
# Inside container: check own capability set
capsh --print | grep -E "cap_sys_admin|cap_sys_module|cap_sys_ptrace|cap_dac_read_search"
# CAP_SYS_ADMIN + writable cgroup v1 → release_agent escape (legacy primitive)
 
# === runc / Leaky Vessels (CVE-2024-21626) ===
runc --version 2>/dev/null
docker info --format '{{.RuncVersion}}' 2>/dev/null
# runc ≤ 1.1.11 → FD leak escape; Docker engines bundle runc — patched in
# Docker 25.0.2 / containerd 1.7.13 / runc 1.1.12. Verify host build.
 
# === Kubernetes pod context ===
SA=/var/run/secrets/kubernetes.io/serviceaccount
[ -d "$SA" ] && { cat "$SA/namespace"; head -c40 "$SA/token"; echo; cat "$SA/ca.crt" | head -2; }
# With token + API server reachable: `kubectl auth can-i --list` (requires kubectl in image
# or curl-able API). Look for: pods/exec, secrets, nodes/proxy, clusterrolebindings.

T1611 (Escape to Host), T1610 (Deploy Container), T1613 (Container and Resource Discovery).

Sudo policy & sudo CVE surface

# Effective sudo policy for current user (-n returns non-zero if a password is needed → still informative)
sudo -n -l 2>&1 || sudo -l
 
# Look for sudoers entries that map to GTFOBins escalation
sudo -l | grep -E "NOPASSWD|\(ALL\)|\(root\)|sudoedit"
 
# sudo binary version (compare against CVEs in the LPE table above)
sudo --version | head -1
 
# Sudoers files referenced (read-only — these are mode 440 root-owned)
sudo cat /etc/sudoers /etc/sudoers.d/* 2>/dev/null | grep -vE "^\s*#|^\s*$"
 
# Quick GTFOBins lookup for any binary in your sudo policy:
#   https://gtfobins.github.io/#<binary>+sudo

Polkit / pkexec

pkexec --version 2>/dev/null              # PwnKit fixed in polkit 0.120 / distro back-ports
ls -l $(command -v pkexec)                # SUID root — present on most desktop installs
pkaction | head -20                       # registered actions (look for org.freedesktop.policykit.exec)
ls /etc/polkit-1/rules.d/ /usr/share/polkit-1/actions/ 2>/dev/null

systemd unit & timer abuse

# Writable units (override files in /etc/systemd are loaded with priority over /lib/systemd)
sudo find /etc/systemd /lib/systemd /run/systemd -type f \( -name "*.service" -o -name "*.timer" -o -name "*.socket" \) -writable 2>/dev/null
 
# Enumerate timers — alternative scheduler to cron
systemctl list-timers --all --no-pager
systemctl list-unit-files --type=service --state=enabled --no-pager
 
# User-level (lingering) units run as that user when enabled with `loginctl enable-linger`
ls -la ~/.config/systemd/user/ 2>/dev/null
loginctl list-users

NFS Shares (Privilege Escalation)

# Check for NFS exports
cat /etc/exports 2>/dev/null
showmount -e <server> 2>/dev/null
 
# Look for no_root_squash (mount as remote root, drop SUID shell, exec as local user)
grep -E "no_root_squash|no_all_squash|insecure" /etc/exports 2>/dev/null

5. Logging & Monitoring Review

Check Logging Status

# Syslog/rsyslog status
systemctl status rsyslog
systemctl status syslog-ng
 
# Auth log (login attempts, sudo usage)
tail -100 /var/log/auth.log      # Debian/Ubuntu
tail -100 /var/log/secure         # RHEL/CentOS
 
# Check for log rotation
cat /etc/logrotate.conf
ls /etc/logrotate.d/
 
# Check log permissions (should not be world-readable)
ls -la /var/log/

Audit Daemon (auditd)

# Check if auditd is running
systemctl status auditd
 
# Review audit rules
auditctl -l
 
# Check for monitoring of sensitive files
auditctl -l | grep -E "/etc/passwd|/etc/shadow|/etc/sudoers"

Failed Login Attempts

# Check for brute force attempts
grep "Failed password" /var/log/auth.log | tail -50
 
# Count failed logins by IP
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn

6. Network Security

Firewall Configuration

# Check firewall status
sudo iptables -L -v -n
sudo ufw status verbose
sudo firewall-cmd --list-all
 
# Look for overly permissive rules (ACCEPT all, 0.0.0.0/0)
sudo iptables -L -v -n | grep "ACCEPT.*0.0.0.0/0"

Exposed Services

# Check what's listening externally (not just localhost)
ss -tulnp | grep -v "127.0.0.1"
 
# Scan from external perspective (if authorized)
nmap -sV -p- <target_ip>

7. Automated Enumeration Tools

Always download to disk and inspect before piping curl | sh on a target you do not control. The snippets below assume an authorized lab.

LinPEAS (PEASS-ng) — primary

# Canonical org is now peass-ng/PEASS-ng (carlospolop/PEASS-ng redirects)
curl -fL -o /tmp/linpeas.sh https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh
sha256sum /tmp/linpeas.sh                          # record hash in evidence
chmod +x /tmp/linpeas.sh
/tmp/linpeas.sh -a > /tmp/linpeas.out              # -a = "all checks"; redirect for evidence
 
# Useful flags: -s (superfast/stealth), -e (extra), -P <password> (sudo password for sudo -l checks),
# -o <list>  (only specific section codes), -n (skip network calls)

Linux Smart Enumeration (LSE) — secondary, color-graded

curl -fL -o /tmp/lse.sh https://github.com/diego-treitos/linux-smart-enumeration/releases/latest/download/lse.sh
chmod +x /tmp/lse.sh
/tmp/lse.sh -l 2 -i > /tmp/lse.out                 # -l 2 = full verbosity, -i = non-interactive

linux-exploit-suggester(-2) — kernel-CVE heuristics (read-only)

# v1 (The-Z-Labs / mzet)
curl -fL -o /tmp/les.sh https://raw.githubusercontent.com/The-Z-Labs/linux-exploit-suggester/master/linux-exploit-suggester.sh
chmod +x /tmp/les.sh && /tmp/les.sh
 
# v2 (jondonas) — Perl rewrite, smaller signature DB, useful as cross-check
curl -fL -o /tmp/les2.pl https://raw.githubusercontent.com/jondonas/linux-exploit-suggester-2/master/linux-exploit-suggester-2.pl
perl /tmp/les2.pl -k $(uname -r)

LinEnum (legacy)

# rebootuser/LinEnum — kept for parity with old playbooks but no releases published and
# essentially unmaintained for years; LinPEAS / LSE supersede it. Use only if both refuse to run.
curl -fL https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh -o /tmp/LinEnum.sh && bash /tmp/LinEnum.sh

pspy — process snooping without root

# Reveals cron/systemd-driven root processes and their argv (file watch via inotify)
curl -fL -o /tmp/pspy https://github.com/DominicBreuker/pspy/releases/latest/download/pspy64
chmod +x /tmp/pspy && /tmp/pspy -pf -i 1000

Note: Review tool output manually; automated scanners generate false positives, miss context, and (especially LinEnum / older LES rule packs) flag CVEs that the running kernel has back-ported patches for. Treat findings as leads, not verdicts.


8. Common Misconfigurations Checklist

Authentication & SSH

  • Root login via SSH enabled (PermitRootLogin yes)
  • Password authentication enabled when keys should be used
  • PermitEmptyPasswords yes or KbdInteractiveAuthentication yes left on
  • Weak SSH KEX/Cipher/MAC (e.g. diffie-hellman-group1, arcfour, MD5/SHA-1 MACs) — confirm with ssh-audit
  • Authorized keys present in unexpected accounts (root, service users, decommissioned employees)

Authorization

  • Users in sudoers with NOPASSWD, or (ALL) ALL for non-admins
  • Sudoers rule maps to a binary listed on GTFOBins (vi, find, awk, less, python, tar, nmap interactive mode, …)
  • sudo / sudoedit / polkit version still vulnerable to CVE-2021-3156, CVE-2023-22809, CVE-2021-4034

Filesystem permissions

  • World-writable files / directories in system paths (/etc, /usr, /opt, /srv)
  • SUID/SGID binaries outside the distro’s expected baseline (compare with a known-good install)
  • Files with dangerous capabilities (cap_setuid+ep, cap_dac_read_search+ep, cap_sys_admin+ep)
  • Weak permissions on /etc/shadow, /etc/sudoers, /etc/sudoers.d/*, ~/.ssh/authorized_keys

Scheduled execution

  • Writable cron jobs / /etc/cron.d/* / /etc/cron.{hourly,daily,weekly,monthly}/*
  • Writable systemd .service / .timer / .socket units (especially under /etc/systemd/system/)
  • PATH wildcards or relative paths in root-executed scripts

Network & services

  • Firewall disabled or overly permissive (ACCEPT … 0.0.0.0/0)
  • Unnecessary services running (FTP, Telnet, rsh, rlogin, tftp, NFSv2/3 without Kerberos)
  • Internal services (databases, Redis, Elasticsearch, Memcached) bound to 0.0.0.0 instead of loopback
  • Default credentials in config files / committed .env / ~/.aws/credentials readable by group

Containers & runtime

  • User in docker group (root-equivalent on host)
  • Mounted Docker / containerd / podman socket inside a container
  • Privileged container (--privileged) or container holding CAP_SYS_ADMIN/CAP_SYS_MODULE
  • runc < 1.1.12 / Docker < 25.0.2 / containerd < 1.7.13 (CVE-2024-21626 Leaky Vessels)
  • Kubernetes pod with cluster-admin SA token, or hostPath/hostNetwork/hostPID exposed

Storage

  • NFS exports with no_root_squash / insecure
  • World-readable backups (/var/backups, /root/*.bak, mysqldumps with passwords inline)

Logging & visibility

  • No central logging (rsyslog/journald → SIEM forwarder absent)
  • auditd not running or no rules covering /etc/passwd, /etc/shadow, /etc/sudoers
  • Log files world-readable (history of usernames, source IPs)

Patch posture

  • Kernel / glibc / sudo / polkit / OpenSSL / OpenSSH severely out of date
  • Unattended upgrades disabled on internet-facing hosts

9. Evidence Collection

For each finding, document:

  • Exact command used
  • Full output (sanitize sensitive data)
  • Timestamp (UTC)
  • Affected hosts/files
  • Screenshot if GUI-based

File structure:

/Evidence/{engagement_id}/Linux/
  ├── enumeration/
  │   ├── 20251005_uname_output.txt
  │   ├── 20251005_ps_aux.txt
  │   └── 20251005_netstat.txt
  ├── configs/
  │   ├── 20251005_sshd_config.txt
  │   ├── 20251005_sudoers.txt
  │   └── 20251005_iptables.txt
  ├── permissions/
  │   ├── 20251005_suid_binaries.txt
  │   └── 20251005_world_writable.txt
  └── screenshots/
      └── 20251005_linpeas_output.png

Hash all files:

sha256sum *.txt > evidence_hashes.txt

10. Reporting

Finding Format

Title: SSH Root Login Enabled
Severity: High
Affected Hosts: server01.example.com, server02.example.com
Description: SSH daemon permits direct root login (PermitRootLogin yes)
Impact: Attackers can brute-force or use leaked credentials to gain root access
Evidence: /etc/ssh/sshd_config line 32
Remediation:
  1. Edit /etc/ssh/sshd_config
  2. Set: PermitRootLogin no
  3. Restart SSH: systemctl restart sshd
  4. Test SSH access with non-root user + sudo
Verification: Re-check config and test login attempts as root (should fail)

Remediation Priorities

  1. Critical: Root SSH, SUID exploits, kernel vulnerabilities
  2. High: Sudo NOPASSWD, world-writable system files, exposed services
  3. Medium: Weak logging, outdated packages, firewall gaps
  4. Low: Informational findings, hardening recommendations

  • Read-only first: Prefer enumeration over exploitation
  • No destructive actions without explicit approval (e.g., kernel exploits, DoS, fork bombs, kernel module loads)
  • No public exploit binaries on production: stage in a sandbox built from the host’s distro / kernel / glibc / sudo / polkit / runc versions
  • Coordinate with sysadmins before running intensive scans
  • Stop immediately if you cause instability or user impact
  • Document everything for audit trail and legal defensibility (see Collection Log for chain-of-custody)
  • Respect scope: Do not pivot beyond authorized hosts; cloud workloads, managed-K8s control planes, and shared hypervisors are usually out-of-scope by default
  • Refer to Legal & Ethics (canonical) and OPSEC Plan for engagement-wide rules — this SOP does not re-derive them

12. Tools Reference

Enumeration & privilege-escalation discovery

ToolPurposeInstall / Link
linpeas.shPrimary automated LPE enumeration (PEASS-ng)github.com/peass-ng/PEASS-ng
lse.shColor-graded LPE enumeration (verbosity 0–2)github.com/diego-treitos/linux-smart-enumeration
linux-exploit-suggesterKernel-CVE heuristic auditor (v1)github.com/The-Z-Labs/linux-exploit-suggester
linux-exploit-suggester-2Kernel-CVE heuristic auditor (v2, Perl)github.com/jondonas/linux-exploit-suggester-2
LinEnum.shLegacy Linux enumeration script (largely unmaintained — fall back only)github.com/rebootuser/LinEnum
pspyMonitor processes / file events without rootgithub.com/DominicBreuker/pspy
GTFOBinsSUID / sudo / capabilities escalation databasegtfobins.github.io

Auditing & hardening baselines

ToolPurposeInstall / Link
lynisHost security auditapt install lynis ; dnf install lynis ; latest from github.com/CISOfy/lynis
chkrootkit / rkhunterRootkit signature scannersapt install chkrootkit rkhunter
debsecan / dnf updateinfoOutstanding security advisories per hostapt install debsecan ; dnf updateinfo list security
ssh-auditSSH server policy + algorithm auditgithub.com/jtesta/ssh-audit ; pip install ssh-audit
OpenSCAP / oscapCIS / STIG compliance scanapt install libopenscap8 ; dnf install openscap-scanner scap-security-guide
auditd + auditctl / aureportKernel audit-rule enforcement & queryBundled with most distros

Capability / process / kernel introspection

ToolPurposeInstall / Link
getcap / setcap / capsh / getpcapsFile + process capability inspectionlibcap2-bin (Debian) / libcap (RHEL)
bpftrace / bpftopLive tracing (read-only when run as root)apt install bpftrace
auditd ruleset templatesAnomaly-detection baselinesgithub.com/Neo23x0/auditd

Container & Kubernetes

ToolPurposeInstall / Link
deepceDocker container enumeration & escape primitives auditgithub.com/stealthcopter/deepce
kube-hunterKubernetes attack-surface discoverygithub.com/aquasecurity/kube-hunter
kubeauditK8s manifest / cluster security auditgithub.com/Shopify/kubeaudit
peiratesK8s post-exploitation toolkit (offensive)github.com/inguardians/peirates
amicontainedIdentify container runtime + capability setgithub.com/genuinetools/amicontained

13. Common Pitfalls

  • ❌ Running public exploit code on production (panic risk, backdoored PoCs)
  • ❌ Forgetting to sanitize sensitive data in reports (passwords, keys, tokens, JWTs from /var/run/secrets/...)
  • ❌ Not checking scope before scanning (out-of-scope hosts, shared K8s nodes, hypervisor)
  • ❌ Relying only on automated tools (miss context-specific issues; no scanner reads policy intent)
  • ❌ Not documenting commands/timestamps (breaks evidence chain — see Collection Log)
  • ❌ Ignoring false positives from tools (verify manually; LinEnum / older LES rules over-flag back-ported kernels)
  • ❌ Assuming all SUID binaries are exploitable (check GTFOBins first; Linux ignores the SUID bit on shell scripts)
  • ❌ Treating CAP_*-marked binaries as benign because they aren’t SUID (capabilities bypass the SUID check)
  • ❌ Inside a container, attacking the host without first verifying you actually escaped the namespace (cat /proc/1/cgroup, readlink /proc/1/root)
  • ❌ Piping curl … | sh from a target you do not control; always download, hash, and inspect first
  • ❌ Failing to check kernel back-ports — Ubuntu/RHEL frequently patch a CVE without changing the upstream uname -r minor version

14. Reference Resources

Comprehensive Knowledge Bases

Enumeration & Scanning Tools

Hardening & Security Benchmarks

Exploit Databases

Kernel Exploitation Resources

  • Kernel Exploit Development - 0x00sec.org
    • Forum with kernel exploitation tutorials
  • Linux Kernel Security - kernsec.org/wiki
    • Kernel security subsystem documentation
  • Dirty COW (CVE-2016-5195) - dirtycow.ninja
    • Famous kernel exploit example and documentation

Docker & Container Security

Vendor security trackers (kernel + userland CVE back-ports)

Notable LPE write-ups (illustrative, not exhaustive)

SSH & Authentication Resources

Post-Exploitation & Persistence

Cheat Sheets & Quick References

Logging & Monitoring

Practice Platforms

Books & Courses

  • Linux Basics for Hackers by OccupyTheWeb
  • SANS SEC504: Hacker Tools, Techniques, and Incident Handling
  • Offensive Security PWK (OSCP)
  • HackerSploit Linux Privilege Escalation - youtube.com/hackersploit

Community & Forums


Engagement governance:

  • Legal & Ethics - Authorization, scope, evidence handling, jurisdictional rules (canonical)
  • OPSEC Plan - Operator and infrastructure OPSEC during the engagement
  • Collection Log - Evidence chain-of-custody pattern referenced by §9 above

Analysis:

Pentesting & Security:


Version: 1.1 · Last Updated: 2026-04-25 · Review Frequency: Quarterly (medium-rot tooling SOP — kernel/userland CVE landscape and PEASS-ng release cadence drive churn)