Safe Penetration Testing Labs · advanced · ~25 min
Run a defensive checklist over any setuid binary.
setuid programs run with the file owner's privileges. Even a tiny bug can hand an attacker root. The audit is a checklist; everything not on the list is a finding.
When you find a setuid binary on a target system during an authorised assessment, you read its source (or disassemble it) and run the checklist. Every miss is a privilege-escalation candidate.
The 5-item checklist:
$PATH, $LD_PRELOAD, $LD_LIBRARY_PATH, $IFS, or $ENV is owned. Always clearenv then set known-safe values.open returns 0 or 1 or 2 — and the next printf writes into your data file.geteuid is the elevated id; getuid is the caller. Auth decisions on the wrong one are a CVE.openat + O_NOFOLLOW or realpath + prefix-check.system(3) and popen(3) inherit environment. If you must spawn, execve with a sanitised envp.Pentester mindset. Walk the list explicitly. Each "yes" is a finding worth a separate write-up.
uid_t getuid(void); /* real uid — caller */
uid_t geteuid(void); /* effective uid — privileges in force */
int setresuid(uid_t r, uid_t e, uid_t s); /* drop forever */
int clearenv(void);
A setuid binary runs with the file owner's privileges, not the caller's.
Setuid root binaries are tiny portals into root. Auditing them is a focused
checklist: PATH inheritance, env scrubbing, fd leaks, file-race patterns, and
the getuid()/geteuid() distinction.
/* Defensive setuid program start-up: */
if (clearenv() != 0) exit(1); /* strip ALL env first */
setenv("PATH", "/usr/bin:/bin", 1); /* known-safe PATH */
if (setresuid(geteuid(), geteuid(), geteuid()) < 0) exit(1);
/* Drop privs entirely the moment the elevated work is done */
uid_t real = getuid();
if (setresuid(real, real, real) < 0) {
perror("setresuid"); exit(1);
}
/* Now we run as the original caller — much less attack surface */
ls -l /usr/bin/sudo shows -rwsr-xr-x — the s is the setuid bit. find / -perm -4000 -type f 2>/dev/null lists them all on a system.
On top of the checklist, the same memory-safety rules apply: bounded copies, validated input, etc.
sudo, su, ping (historically), mount (historically), passwd. Each ships with the audit baked in; review them for the patterns.
5 items: env, fds, uids, races, child processes. Every miss is a privilege-escalation candidate.