📅 Day 16 — Linux Privilege Escalation: SUID, SGID, Sticky Bit (Foundations)

📸 Lab Session: SUID Binary Execution Verification
Terminal screenshot showing a Linux bash session on ubuntu-linux-2404 that demonstrates SUID behavior by creating and testing a compiled C program named whoami.sh. The terminal displays chmod, ls, and execution commands with output showing real UID equals 1000 (parallels user) and effective UID equals 0 (root), confirming that the SUID bit successfully changes execution context for compiled binaries. The session also shows password prompts and kernel warnings about SUID on scripts being ignored. Text visible includes file permissions (-rwxr-xr-x), user/group information (parallels), and explanatory echo statements about script execution and privilege handling.
🎯 Goal
Build a correct mental model of Linux privilege escalation foundations by understanding:
- What SUID, SGID, and Sticky Bit actually do
- How Linux really handles execution identity
- Why some configurations are dangerous — and others only look dangerous
- How attackers enumerate and reason about privilege boundaries
This day was about mechanics, not exploits.
🧠 Key Concepts (Before Touching Commands)
Linux privilege escalation is not magic.
It is about execution context.
Every process has:
- a real UID/GID (who launched it)
- an effective UID/GID (whose permissions it runs with)
Special permission bits exist to intentionally bend this rule — and that’s where things can go wrong.
🔧 Lab Work & Observations
1️⃣ SUID on Scripts (The Trap)
I created a simple shell script and set the SUID bit on it.
Even though:
- the filesystem showed the
sbit filereported it assetuid
Linux did not change the effective UID at runtime.
Why?
- Modern Linux kernels ignore SUID on scripts
- Interpreters + environment variables + race conditions are inherently unsafe
➡️ This is not a bug.
➡️ This is a security decision.
Key insight:
Filesystem permissions ≠ kernel execution behavior.
2️⃣ Real SUID: Compiled Binary
I then built a small C program printing:
- real UID
- effective UID
When the binary was:
- compiled (ELF)
- owned by
root - marked with SUID
Running it as a normal user clearly showed:
- real UID = my user
- effective UID =
root
🔥 This is real SUID behavior.
No guessing. No theory. Just mechanics.
3️⃣ Enumerating SUID Files (Attacker View)
I enumerated SUID binaries using:
find / -perm -4000 2>/dev/null
Important realization:
-
Most SUID binaries are expected and hardened
-
Attackers don’t panic — they filter
I analyzed examples like:
-
Xorg.wrap→ legacy, historically vulnerable, environment-dependent -
chfn→ boring but input-parsing (interesting in older systems) -
snap-confine→ security boundary creator (high-impact if broken)
Lesson:
The most interesting SUID binaries are often the ones enforcing security, not the obvious ones.
4️⃣ SGID: Quiet Privilege Changes
SGID doesn’t usually give root — but it can:
-
grant access to powerful groups
-
enable sideways privilege escalation
-
act as a stepping stone
Enumerated with:
find / -perm -2000 2>/dev/null
Key takeaway:
SGID is a horizontal privilege change — subtle, but real.
5️⃣ Sticky Bit: Damage Containment
Checked /tmp permissions:
ls -ld /tmp
Observed:
-
world-writable directory
-
sticky bit enabled (
t)
Sticky bit:
-
does not grant privileges
-
prevents users from deleting each other’s files
Attackers don’t exploit sticky bit —
they exploit its absence.
6️⃣ PATH, Cron, Services (Previewed, Not Mastered)
I also introduced:
-
writable directories in
$PATH -
cron jobs
-
root-owned services
Important realization:
These are not vulnerabilities on their own.
They become dangerous only when chained with:
-
SUID binaries
-
unsafe scripts
-
trusted execution contexts
This part needs deeper, slower treatment — scheduled for later.
🧩 Mental Model (The Real Outcome)
By the end of the day, the model became clear:
-
SUID → vertical privilege jump (dangerous)
-
SGID → horizontal privilege shift (subtle)
-
Sticky bit → containment, not escalation
-
PATH / cron / services → exploit enablers, not exploits
Privilege escalation is not about running commands.
It’s about breaking trust boundaries.
🧠 Lessons Learned
What worked
-
Building my own binaries instead of trusting examples
-
Verifying everything with
id,file, and real output -
Thinking like an attacker, not a tutorial follower
What broke
-
Initial assumptions about SUID on scripts
-
Treating enumeration commands as “find exploit buttons”
Why it broke
-
Confusing filesystem metadata with kernel execution rules
-
Not separating capability from exploitability
Fix / takeaway
-
Always verify who a program actually runs as
-
Treat enumeration as judgment training, not exploit hunting
-
Slow down when concepts start chaining — depth beats speed
